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>
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>
Jakub Jelinek <jakub@redhat.com>
......
......@@ -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,
......
......@@ -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. */
......
......@@ -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);
......
......@@ -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;
}
......
......@@ -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)
{
......
......@@ -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. */
......
......@@ -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);
......
......@@ -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
......
......@@ -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);
......
......@@ -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);
......
// 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" }
}
// 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