From 930e81755b53deb8ef27e5531d87d33be3c59d3b Mon Sep 17 00:00:00 2001 From: jason Date: Mon, 4 Feb 2008 03:28:53 +0000 Subject: [PATCH] PR c++/33916 * cp/init.c (build_value_init_1): New function. (build_value_init): New function. * cp/typeck2.c (build_functional_cast): Call it. * cp/cp-gimplify.c (cp_gimplify_init_expr): Handle its output. * cp/cp-tree.h (TYPE_HAS_USER_CONSTRUCTOR): Rename from TYPE_HAS_CONSTRUCTOR. * cp/class.c (finish_struct_bits, maybe_warn_about_overly_private_class, add_implicitly_declared_members): Adjust. (check_field_decls): Adjust. Remove warnings about reference/const in class without constructor. (check_bases_and_members): Adjust. Give those warnings here instead. * cp/decl.c (fixup_anonymous_aggr): Adjust. (check_initializer): Adjust, clarify logic slightly. (grok_special_member_properties): Adjust, only set if user-provided. * cp/rtti.c (create_tinfo_types): Don't set. * cp/cvt.c (ocp_convert): Remove exception for vtable_entry_type et al. Use same_type_ignoring_top_level_qualifiers_p. * cp/pt.c (check_explicit_specialization): Adjust. (instantiate_class_template): Adjust. * print-tree.c (print_node) [CONSTRUCTOR]: Print elements. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@132088 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/ChangeLog | 4 + gcc/cp/ChangeLog | 25 ++++++ gcc/cp/class.c | 84 ++++++++++++++----- gcc/cp/cp-gimplify.c | 55 +++++++++---- gcc/cp/cp-tree.h | 5 +- gcc/cp/cvt.c | 13 +-- gcc/cp/decl.c | 16 ++-- gcc/cp/init.c | 153 ++++++++++++++++++++++++++++++++++- gcc/cp/pt.c | 4 +- gcc/cp/rtti.c | 2 - gcc/cp/typeck2.c | 27 +++++-- gcc/print-tree.c | 15 ++++ gcc/testsuite/g++.dg/init/ctor8.C | 4 +- gcc/testsuite/g++.dg/init/value1.C | 22 +++++ gcc/testsuite/g++.dg/warn/Wextra-1.C | 12 +++ gcc/testsuite/g++.dg/warn/Wextra-2.C | 15 ++++ 16 files changed, 383 insertions(+), 73 deletions(-) create mode 100644 gcc/testsuite/g++.dg/init/value1.C create mode 100644 gcc/testsuite/g++.dg/warn/Wextra-1.C create mode 100644 gcc/testsuite/g++.dg/warn/Wextra-2.C diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 8426d4153bc..089f82f239d 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,7 @@ +2008-02-03 Jason Merrill + + * print-tree.c (print_node) [CONSTRUCTOR]: Print elements. + 2008-02-04 Ralf Wildenhues PR other/29972 diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 5b4cc3bb49b..3504769f1bb 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,28 @@ +2008-02-02 Jason Merrill + Mark Mitchell + + PR c++/33916 + * init.c (build_value_init_1): New function. + (build_value_init): New function. + * typeck2.c (build_functional_cast): Call it. + * cp-gimplify.c (cp_gimplify_init_expr): Handle its output. + + * cp-tree.h (TYPE_HAS_USER_CONSTRUCTOR): Rename from + TYPE_HAS_CONSTRUCTOR. + * class.c (finish_struct_bits, maybe_warn_about_overly_private_class, + add_implicitly_declared_members): Adjust. + (check_field_decls): Adjust. Remove warnings about reference/const + in class without constructor. + (check_bases_and_members): Adjust. Give those warnings here instead. + * decl.c (fixup_anonymous_aggr): Adjust. + (check_initializer): Adjust, clarify logic slightly. + (grok_special_member_properties): Adjust, only set if user-provided. + * rtti.c (create_tinfo_types): Don't set. + * cvt.c (ocp_convert): Remove exception for vtable_entry_type et al. + Use same_type_ignoring_top_level_qualifiers_p. + * pt.c (check_explicit_specialization): Adjust. + (instantiate_class_template): Adjust. + 2008-01-31 Douglas Gregor Jakub Jelinek diff --git a/gcc/cp/class.c b/gcc/cp/class.c index 7560dbe3da7..a5456c23324 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -955,7 +955,7 @@ add_method (tree type, tree method, tree using_decl) CLASSTYPE_METHOD_VEC (type) = method_vec; } - /* Maintain TYPE_HAS_CONSTRUCTOR, etc. */ + /* Maintain TYPE_HAS_USER_CONSTRUCTOR, etc. */ grok_special_member_properties (method); /* Constructors and destructors go in special slots. */ @@ -1451,7 +1451,7 @@ finish_struct_bits (tree t) { /* These fields are in the _TYPE part of the node, not in the TYPE_LANG_SPECIFIC component, so they are not shared. */ - TYPE_HAS_CONSTRUCTOR (variants) = TYPE_HAS_CONSTRUCTOR (t); + TYPE_HAS_USER_CONSTRUCTOR (variants) = TYPE_HAS_USER_CONSTRUCTOR (t); TYPE_NEEDS_CONSTRUCTING (variants) = TYPE_NEEDS_CONSTRUCTING (t); TYPE_HAS_NONTRIVIAL_DESTRUCTOR (variants) = TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t); @@ -1596,7 +1596,8 @@ maybe_warn_about_overly_private_class (tree t) return; } - if (TYPE_HAS_CONSTRUCTOR (t) + /* Warn about classes that have private constructors and no friends. */ + if (TYPE_HAS_USER_CONSTRUCTOR (t) /* Implicitly generated constructors are always public. */ && (!CLASSTYPE_LAZY_DEFAULT_CTOR (t) || !CLASSTYPE_LAZY_COPY_CTOR (t))) @@ -2602,20 +2603,25 @@ add_implicitly_declared_members (tree t, } } - /* Default constructor. */ - if (! TYPE_HAS_CONSTRUCTOR (t)) + /* [class.ctor] + + If there is no user-declared constructor for a class, a default + constructor is implicitly declared. */ + if (! TYPE_HAS_USER_CONSTRUCTOR (t)) { TYPE_HAS_DEFAULT_CONSTRUCTOR (t) = 1; CLASSTYPE_LAZY_DEFAULT_CTOR (t) = 1; } - /* Copy constructor. */ + /* [class.ctor] + + If a class definition does not explicitly declare a copy + constructor, one is declared implicitly. */ if (! TYPE_HAS_INIT_REF (t) && ! TYPE_FOR_JAVA (t)) { TYPE_HAS_INIT_REF (t) = 1; TYPE_HAS_CONST_INIT_REF (t) = !cant_have_const_cctor; CLASSTYPE_LAZY_COPY_CTOR (t) = 1; - TYPE_HAS_CONSTRUCTOR (t) = 1; } /* If there is no assignment operator, one will be created if and @@ -2937,8 +2943,7 @@ check_field_decls (tree t, tree *access_decls, if (TREE_PRIVATE (x) || TREE_PROTECTED (x)) CLASSTYPE_NON_AGGREGATE (t) = 1; - /* If this is of reference type, check if it needs an init. - Also do a little ANSI jig if necessary. */ + /* If this is of reference type, check if it needs an init. */ if (TREE_CODE (type) == REFERENCE_TYPE) { CLASSTYPE_NON_POD_P (t) = 1; @@ -2950,10 +2955,6 @@ check_field_decls (tree t, tree *access_decls, only way to initialize nonstatic const and reference members. */ TYPE_HAS_COMPLEX_ASSIGN_REF (t) = 1; - - if (! TYPE_HAS_CONSTRUCTOR (t) && CLASSTYPE_NON_AGGREGATE (t) - && extra_warnings) - warning (OPT_Wextra, "non-static reference %q+#D in class without a constructor", x); } type = strip_array_types (type); @@ -3028,10 +3029,6 @@ check_field_decls (tree t, tree *access_decls, only way to initialize nonstatic const and reference members. */ TYPE_HAS_COMPLEX_ASSIGN_REF (t) = 1; - - if (! TYPE_HAS_CONSTRUCTOR (t) && CLASSTYPE_NON_AGGREGATE (t) - && extra_warnings) - warning (OPT_Wextra, "non-static const member %q+#D in class without a constructor", x); } /* A field that is pseudo-const makes the structure likewise. */ else if (CLASS_TYPE_P (type)) @@ -3045,7 +3042,8 @@ check_field_decls (tree t, tree *access_decls, /* Core issue 80: A nonstatic data member is required to have a different name from the class iff the class has a user-defined constructor. */ - if (constructor_name_p (DECL_NAME (x), t) && TYPE_HAS_CONSTRUCTOR (t)) + if (constructor_name_p (DECL_NAME (x), t) + && TYPE_HAS_USER_CONSTRUCTOR (t)) pedwarn ("field %q+#D with same name as class", x); /* We set DECL_C_BIT_FIELD in grokbitfield. @@ -3073,7 +3071,7 @@ check_field_decls (tree t, tree *access_decls, This seems enough for practical purposes. */ if (warn_ecpp && has_pointers - && TYPE_HAS_CONSTRUCTOR (t) + && TYPE_HAS_USER_CONSTRUCTOR (t) && TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t) && !(TYPE_HAS_INIT_REF (t) && TYPE_HAS_ASSIGN_REF (t))) { @@ -4158,10 +4156,22 @@ check_bases_and_members (tree t) declared member functions. */ TYPE_HAS_COMPLEX_INIT_REF (t) |= (TYPE_HAS_INIT_REF (t) || TYPE_CONTAINS_VPTR_P (t)); + /* We need to call a constructor for this class if it has a + user-declared constructor, or if the default constructor is going + to initialize the vptr. (This is not an if-and-only-if; + TYPE_NEEDS_CONSTRUCTING is set elsewhere if bases or members + themselves need constructing.) */ TYPE_NEEDS_CONSTRUCTING (t) - |= (TYPE_HAS_CONSTRUCTOR (t) || TYPE_CONTAINS_VPTR_P (t)); + |= (TYPE_HAS_USER_CONSTRUCTOR (t) || TYPE_CONTAINS_VPTR_P (t)); + /* [dcl.init.aggr] + + An aggregate is an arry or a class with no user-declared + constructors ... and no virtual functions. + + Again, other conditions for being an aggregate are checked + elsewhere. */ CLASSTYPE_NON_AGGREGATE (t) - |= (TYPE_HAS_CONSTRUCTOR (t) || TYPE_POLYMORPHIC_P (t)); + |= (TYPE_HAS_USER_CONSTRUCTOR (t) || TYPE_POLYMORPHIC_P (t)); CLASSTYPE_NON_POD_P (t) |= (CLASSTYPE_NON_AGGREGATE (t) || TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t) @@ -4171,6 +4181,38 @@ check_bases_and_members (tree t) TYPE_HAS_COMPLEX_DFLT (t) |= (TYPE_HAS_DEFAULT_CONSTRUCTOR (t) || TYPE_CONTAINS_VPTR_P (t)); + /* If the class has no user-declared constructor, but does have + non-static const or reference data members that can never be + initialized, issue a warning. */ + if (extra_warnings + /* Classes with user-declared constructors are presumed to + initialize these members. */ + && !TYPE_HAS_USER_CONSTRUCTOR (t) + /* Aggregates can be initialized with brace-enclosed + initializers. */ + && CLASSTYPE_NON_AGGREGATE (t)) + { + tree field; + + for (field = TYPE_FIELDS (t); field; field = TREE_CHAIN (field)) + { + tree type; + + if (TREE_CODE (field) != FIELD_DECL) + continue; + + type = TREE_TYPE (field); + if (TREE_CODE (type) == REFERENCE_TYPE) + warning (OPT_Wextra, "non-static reference %q+#D in class " + "without a constructor", field); + else if (CP_TYPE_CONST_P (type) + && (!CLASS_TYPE_P (type) + || !TYPE_HAS_DEFAULT_CONSTRUCTOR (type))) + warning (OPT_Wextra, "non-static const member %q+#D in class " + "without a constructor", field); + } + } + /* Synthesize any needed methods. */ add_implicitly_declared_members (t, cant_have_const_ctor, diff --git a/gcc/cp/cp-gimplify.c b/gcc/cp/cp-gimplify.c index f9d800ea388..50b40484413 100644 --- a/gcc/cp/cp-gimplify.c +++ b/gcc/cp/cp-gimplify.c @@ -387,35 +387,56 @@ cp_gimplify_init_expr (tree *expr_p, tree *pre_p, tree *post_p) { tree from = TREE_OPERAND (*expr_p, 1); tree to = TREE_OPERAND (*expr_p, 0); - tree sub; + tree t; + tree slot = NULL_TREE; /* What about code that pulls out the temp and uses it elsewhere? I think that such code never uses the TARGET_EXPR as an initializer. If I'm wrong, we'll abort because the temp won't have any RTL. In that case, I guess we'll need to replace references somehow. */ if (TREE_CODE (from) == TARGET_EXPR) - from = TARGET_EXPR_INITIAL (from); + { + slot = TARGET_EXPR_SLOT (from); + from = TARGET_EXPR_INITIAL (from); + } /* Look through any COMPOUND_EXPRs, since build_compound_expr pushes them inside the TARGET_EXPR. */ - sub = expr_last (from); + for (t = from; t; ) + { + tree sub = TREE_CODE (t) == COMPOUND_EXPR ? TREE_OPERAND (t, 0) : t; - /* If we are initializing from an AGGR_INIT_EXPR, drop the INIT_EXPR and - replace the slot operand with our target. + /* If we are initializing from an AGGR_INIT_EXPR, drop the INIT_EXPR and + replace the slot operand with our target. - Should we add a target parm to gimplify_expr instead? No, as in this - case we want to replace the INIT_EXPR. */ - if (TREE_CODE (sub) == AGGR_INIT_EXPR) - { - gimplify_expr (&to, pre_p, post_p, is_gimple_lvalue, fb_lvalue); - AGGR_INIT_EXPR_SLOT (sub) = to; - *expr_p = from; - - /* The initialization is now a side-effect, so the container can - become void. */ - if (from != sub) - TREE_TYPE (from) = void_type_node; + Should we add a target parm to gimplify_expr instead? No, as in this + case we want to replace the INIT_EXPR. */ + if (TREE_CODE (sub) == AGGR_INIT_EXPR) + { + gimplify_expr (&to, pre_p, post_p, is_gimple_lvalue, fb_lvalue); + AGGR_INIT_EXPR_SLOT (sub) = to; + *expr_p = from; + + /* The initialization is now a side-effect, so the container can + become void. */ + if (from != sub) + TREE_TYPE (from) = void_type_node; + } + else if (TREE_CODE (sub) == INIT_EXPR + && TREE_OPERAND (sub, 0) == slot) + { + /* An INIT_EXPR under TARGET_EXPR created by build_value_init, + will be followed by an AGGR_INIT_EXPR. */ + gimplify_expr (&to, pre_p, post_p, is_gimple_lvalue, fb_lvalue); + TREE_OPERAND (sub, 0) = to; + } + + if (t == sub) + break; + else + t = TREE_OPERAND (t, 1); } + } /* Gimplify a MUST_NOT_THROW_EXPR. */ diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index e6aba2fe2c4..549625c5138 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -91,7 +91,7 @@ struct diagnostic_info; Usage of TYPE_LANG_FLAG_?: 0: TYPE_DEPENDENT_P - 1: TYPE_HAS_CONSTRUCTOR. + 1: TYPE_HAS_USER_CONSTRUCTOR. 2: Unused 3: TYPE_FOR_JAVA. 4: TYPE_HAS_NONTRIVIAL_DESTRUCTOR @@ -2709,7 +2709,7 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter) /* Nonzero for a class type means that the class type has a user-declared constructor. */ -#define TYPE_HAS_CONSTRUCTOR(NODE) (TYPE_LANG_FLAG_1 (NODE)) +#define TYPE_HAS_USER_CONSTRUCTOR(NODE) (TYPE_LANG_FLAG_1 (NODE)) /* When appearing in an INDIRECT_REF, it means that the tree structure underneath is actually a call to a constructor. This is needed @@ -4346,6 +4346,7 @@ extern tree build_aggr_init (tree, tree, int); extern int is_aggr_type (tree, int); extern tree get_type_value (tree); extern tree build_zero_init (tree, tree, bool); +extern tree build_value_init (tree); extern tree build_offset_ref (tree, tree, bool); extern tree build_new (tree, tree, tree, tree, int); extern tree build_vec_init (tree, tree, tree, bool, int); diff --git a/gcc/cp/cvt.c b/gcc/cp/cvt.c index ebfc7d05d98..5f48cc525e8 100644 --- a/gcc/cp/cvt.c +++ b/gcc/cp/cvt.c @@ -596,13 +596,9 @@ ocp_convert (tree type, tree expr, int convtype, int flags) e = integral_constant_value (e); - if (IS_AGGR_TYPE (type) && (convtype & CONV_FORCE_TEMP) - /* Some internal structures (vtable_entry_type, sigtbl_ptr_type) - don't go through finish_struct, so they don't have the synthesized - constructors. So don't force a temporary. */ - && TYPE_HAS_CONSTRUCTOR (type)) + if (IS_AGGR_TYPE (type) && (convtype & CONV_FORCE_TEMP)) /* We need a new temporary; don't take this shortcut. */; - else if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (TREE_TYPE (e))) + else if (same_type_ignoring_top_level_qualifiers_p (type, TREE_TYPE (e))) { if (same_type_p (type, TREE_TYPE (e))) /* The call to fold will not always remove the NOP_EXPR as @@ -619,10 +615,7 @@ ocp_convert (tree type, tree expr, int convtype, int flags) else if (TREE_CODE (e) == TARGET_EXPR) { /* Don't build a NOP_EXPR of class type. Instead, change the - type of the temporary. Only allow this for cv-qual changes, - though. */ - gcc_assert (same_type_p (TYPE_MAIN_VARIANT (TREE_TYPE (e)), - TYPE_MAIN_VARIANT (type))); + type of the temporary. */ TREE_TYPE (e) = TREE_TYPE (TARGET_EXPR_SLOT (e)) = type; return e; } diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 21db36e2095..93baa7db83a 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -3689,7 +3689,7 @@ fixup_anonymous_aggr (tree t) tree *q; /* Wipe out memory of synthesized methods. */ - TYPE_HAS_CONSTRUCTOR (t) = 0; + TYPE_HAS_USER_CONSTRUCTOR (t) = 0; TYPE_HAS_DEFAULT_CONSTRUCTOR (t) = 0; TYPE_HAS_INIT_REF (t) = 0; TYPE_HAS_CONST_INIT_REF (t) = 0; @@ -4993,11 +4993,11 @@ check_initializer (tree decl, tree init, int flags, tree *cleanup) if (type == error_mark_node) return NULL_TREE; - if (TYPE_HAS_CONSTRUCTOR (type) || TYPE_NEEDS_CONSTRUCTING (type)) + if (TREE_CODE (type) == ARRAY_TYPE && TYPE_NEEDS_CONSTRUCTING (type)) + goto initialize_aggr; + else if (CLASS_TYPE_P (type)) { - if (TREE_CODE (type) == ARRAY_TYPE) - goto initialize_aggr; - else if (TREE_CODE (init) == CONSTRUCTOR) + if (TREE_CODE (init) == CONSTRUCTOR) { if (TYPE_NON_AGGREGATE_CLASS (type)) { @@ -9582,7 +9582,8 @@ move_fn_p (const_tree d) /* Remember any special properties of member function DECL. */ -void grok_special_member_properties (tree decl) +void +grok_special_member_properties (tree decl) { tree class_type; @@ -9594,7 +9595,8 @@ void grok_special_member_properties (tree decl) { int ctor = copy_fn_p (decl); - TYPE_HAS_CONSTRUCTOR (class_type) = 1; + if (!DECL_ARTIFICIAL (decl)) + TYPE_HAS_USER_CONSTRUCTOR (class_type) = 1; if (ctor > 0) { diff --git a/gcc/cp/init.c b/gcc/cp/init.c index a6da19f1933..ec59207716d 100644 --- a/gcc/cp/init.c +++ b/gcc/cp/init.c @@ -152,7 +152,7 @@ build_zero_init (tree type, tree nelts, bool static_storage_p) /* [dcl.init] - To zero-initialization storage for an object of type T means: + To zero-initialize an object of type T means: -- if T is a scalar type, the storage is set to the value of zero converted to T. @@ -209,8 +209,8 @@ build_zero_init (tree type, tree nelts, bool static_storage_p) break; } - /* Build a constructor to contain the initializations. */ - init = build_constructor (type, v); + /* Build a constructor to contain the initializations. */ + init = build_constructor (type, v); } else if (TREE_CODE (type) == ARRAY_TYPE) { @@ -315,6 +315,153 @@ build_default_init (tree type, tree nelts) return build_zero_init (type, nelts, /*static_storage_p=*/false); } +/* Return a suitable initializer for value-initializing an object of type + TYPE, as described in [dcl.init]. If HAVE_CTOR is true, the initializer + for an enclosing object is already calling the constructor for this + object. */ + +static tree +build_value_init_1 (tree type, bool have_ctor) +{ + /* [dcl.init] + + To value-initialize an object of type T means: + + - if T is a class type (clause 9) with a user-provided constructor + (12.1), then the default constructor for T is called (and the + initialization is ill-formed if T has no accessible default + constructor); + + - if T is a non-union class type without a user-provided constructor, + then every non-static data member and base-class component of T is + value-initialized;92) + + - if T is an array type, then each element is value-initialized; + + - otherwise, the object is zero-initialized. + + A program that calls for default-initialization or + value-initialization of an entity of reference type is ill-formed. + + 92) Value-initialization for such a class object may be implemented by + zero-initializing the object and then calling the default + constructor. */ + + if (CLASS_TYPE_P (type)) + { + if (TYPE_HAS_USER_CONSTRUCTOR (type) && !have_ctor) + return build_cplus_new + (type, + build_special_member_call (NULL_TREE, complete_ctor_identifier, + NULL_TREE, type, LOOKUP_NORMAL)); + else if (TREE_CODE (type) != UNION_TYPE) + { + tree field, init; + VEC(constructor_elt,gc) *v = NULL; + bool call_ctor = !have_ctor && TYPE_NEEDS_CONSTRUCTING (type); + + /* Iterate over the fields, building initializations. */ + for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field)) + { + tree ftype, value; + + if (TREE_CODE (field) != FIELD_DECL) + continue; + + ftype = TREE_TYPE (field); + + if (TREE_CODE (ftype) == REFERENCE_TYPE) + error ("value-initialization of reference"); + + /* We could skip vfields and fields of types with + user-defined constructors, but I think that won't improve + performance at all; it should be simpler in general just + to zero out the entire object than try to only zero the + bits that actually need it. */ + + /* Note that for class types there will be FIELD_DECLs + corresponding to base classes as well. Thus, iterating + over TYPE_FIELDs will result in correct initialization of + all of the subobjects. */ + value = build_value_init_1 (ftype, have_ctor || call_ctor); + + if (value) + CONSTRUCTOR_APPEND_ELT(v, field, value); + } + + /* Build a constructor to contain the zero- initializations. */ + init = build_constructor (type, v); + if (call_ctor) + { + /* This is a class that needs constructing, but doesn't have + a user-defined constructor. So we need to zero-initialize + the object and then call the implicitly defined ctor. + Implement this by sticking the zero-initialization inside + the TARGET_EXPR for the constructor call; + cp_gimplify_init_expr will know how to handle it. */ + tree ctor = build_special_member_call + (NULL_TREE, complete_ctor_identifier, + NULL_TREE, type, LOOKUP_NORMAL); + + ctor = build_cplus_new (type, ctor); + init = build2 (INIT_EXPR, void_type_node, + TARGET_EXPR_SLOT (ctor), init); + init = build2 (COMPOUND_EXPR, void_type_node, init, + TARGET_EXPR_INITIAL (ctor)); + TARGET_EXPR_INITIAL (ctor) = init; + return ctor; + } + return init; + } + } + else if (TREE_CODE (type) == ARRAY_TYPE) + { + VEC(constructor_elt,gc) *v = NULL; + + /* Iterate over the array elements, building initializations. */ + tree max_index = array_type_nelts (type); + + /* If we have an error_mark here, we should just return error mark + as we don't know the size of the array yet. */ + if (max_index == error_mark_node) + return error_mark_node; + gcc_assert (TREE_CODE (max_index) == INTEGER_CST); + + /* A zero-sized array, which is accepted as an extension, will + have an upper bound of -1. */ + if (!tree_int_cst_equal (max_index, integer_minus_one_node)) + { + constructor_elt *ce; + + v = VEC_alloc (constructor_elt, gc, 1); + ce = VEC_quick_push (constructor_elt, v, NULL); + + /* If this is a one element array, we just use a regular init. */ + if (tree_int_cst_equal (size_zero_node, max_index)) + ce->index = size_zero_node; + else + ce->index = build2 (RANGE_EXPR, sizetype, size_zero_node, + max_index); + + ce->value = build_value_init_1 (TREE_TYPE (type), have_ctor); + } + + /* Build a constructor to contain the initializations. */ + return build_constructor (type, v); + } + + return build_zero_init (type, NULL_TREE, /*static_storage_p=*/false); +} + +/* Return a suitable initializer for value-initializing an object of type + TYPE, as described in [dcl.init]. */ + +tree +build_value_init (tree type) +{ + return build_value_init_1 (type, false); +} + /* Initialize MEMBER, a FIELD_DECL, with INIT, a TREE_LIST of arguments. If TREE_LIST is void_type_node, an empty initializer list was given; if NULL_TREE no initializer was given. */ diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index b5caf5c7cb2..2b996d41ae1 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -2091,7 +2091,7 @@ check_explicit_specialization (tree declarator, { int is_constructor = DECL_CONSTRUCTOR_P (decl); - if (is_constructor ? !TYPE_HAS_CONSTRUCTOR (ctype) + if (is_constructor ? !TYPE_HAS_USER_CONSTRUCTOR (ctype) : !CLASSTYPE_DESTRUCTORS (ctype)) { /* From [temp.expl.spec]: @@ -6818,7 +6818,7 @@ instantiate_class_template (tree type) input_location = DECL_SOURCE_LOCATION (typedecl); in_system_header = DECL_IN_SYSTEM_HEADER (typedecl); - TYPE_HAS_CONSTRUCTOR (type) = TYPE_HAS_CONSTRUCTOR (pattern); + TYPE_HAS_USER_CONSTRUCTOR (type) = TYPE_HAS_USER_CONSTRUCTOR (pattern); TYPE_HAS_NEW_OPERATOR (type) = TYPE_HAS_NEW_OPERATOR (pattern); TYPE_HAS_ARRAY_NEW_OPERATOR (type) = TYPE_HAS_ARRAY_NEW_OPERATOR (pattern); TYPE_GETS_DELETE (type) = TYPE_GETS_DELETE (pattern); diff --git a/gcc/cp/rtti.c b/gcc/cp/rtti.c index 6cac0efc1f8..1925d04fbc5 100644 --- a/gcc/cp/rtti.c +++ b/gcc/cp/rtti.c @@ -1318,7 +1318,6 @@ create_tinfo_types (void) ti->name = NULL_TREE; finish_builtin_struct (ti->type, "__type_info_pseudo", fields, NULL_TREE); - TYPE_HAS_CONSTRUCTOR (ti->type) = 1; } /* Fundamental type_info */ @@ -1357,7 +1356,6 @@ create_tinfo_types (void) ti->name = NULL_TREE; finish_builtin_struct (ti->type, "__base_class_type_info_pseudo", fields, NULL_TREE); - TYPE_HAS_CONSTRUCTOR (ti->type) = 1; } /* Pointer type_info. Adds two fields, qualification mask diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c index adbe9de7541..66c35d44e43 100644 --- a/gcc/cp/typeck2.c +++ b/gcc/cp/typeck2.c @@ -1310,6 +1310,8 @@ build_functional_cast (tree exp, tree parms) { /* This is either a call to a constructor, or a C cast in C++'s `functional' notation. */ + + /* The type to which we are casting. */ tree type; if (exp == error_mark_node || parms == error_mark_node) @@ -1350,20 +1352,31 @@ build_functional_cast (tree exp, tree parms) if (abstract_virtuals_error (NULL_TREE, type)) return error_mark_node; + /* [expr.type.conv] + + If the expression list is a single-expression, the type + conversion is equivalent (in definedness, and if defined in + meaning) to the corresponding cast expression. */ if (parms && TREE_CHAIN (parms) == NULL_TREE) return build_c_cast (type, TREE_VALUE (parms)); - /* We need to zero-initialize POD types. */ - if (parms == NULL_TREE - && !CLASSTYPE_NON_POD_P (type) - && TYPE_HAS_DEFAULT_CONSTRUCTOR (type)) + /* [expr.type.conv] + + The expression T(), where T is a simple-type-specifier for a + non-array complete object type or the (possibly cv-qualified) + void type, creates an rvalue of the specified type, which is + value-initialized. */ + + if (parms == NULL_TREE + /* If there's a user-defined constructor, value-initialization is + just calling the constructor, so fall through. */ + && !TYPE_HAS_USER_CONSTRUCTOR (type)) { - exp = build_zero_init (type, - /*nelts=*/NULL_TREE, - /*static_storage_p=*/false); + exp = build_value_init (type); return get_target_expr (exp); } + /* Call the constructor. */ exp = build_special_member_call (NULL_TREE, complete_ctor_identifier, parms, type, LOOKUP_NORMAL); diff --git a/gcc/print-tree.c b/gcc/print-tree.c index 37c10078602..8f2ca7555c8 100644 --- a/gcc/print-tree.c +++ b/gcc/print-tree.c @@ -851,6 +851,21 @@ print_node (FILE *file, const char *prefix, tree node, int indent) } break; + case CONSTRUCTOR: + { + unsigned HOST_WIDE_INT cnt; + tree index, value; + len = VEC_length (constructor_elt, CONSTRUCTOR_ELTS (node)); + fprintf (file, " lngt %d", len); + FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (node), + cnt, index, value) + { + print_node (file, "idx", index, indent + 4); + print_node (file, "val", value, indent + 4); + } + } + break; + case STATEMENT_LIST: dump_addr (file, " head ", node->stmt_list.head); dump_addr (file, " tail ", node->stmt_list.tail); diff --git a/gcc/testsuite/g++.dg/init/ctor8.C b/gcc/testsuite/g++.dg/init/ctor8.C index beb92ef8519..3491f6a1d2c 100644 --- a/gcc/testsuite/g++.dg/init/ctor8.C +++ b/gcc/testsuite/g++.dg/init/ctor8.C @@ -1,9 +1,9 @@ // PR c++/29039 -typedef struct S { // { dg-error "reference" } +typedef struct S { int &r; }; // { dg-warning "'typedef' was ignored" } S f () { - return S (); // { dg-error "synthesized" } + return S (); // { dg-error "reference" } } diff --git a/gcc/testsuite/g++.dg/init/value1.C b/gcc/testsuite/g++.dg/init/value1.C new file mode 100644 index 00000000000..9dbc2e06775 --- /dev/null +++ b/gcc/testsuite/g++.dg/init/value1.C @@ -0,0 +1,22 @@ +// Test that with value-initialization, i is initialized to 0 +// and the vtable pointer is properly initialized. + +// { dg-do run } + +struct A +{ + int i; + virtual void f() {} +}; + +void f (A& a) +{ + a.f(); +} + +int main() +{ + A a = A(); + f (a); + return a.i; +} diff --git a/gcc/testsuite/g++.dg/warn/Wextra-1.C b/gcc/testsuite/g++.dg/warn/Wextra-1.C new file mode 100644 index 00000000000..c75a6b08767 --- /dev/null +++ b/gcc/testsuite/g++.dg/warn/Wextra-1.C @@ -0,0 +1,12 @@ +// { dg-options "-Wextra" } + +struct T { + // If the implicitly-declared default constructor for "T" is + // required, an error will be issued because "i" cannot be + // initialized. And, this class is not an aggregate, so it cannot + // be brace-initialized. Thus, there is no way to create an object + // of this class. We issue a warning with -Wextra. + const int i; // { dg-warning "const" } +private: + int j; +}; diff --git a/gcc/testsuite/g++.dg/warn/Wextra-2.C b/gcc/testsuite/g++.dg/warn/Wextra-2.C new file mode 100644 index 00000000000..5ca41c39d93 --- /dev/null +++ b/gcc/testsuite/g++.dg/warn/Wextra-2.C @@ -0,0 +1,15 @@ +// { dg-options "-Wextra" } + +struct S { + S(); +}; + +struct T { +private: + int i; +public: + // There should be no warning about this data member because the + // default constructor for "T" will invoke the default constructor + // for "S", even though "S" is "const". + const S s; // { dg-bogus "const" } +}; -- 2.11.4.GIT