aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJason Merrill <jason@redhat.com>2008-02-03 22:28:53 -0500
committerJason Merrill <jason@gcc.gnu.org>2008-02-03 22:28:53 -0500
commit0fcedd9c98d1f9f880b59b979b77f4db4d9eb391 (patch)
tree985387257ec096f981de1673a4abb0deacefe8d7
parenta31cfd58cff0429868f5c11a761a0d013652ad94 (diff)
downloadgcc-0fcedd9c98d1f9f880b59b979b77f4db4d9eb391.zip
gcc-0fcedd9c98d1f9f880b59b979b77f4db4d9eb391.tar.gz
gcc-0fcedd9c98d1f9f880b59b979b77f4db4d9eb391.tar.bz2
re PR c++/33916 (Default constructor fails to initialize array members)
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. Co-Authored-By: Mark Mitchell <mark@codesourcery.com> From-SVN: r132088
-rw-r--r--gcc/ChangeLog4
-rw-r--r--gcc/cp/ChangeLog25
-rw-r--r--gcc/cp/class.c84
-rw-r--r--gcc/cp/cp-gimplify.c55
-rw-r--r--gcc/cp/cp-tree.h5
-rw-r--r--gcc/cp/cvt.c13
-rw-r--r--gcc/cp/decl.c16
-rw-r--r--gcc/cp/init.c153
-rw-r--r--gcc/cp/pt.c4
-rw-r--r--gcc/cp/rtti.c2
-rw-r--r--gcc/cp/typeck2.c27
-rw-r--r--gcc/print-tree.c15
-rw-r--r--gcc/testsuite/g++.dg/init/ctor8.C4
-rw-r--r--gcc/testsuite/g++.dg/init/value1.C22
-rw-r--r--gcc/testsuite/g++.dg/warn/Wextra-1.C12
-rw-r--r--gcc/testsuite/g++.dg/warn/Wextra-2.C15
16 files changed, 383 insertions, 73 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 8426d41..089f82f 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,7 @@
+2008-02-03 Jason Merrill <jason@redhat.com>
+
+ * print-tree.c (print_node) [CONSTRUCTOR]: Print elements.
+
2008-02-04 Ralf Wildenhues <Ralf.Wildenhues@gmx.de>
PR other/29972
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 5b4cc3bb..3504769 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,28 @@
+2008-02-02 Jason Merrill <jason@redhat.com>
+ Mark Mitchell <mark@codesourcery.com>
+
+ 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 <doug.gregor@gmail.com>
Jakub Jelinek <jakub@redhat.com>
diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index 7560dbe..a5456c2 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 f9d800e..50b4048 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 e6aba2f..549625c 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 ebfc7d0..5f48cc5 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 21db36e..93baa7d 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 a6da19f..ec59207 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 b5caf5c..2b996d4 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 6cac0ef..1925d04f 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 adbe9de..66c35d4 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 37c1007..8f2ca75 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 beb92ef..3491f6a 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 0000000..9dbc2e0
--- /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 0000000..c75a6b0
--- /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 0000000..5ca41c39d
--- /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" }
+};