Commit 0fcedd9c by Jason Merrill Committed by Jason Merrill

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
parent a31cfd58
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> 2008-02-04 Ralf Wildenhues <Ralf.Wildenhues@gmx.de>
PR other/29972 PR other/29972
......
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> 2008-01-31 Douglas Gregor <doug.gregor@gmail.com>
Jakub Jelinek <jakub@redhat.com> Jakub Jelinek <jakub@redhat.com>
......
...@@ -955,7 +955,7 @@ add_method (tree type, tree method, tree using_decl) ...@@ -955,7 +955,7 @@ add_method (tree type, tree method, tree using_decl)
CLASSTYPE_METHOD_VEC (type) = method_vec; CLASSTYPE_METHOD_VEC (type) = method_vec;
} }
/* Maintain TYPE_HAS_CONSTRUCTOR, etc. */ /* Maintain TYPE_HAS_USER_CONSTRUCTOR, etc. */
grok_special_member_properties (method); grok_special_member_properties (method);
/* Constructors and destructors go in special slots. */ /* Constructors and destructors go in special slots. */
...@@ -1451,7 +1451,7 @@ finish_struct_bits (tree t) ...@@ -1451,7 +1451,7 @@ finish_struct_bits (tree t)
{ {
/* These fields are in the _TYPE part of the node, not in /* These fields are in the _TYPE part of the node, not in
the TYPE_LANG_SPECIFIC component, so they are not shared. */ 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_NEEDS_CONSTRUCTING (variants) = TYPE_NEEDS_CONSTRUCTING (t);
TYPE_HAS_NONTRIVIAL_DESTRUCTOR (variants) TYPE_HAS_NONTRIVIAL_DESTRUCTOR (variants)
= TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t); = TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t);
...@@ -1596,7 +1596,8 @@ maybe_warn_about_overly_private_class (tree t) ...@@ -1596,7 +1596,8 @@ maybe_warn_about_overly_private_class (tree t)
return; 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. */ /* Implicitly generated constructors are always public. */
&& (!CLASSTYPE_LAZY_DEFAULT_CTOR (t) && (!CLASSTYPE_LAZY_DEFAULT_CTOR (t)
|| !CLASSTYPE_LAZY_COPY_CTOR (t))) || !CLASSTYPE_LAZY_COPY_CTOR (t)))
...@@ -2602,20 +2603,25 @@ add_implicitly_declared_members (tree t, ...@@ -2602,20 +2603,25 @@ add_implicitly_declared_members (tree t,
} }
} }
/* Default constructor. */ /* [class.ctor]
if (! TYPE_HAS_CONSTRUCTOR (t))
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; TYPE_HAS_DEFAULT_CONSTRUCTOR (t) = 1;
CLASSTYPE_LAZY_DEFAULT_CTOR (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)) if (! TYPE_HAS_INIT_REF (t) && ! TYPE_FOR_JAVA (t))
{ {
TYPE_HAS_INIT_REF (t) = 1; TYPE_HAS_INIT_REF (t) = 1;
TYPE_HAS_CONST_INIT_REF (t) = !cant_have_const_cctor; TYPE_HAS_CONST_INIT_REF (t) = !cant_have_const_cctor;
CLASSTYPE_LAZY_COPY_CTOR (t) = 1; CLASSTYPE_LAZY_COPY_CTOR (t) = 1;
TYPE_HAS_CONSTRUCTOR (t) = 1;
} }
/* If there is no assignment operator, one will be created if and /* If there is no assignment operator, one will be created if and
...@@ -2937,8 +2943,7 @@ check_field_decls (tree t, tree *access_decls, ...@@ -2937,8 +2943,7 @@ check_field_decls (tree t, tree *access_decls,
if (TREE_PRIVATE (x) || TREE_PROTECTED (x)) if (TREE_PRIVATE (x) || TREE_PROTECTED (x))
CLASSTYPE_NON_AGGREGATE (t) = 1; CLASSTYPE_NON_AGGREGATE (t) = 1;
/* If this is of reference type, check if it needs an init. /* If this is of reference type, check if it needs an init. */
Also do a little ANSI jig if necessary. */
if (TREE_CODE (type) == REFERENCE_TYPE) if (TREE_CODE (type) == REFERENCE_TYPE)
{ {
CLASSTYPE_NON_POD_P (t) = 1; CLASSTYPE_NON_POD_P (t) = 1;
...@@ -2950,10 +2955,6 @@ check_field_decls (tree t, tree *access_decls, ...@@ -2950,10 +2955,6 @@ check_field_decls (tree t, tree *access_decls,
only way to initialize nonstatic const and reference only way to initialize nonstatic const and reference
members. */ members. */
TYPE_HAS_COMPLEX_ASSIGN_REF (t) = 1; 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); type = strip_array_types (type);
...@@ -3028,10 +3029,6 @@ check_field_decls (tree t, tree *access_decls, ...@@ -3028,10 +3029,6 @@ check_field_decls (tree t, tree *access_decls,
only way to initialize nonstatic const and reference only way to initialize nonstatic const and reference
members. */ members. */
TYPE_HAS_COMPLEX_ASSIGN_REF (t) = 1; 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. */ /* A field that is pseudo-const makes the structure likewise. */
else if (CLASS_TYPE_P (type)) else if (CLASS_TYPE_P (type))
...@@ -3045,7 +3042,8 @@ check_field_decls (tree t, tree *access_decls, ...@@ -3045,7 +3042,8 @@ check_field_decls (tree t, tree *access_decls,
/* Core issue 80: A nonstatic data member is required to have a /* Core issue 80: A nonstatic data member is required to have a
different name from the class iff the class has a different name from the class iff the class has a
user-defined constructor. */ 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); pedwarn ("field %q+#D with same name as class", x);
/* We set DECL_C_BIT_FIELD in grokbitfield. /* We set DECL_C_BIT_FIELD in grokbitfield.
...@@ -3073,7 +3071,7 @@ check_field_decls (tree t, tree *access_decls, ...@@ -3073,7 +3071,7 @@ check_field_decls (tree t, tree *access_decls,
This seems enough for practical purposes. */ This seems enough for practical purposes. */
if (warn_ecpp if (warn_ecpp
&& has_pointers && has_pointers
&& TYPE_HAS_CONSTRUCTOR (t) && TYPE_HAS_USER_CONSTRUCTOR (t)
&& TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t) && TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t)
&& !(TYPE_HAS_INIT_REF (t) && TYPE_HAS_ASSIGN_REF (t))) && !(TYPE_HAS_INIT_REF (t) && TYPE_HAS_ASSIGN_REF (t)))
{ {
...@@ -4158,10 +4156,22 @@ check_bases_and_members (tree t) ...@@ -4158,10 +4156,22 @@ check_bases_and_members (tree t)
declared member functions. */ declared member functions. */
TYPE_HAS_COMPLEX_INIT_REF (t) TYPE_HAS_COMPLEX_INIT_REF (t)
|= (TYPE_HAS_INIT_REF (t) || TYPE_CONTAINS_VPTR_P (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_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) 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_POD_P (t)
|= (CLASSTYPE_NON_AGGREGATE (t) |= (CLASSTYPE_NON_AGGREGATE (t)
|| TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t) || TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t)
...@@ -4171,6 +4181,38 @@ check_bases_and_members (tree t) ...@@ -4171,6 +4181,38 @@ check_bases_and_members (tree t)
TYPE_HAS_COMPLEX_DFLT (t) TYPE_HAS_COMPLEX_DFLT (t)
|= (TYPE_HAS_DEFAULT_CONSTRUCTOR (t) || TYPE_CONTAINS_VPTR_P (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. */ /* Synthesize any needed methods. */
add_implicitly_declared_members (t, add_implicitly_declared_members (t,
cant_have_const_ctor, cant_have_const_ctor,
......
...@@ -387,18 +387,24 @@ cp_gimplify_init_expr (tree *expr_p, tree *pre_p, tree *post_p) ...@@ -387,18 +387,24 @@ cp_gimplify_init_expr (tree *expr_p, tree *pre_p, tree *post_p)
{ {
tree from = TREE_OPERAND (*expr_p, 1); tree from = TREE_OPERAND (*expr_p, 1);
tree to = TREE_OPERAND (*expr_p, 0); 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 /* 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 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 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. */ case, I guess we'll need to replace references somehow. */
if (TREE_CODE (from) == TARGET_EXPR) if (TREE_CODE (from) == TARGET_EXPR)
{
slot = TARGET_EXPR_SLOT (from);
from = TARGET_EXPR_INITIAL (from); from = TARGET_EXPR_INITIAL (from);
}
/* Look through any COMPOUND_EXPRs, since build_compound_expr pushes them /* Look through any COMPOUND_EXPRs, since build_compound_expr pushes them
inside the TARGET_EXPR. */ 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 /* If we are initializing from an AGGR_INIT_EXPR, drop the INIT_EXPR and
replace the slot operand with our target. replace the slot operand with our target.
...@@ -416,6 +422,21 @@ cp_gimplify_init_expr (tree *expr_p, tree *pre_p, tree *post_p) ...@@ -416,6 +422,21 @@ cp_gimplify_init_expr (tree *expr_p, tree *pre_p, tree *post_p)
if (from != sub) if (from != sub)
TREE_TYPE (from) = void_type_node; 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. */ /* Gimplify a MUST_NOT_THROW_EXPR. */
......
...@@ -91,7 +91,7 @@ struct diagnostic_info; ...@@ -91,7 +91,7 @@ struct diagnostic_info;
Usage of TYPE_LANG_FLAG_?: Usage of TYPE_LANG_FLAG_?:
0: TYPE_DEPENDENT_P 0: TYPE_DEPENDENT_P
1: TYPE_HAS_CONSTRUCTOR. 1: TYPE_HAS_USER_CONSTRUCTOR.
2: Unused 2: Unused
3: TYPE_FOR_JAVA. 3: TYPE_FOR_JAVA.
4: TYPE_HAS_NONTRIVIAL_DESTRUCTOR 4: TYPE_HAS_NONTRIVIAL_DESTRUCTOR
...@@ -2709,7 +2709,7 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter) ...@@ -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 /* Nonzero for a class type means that the class type has a
user-declared constructor. */ 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 /* When appearing in an INDIRECT_REF, it means that the tree structure
underneath is actually a call to a constructor. This is needed underneath is actually a call to a constructor. This is needed
...@@ -4346,6 +4346,7 @@ extern tree build_aggr_init (tree, tree, int); ...@@ -4346,6 +4346,7 @@ extern tree build_aggr_init (tree, tree, int);
extern int is_aggr_type (tree, int); extern int is_aggr_type (tree, int);
extern tree get_type_value (tree); extern tree get_type_value (tree);
extern tree build_zero_init (tree, tree, bool); 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_offset_ref (tree, tree, bool);
extern tree build_new (tree, tree, tree, tree, int); extern tree build_new (tree, tree, tree, tree, int);
extern tree build_vec_init (tree, tree, tree, bool, int); extern tree build_vec_init (tree, tree, tree, bool, int);
......
...@@ -596,13 +596,9 @@ ocp_convert (tree type, tree expr, int convtype, int flags) ...@@ -596,13 +596,9 @@ ocp_convert (tree type, tree expr, int convtype, int flags)
e = integral_constant_value (e); e = integral_constant_value (e);
if (IS_AGGR_TYPE (type) && (convtype & CONV_FORCE_TEMP) 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))
/* We need a new temporary; don't take this shortcut. */; /* 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))) if (same_type_p (type, TREE_TYPE (e)))
/* The call to fold will not always remove the NOP_EXPR as /* 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) ...@@ -619,10 +615,7 @@ ocp_convert (tree type, tree expr, int convtype, int flags)
else if (TREE_CODE (e) == TARGET_EXPR) else if (TREE_CODE (e) == TARGET_EXPR)
{ {
/* Don't build a NOP_EXPR of class type. Instead, change the /* Don't build a NOP_EXPR of class type. Instead, change the
type of the temporary. Only allow this for cv-qual changes, type of the temporary. */
though. */
gcc_assert (same_type_p (TYPE_MAIN_VARIANT (TREE_TYPE (e)),
TYPE_MAIN_VARIANT (type)));
TREE_TYPE (e) = TREE_TYPE (TARGET_EXPR_SLOT (e)) = type; TREE_TYPE (e) = TREE_TYPE (TARGET_EXPR_SLOT (e)) = type;
return e; return e;
} }
......
...@@ -3689,7 +3689,7 @@ fixup_anonymous_aggr (tree t) ...@@ -3689,7 +3689,7 @@ fixup_anonymous_aggr (tree t)
tree *q; tree *q;
/* Wipe out memory of synthesized methods. */ /* 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_DEFAULT_CONSTRUCTOR (t) = 0;
TYPE_HAS_INIT_REF (t) = 0; TYPE_HAS_INIT_REF (t) = 0;
TYPE_HAS_CONST_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) ...@@ -4993,11 +4993,11 @@ check_initializer (tree decl, tree init, int flags, tree *cleanup)
if (type == error_mark_node) if (type == error_mark_node)
return NULL_TREE; return NULL_TREE;
if (TYPE_HAS_CONSTRUCTOR (type) || TYPE_NEEDS_CONSTRUCTING (type)) if (TREE_CODE (type) == ARRAY_TYPE && TYPE_NEEDS_CONSTRUCTING (type))
{
if (TREE_CODE (type) == ARRAY_TYPE)
goto initialize_aggr; goto initialize_aggr;
else if (TREE_CODE (init) == CONSTRUCTOR) else if (CLASS_TYPE_P (type))
{
if (TREE_CODE (init) == CONSTRUCTOR)
{ {
if (TYPE_NON_AGGREGATE_CLASS (type)) if (TYPE_NON_AGGREGATE_CLASS (type))
{ {
...@@ -9582,7 +9582,8 @@ move_fn_p (const_tree d) ...@@ -9582,7 +9582,8 @@ move_fn_p (const_tree d)
/* Remember any special properties of member function DECL. */ /* 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; tree class_type;
...@@ -9594,7 +9595,8 @@ void grok_special_member_properties (tree decl) ...@@ -9594,7 +9595,8 @@ void grok_special_member_properties (tree decl)
{ {
int ctor = copy_fn_p (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) if (ctor > 0)
{ {
......
...@@ -152,7 +152,7 @@ build_zero_init (tree type, tree nelts, bool static_storage_p) ...@@ -152,7 +152,7 @@ build_zero_init (tree type, tree nelts, bool static_storage_p)
/* [dcl.init] /* [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 -- if T is a scalar type, the storage is set to the value of zero
converted to T. converted to T.
...@@ -315,6 +315,153 @@ build_default_init (tree type, tree nelts) ...@@ -315,6 +315,153 @@ build_default_init (tree type, tree nelts)
return build_zero_init (type, nelts, /*static_storage_p=*/false); 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 /* Initialize MEMBER, a FIELD_DECL, with INIT, a TREE_LIST of
arguments. If TREE_LIST is void_type_node, an empty initializer arguments. If TREE_LIST is void_type_node, an empty initializer
list was given; if NULL_TREE no initializer was given. */ list was given; if NULL_TREE no initializer was given. */
......
...@@ -2091,7 +2091,7 @@ check_explicit_specialization (tree declarator, ...@@ -2091,7 +2091,7 @@ check_explicit_specialization (tree declarator,
{ {
int is_constructor = DECL_CONSTRUCTOR_P (decl); 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)) : !CLASSTYPE_DESTRUCTORS (ctype))
{ {
/* From [temp.expl.spec]: /* From [temp.expl.spec]:
...@@ -6818,7 +6818,7 @@ instantiate_class_template (tree type) ...@@ -6818,7 +6818,7 @@ instantiate_class_template (tree type)
input_location = DECL_SOURCE_LOCATION (typedecl); input_location = DECL_SOURCE_LOCATION (typedecl);
in_system_header = DECL_IN_SYSTEM_HEADER (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_NEW_OPERATOR (type) = TYPE_HAS_NEW_OPERATOR (pattern);
TYPE_HAS_ARRAY_NEW_OPERATOR (type) = TYPE_HAS_ARRAY_NEW_OPERATOR (pattern); TYPE_HAS_ARRAY_NEW_OPERATOR (type) = TYPE_HAS_ARRAY_NEW_OPERATOR (pattern);
TYPE_GETS_DELETE (type) = TYPE_GETS_DELETE (pattern); TYPE_GETS_DELETE (type) = TYPE_GETS_DELETE (pattern);
......
...@@ -1318,7 +1318,6 @@ create_tinfo_types (void) ...@@ -1318,7 +1318,6 @@ create_tinfo_types (void)
ti->name = NULL_TREE; ti->name = NULL_TREE;
finish_builtin_struct (ti->type, "__type_info_pseudo", finish_builtin_struct (ti->type, "__type_info_pseudo",
fields, NULL_TREE); fields, NULL_TREE);
TYPE_HAS_CONSTRUCTOR (ti->type) = 1;
} }
/* Fundamental type_info */ /* Fundamental type_info */
...@@ -1357,7 +1356,6 @@ create_tinfo_types (void) ...@@ -1357,7 +1356,6 @@ create_tinfo_types (void)
ti->name = NULL_TREE; ti->name = NULL_TREE;
finish_builtin_struct (ti->type, "__base_class_type_info_pseudo", finish_builtin_struct (ti->type, "__base_class_type_info_pseudo",
fields, NULL_TREE); fields, NULL_TREE);
TYPE_HAS_CONSTRUCTOR (ti->type) = 1;
} }
/* Pointer type_info. Adds two fields, qualification mask /* Pointer type_info. Adds two fields, qualification mask
......
...@@ -1310,6 +1310,8 @@ build_functional_cast (tree exp, tree parms) ...@@ -1310,6 +1310,8 @@ build_functional_cast (tree exp, tree parms)
{ {
/* This is either a call to a constructor, /* This is either a call to a constructor,
or a C cast in C++'s `functional' notation. */ or a C cast in C++'s `functional' notation. */
/* The type to which we are casting. */
tree type; tree type;
if (exp == error_mark_node || parms == error_mark_node) if (exp == error_mark_node || parms == error_mark_node)
...@@ -1350,20 +1352,31 @@ build_functional_cast (tree exp, tree parms) ...@@ -1350,20 +1352,31 @@ build_functional_cast (tree exp, tree parms)
if (abstract_virtuals_error (NULL_TREE, type)) if (abstract_virtuals_error (NULL_TREE, type))
return error_mark_node; 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) if (parms && TREE_CHAIN (parms) == NULL_TREE)
return build_c_cast (type, TREE_VALUE (parms)); return build_c_cast (type, TREE_VALUE (parms));
/* We need to zero-initialize POD types. */ /* [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 (parms == NULL_TREE
&& !CLASSTYPE_NON_POD_P (type) /* If there's a user-defined constructor, value-initialization is
&& TYPE_HAS_DEFAULT_CONSTRUCTOR (type)) just calling the constructor, so fall through. */
&& !TYPE_HAS_USER_CONSTRUCTOR (type))
{ {
exp = build_zero_init (type, exp = build_value_init (type);
/*nelts=*/NULL_TREE,
/*static_storage_p=*/false);
return get_target_expr (exp); return get_target_expr (exp);
} }
/* Call the constructor. */
exp = build_special_member_call (NULL_TREE, complete_ctor_identifier, parms, exp = build_special_member_call (NULL_TREE, complete_ctor_identifier, parms,
type, LOOKUP_NORMAL); type, LOOKUP_NORMAL);
......
...@@ -851,6 +851,21 @@ print_node (FILE *file, const char *prefix, tree node, int indent) ...@@ -851,6 +851,21 @@ print_node (FILE *file, const char *prefix, tree node, int indent)
} }
break; 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: case STATEMENT_LIST:
dump_addr (file, " head ", node->stmt_list.head); dump_addr (file, " head ", node->stmt_list.head);
dump_addr (file, " tail ", node->stmt_list.tail); dump_addr (file, " tail ", node->stmt_list.tail);
......
// PR c++/29039 // PR c++/29039
typedef struct S { // { dg-error "reference" } typedef struct S {
int &r; int &r;
}; // { dg-warning "'typedef' was ignored" } }; // { dg-warning "'typedef' was ignored" }
S f () { S f () {
return S (); // { dg-error "synthesized" } return S (); // { dg-error "reference" }
} }
// 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;
}
// { 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;
};
// { 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" }
};
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment