Commit 2282d28d by Mark Mitchell Committed by Mark Mitchell

re PR c++/7188 (Segfault with template class and recursive (incorrect) initalizer list.)

	PR c++/7188.
	* cp-tree.def (CTOR_INITIALIZER): Use one slot, not two.
	* cp-tree.h (emit_base_init): Rename to ....
	(emit_mem_initializers): ... this.
	(expand_member_init): Change prototype.
	* init.c (perform_member_init): Compute explicit, rather than
	requiring it as a parameter.
	(sort_member_init): Rename to ...
	(sort_mem_initializers): ... this.  Process bases and data members
	together.
	(sort_base_init): Remove.
	(emit_base_init): Rename to ...
	(emit_mem_initializers): ... this.
	(expand_aggr_vbase_init_1): Remove.
	(construct_virtual_bases): Rename to ...
	(construct_virtual_base): ... this.
	(expand_member_init): Rework handling of base initializers.
	* method.c (do_build_copy_constructor): Use
	finish_mem_initializers.
	* parse.y (member_init): Adjust calls to expand_member_init.
	* pt.c (tsubst_expr): Simplify CTOR_INITIALIZER case.
	(tsubst_initializer_list): Use expand_member_init.
	* semantics.c (finish_mem_intiailizers): Simplify.

	PR c++/7188.
	* g++.dg/template/meminit1.C: New test.
	* g++.dg/warn/Wreorder-1.C: Likewise.
	* g++.old-deja/g++.mike/warn3.C: Tweak.
	* lib/prune.exp: Ingore "in copy constructor".

From-SVN: r57748
parent 854ef390
2002-10-02 Mark Mitchell <mark@codesourcery.com>
PR c++/7188.
* cp-tree.def (CTOR_INITIALIZER): Use one slot, not two.
* cp-tree.h (emit_base_init): Rename to ....
(emit_mem_initializers): ... this.
(expand_member_init): Change prototype.
* init.c (perform_member_init): Compute explicit, rather than
requiring it as a parameter.
(sort_member_init): Rename to ...
(sort_mem_initializers): ... this. Process bases and data members
together.
(sort_base_init): Remove.
(emit_base_init): Rename to ...
(emit_mem_initializers): ... this.
(expand_aggr_vbase_init_1): Remove.
(construct_virtual_bases): Rename to ...
(construct_virtual_base): ... this.
(expand_member_init): Rework handling of base initializers.
* method.c (do_build_copy_constructor): Use
finish_mem_initializers.
* parse.y (member_init): Adjust calls to expand_member_init.
* pt.c (tsubst_expr): Simplify CTOR_INITIALIZER case.
(tsubst_initializer_list): Use expand_member_init.
* semantics.c (finish_mem_intiailizers): Simplify.
2002-10-02 Roger Sayle <roger@eyesopen.com> 2002-10-02 Roger Sayle <roger@eyesopen.com>
PR optimization/6627 PR optimization/6627
......
...@@ -251,7 +251,7 @@ DEFTREECODE (PSEUDO_DTOR_EXPR, "pseudo_dtor_expr", 'e', 3) ...@@ -251,7 +251,7 @@ DEFTREECODE (PSEUDO_DTOR_EXPR, "pseudo_dtor_expr", 'e', 3)
/* CTOR_INITIALIZER is a placeholder in template code for a call to /* CTOR_INITIALIZER is a placeholder in template code for a call to
setup_vtbl_pointer (and appears in all functions, not just ctors). */ setup_vtbl_pointer (and appears in all functions, not just ctors). */
DEFTREECODE (CTOR_INITIALIZER, "ctor_initializer", 'e', 2) DEFTREECODE (CTOR_INITIALIZER, "ctor_initializer", 'e', 1)
DEFTREECODE (RETURN_INIT, "return_init", 'e', 2) DEFTREECODE (RETURN_INIT, "return_init", 'e', 2)
DEFTREECODE (TRY_BLOCK, "try_block", 'e', 2) DEFTREECODE (TRY_BLOCK, "try_block", 'e', 2)
DEFTREECODE (EH_SPEC_BLOCK, "eh_spec_block", 'e', 2) DEFTREECODE (EH_SPEC_BLOCK, "eh_spec_block", 'e', 2)
......
...@@ -3845,8 +3845,8 @@ extern void add_friend PARAMS ((tree, tree)); ...@@ -3845,8 +3845,8 @@ extern void add_friend PARAMS ((tree, tree));
extern tree do_friend PARAMS ((tree, tree, tree, tree, tree, enum overload_flags, tree, int)); extern tree do_friend PARAMS ((tree, tree, tree, tree, tree, enum overload_flags, tree, int));
/* in init.c */ /* in init.c */
extern void emit_base_init PARAMS ((tree, tree)); extern tree expand_member_init (tree, tree);
extern tree expand_member_init PARAMS ((tree, tree, tree)); extern void emit_mem_initializers (tree);
extern tree build_aggr_init PARAMS ((tree, tree, int)); extern tree build_aggr_init PARAMS ((tree, tree, int));
extern tree build_init PARAMS ((tree, tree, int)); extern tree build_init PARAMS ((tree, tree, int));
extern int is_aggr_type PARAMS ((tree, int)); extern int is_aggr_type PARAMS ((tree, int));
......
...@@ -34,17 +34,15 @@ Boston, MA 02111-1307, USA. */ ...@@ -34,17 +34,15 @@ Boston, MA 02111-1307, USA. */
#include "toplev.h" #include "toplev.h"
#include "ggc.h" #include "ggc.h"
static void expand_aggr_vbase_init_1 PARAMS ((tree, tree, tree, tree)); static void construct_virtual_base (tree, tree);
static void construct_virtual_bases PARAMS ((tree, tree, tree, tree, tree));
static void expand_aggr_init_1 PARAMS ((tree, tree, tree, tree, int)); static void expand_aggr_init_1 PARAMS ((tree, tree, tree, tree, int));
static void expand_default_init PARAMS ((tree, tree, tree, tree, int)); static void expand_default_init PARAMS ((tree, tree, tree, tree, int));
static tree build_vec_delete_1 PARAMS ((tree, tree, tree, special_function_kind, int)); static tree build_vec_delete_1 PARAMS ((tree, tree, tree, special_function_kind, int));
static void perform_member_init PARAMS ((tree, tree, int)); static void perform_member_init (tree, tree);
static void sort_base_init PARAMS ((tree, tree, tree *, tree *));
static tree build_builtin_delete_call PARAMS ((tree)); static tree build_builtin_delete_call PARAMS ((tree));
static int member_init_ok_or_else PARAMS ((tree, tree, tree)); static int member_init_ok_or_else PARAMS ((tree, tree, tree));
static void expand_virtual_init PARAMS ((tree, tree)); static void expand_virtual_init PARAMS ((tree, tree));
static tree sort_member_init PARAMS ((tree, tree)); static tree sort_mem_initializers (tree, tree);
static tree initializing_context PARAMS ((tree)); static tree initializing_context PARAMS ((tree));
static void expand_cleanup_for_base PARAMS ((tree, tree)); static void expand_cleanup_for_base PARAMS ((tree, tree));
static tree get_temp_regvar PARAMS ((tree, tree)); static tree get_temp_regvar PARAMS ((tree, tree));
...@@ -303,16 +301,30 @@ build_default_init (type) ...@@ -303,16 +301,30 @@ build_default_init (type)
return build_zero_init (type, /*static_storage_p=*/false); return build_zero_init (type, /*static_storage_p=*/false);
} }
/* Subroutine of emit_base_init. */ /* 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. */
static void static void
perform_member_init (member, init, explicit) perform_member_init (tree member, tree init)
tree member, init;
int explicit;
{ {
tree decl; tree decl;
tree type = TREE_TYPE (member); tree type = TREE_TYPE (member);
bool explicit;
explicit = (init != NULL_TREE);
/* Effective C++ rule 12 requires that all data members be
initialized. */
if (warn_ecpp && !explicit && TREE_CODE (type) != ARRAY_TYPE)
warning ("`%D' should be initialized in the member initialization "
"list",
member);
if (init == void_type_node)
init = NULL_TREE;
/* Get an lvalue for the data member. */
decl = build_class_member_access_expr (current_class_ref, member, decl = build_class_member_access_expr (current_class_ref, member,
/*access_path=*/NULL_TREE, /*access_path=*/NULL_TREE,
/*preserve_reference=*/true); /*preserve_reference=*/true);
...@@ -333,11 +345,6 @@ perform_member_init (member, init, explicit) ...@@ -333,11 +345,6 @@ perform_member_init (member, init, explicit)
else if (TYPE_NEEDS_CONSTRUCTING (type) else if (TYPE_NEEDS_CONSTRUCTING (type)
|| (init && TYPE_HAS_CONSTRUCTOR (type))) || (init && TYPE_HAS_CONSTRUCTOR (type)))
{ {
/* Since `init' is already a TREE_LIST on the member_init_list,
only build it into one if we aren't already a list. */
if (init != NULL_TREE && TREE_CODE (init) != TREE_LIST)
init = build_tree_list (NULL_TREE, init);
if (explicit if (explicit
&& TREE_CODE (type) == ARRAY_TYPE && TREE_CODE (type) == ARRAY_TYPE
&& init != NULL_TREE && init != NULL_TREE
...@@ -443,79 +450,107 @@ build_field_list (t, list, uses_unions_p) ...@@ -443,79 +450,107 @@ build_field_list (t, list, uses_unions_p)
return list; return list;
} }
/* The MEMBER_INIT_LIST is a TREE_LIST. The TREE_PURPOSE of each list /* The MEM_INITS are a TREE_LIST. The TREE_PURPOSE of each list gives
gives a FIELD_DECL in T that needs initialization. The TREE_VALUE a FIELD_DECL or BINFO in T that needs initialization. The
gives the initializer, or list of initializer arguments. Sort the TREE_VALUE gives the initializer, or list of initializer arguments.
MEMBER_INIT_LIST, returning a version that contains the same
information but in the order that the fields should actually be Return a TREE_LIST containing all of the initializations required
initialized. Perform error-checking in the process. */ for T, in the order in which they should be performed. The output
list has the same format as the input. */
static tree static tree
sort_member_init (t, member_init_list) sort_mem_initializers (tree t, tree mem_inits)
tree t;
tree member_init_list;
{ {
tree init_list;
tree last_field;
tree init; tree init;
tree base;
tree sorted_inits;
tree next_subobject;
int i;
int uses_unions_p; int uses_unions_p;
/* Build up a list of the various fields, in sorted order. */ /* Build up a list of initializations. The TREE_PURPOSE of entry
init_list = nreverse (build_field_list (t, NULL_TREE, &uses_unions_p)); will be the subobject (a FIELD_DECL or BINFO) to initialize. The
TREE_VALUE will be the constructor arguments, or NULL if no
/* Go through the explicit initializers, adding them to the explicit initialization was provided. */
INIT_LIST. */ sorted_inits = NULL_TREE;
last_field = init_list; /* Process the virtual bases. */
for (init = member_init_list; init; init = TREE_CHAIN (init)) for (base = CLASSTYPE_VBASECLASSES (t); base; base = TREE_CHAIN (base))
{ sorted_inits = tree_cons (TREE_VALUE (base), NULL_TREE, sorted_inits);
tree f; /* Process the direct bases. */
tree initialized_field; for (i = 0; i < CLASSTYPE_N_BASECLASSES (t); ++i)
{
initialized_field = TREE_PURPOSE (init); base = BINFO_BASETYPE (TYPE_BINFO (t), i);
my_friendly_assert (TREE_CODE (initialized_field) == FIELD_DECL, if (!TREE_VIA_VIRTUAL (base))
20000516); sorted_inits = tree_cons (base, NULL_TREE, sorted_inits);
}
/* If the explicit initializers are in sorted order, then the /* Process the non-static data members. */
INITIALIZED_FIELD will be for a field following the sorted_inits = build_field_list (t, sorted_inits, &uses_unions_p);
LAST_FIELD. */ /* Reverse the entire list of initializations, so that they are in
for (f = last_field; f; f = TREE_CHAIN (f)) the order that they will actually be performed. */
if (TREE_PURPOSE (f) == initialized_field) sorted_inits = nreverse (sorted_inits);
/* If the user presented the initializers in an order different from
that in which they will actually occur, we issue a warning. Keep
track of the next subobject which can be explicitly initialized
without issuing a warning. */
next_subobject = sorted_inits;
/* Go through the explicit initializers, filling in TREE_PURPOSE in
the SORTED_INITS. */
for (init = mem_inits; init; init = TREE_CHAIN (init))
{
tree subobject;
tree subobject_init;
subobject = TREE_PURPOSE (init);
/* If the explicit initializers are in sorted order, then
SUBOBJECT will be NEXT_SUBOBJECT, or something following
it. */
for (subobject_init = next_subobject;
subobject_init;
subobject_init = TREE_CHAIN (subobject_init))
if (TREE_PURPOSE (subobject_init) == subobject)
break; break;
/* Give a warning, if appropriate. */ /* Issue a warning if the explicit initializer order does not
if (warn_reorder && !f) match that which will actually occur. */
if (warn_reorder && !subobject_init)
{ {
cp_warning_at ("member initializers for `%#D'", if (TREE_CODE (TREE_PURPOSE (next_subobject)) == FIELD_DECL)
TREE_PURPOSE (last_field)); cp_warning_at ("`%D' will be initialized after",
cp_warning_at (" and `%#D'", initialized_field); TREE_PURPOSE (next_subobject));
warning (" will be re-ordered to match declaration order"); else
warning ("base `%T' will be initialized after",
TREE_PURPOSE (next_subobject));
if (TREE_CODE (subobject) == FIELD_DECL)
cp_warning_at (" `%#D'", subobject);
else
warning (" base `%T'", subobject);
} }
/* Look again, from the beginning of the list. We must find the /* Look again, from the beginning of the list. */
field on this loop. */ if (!subobject_init)
if (!f)
{ {
f = init_list; subobject_init = sorted_inits;
while (TREE_PURPOSE (f) != initialized_field) while (TREE_PURPOSE (subobject_init) != subobject)
f = TREE_CHAIN (f); subobject_init = TREE_CHAIN (subobject_init);
} }
/* If there was already an explicit initializer for this field, /* It is invalid to initialize the same subobject more than
issue an error. */ once. */
if (TREE_TYPE (f)) if (TREE_VALUE (subobject_init))
error ("multiple initializations given for member `%D'",
initialized_field);
else
{ {
/* Mark the field as explicitly initialized. */ if (TREE_CODE (subobject) == FIELD_DECL)
TREE_TYPE (f) = error_mark_node; error ("multiple initializations given for `%D'", subobject);
/* And insert the initializer. */ else
TREE_VALUE (f) = TREE_VALUE (init); error ("multiple initializations given for base `%T'",
subobject);
} }
/* Remember the location of the last explicitly initialized /* Record the initialization. */
field. */ TREE_VALUE (subobject_init) = TREE_VALUE (init);
last_field = f; next_subobject = subobject_init;
} }
/* [class.base.init] /* [class.base.init]
...@@ -525,15 +560,16 @@ sort_member_init (t, member_init_list) ...@@ -525,15 +560,16 @@ sort_member_init (t, member_init_list)
anonymous unions), the ctor-initializer is ill-formed. */ anonymous unions), the ctor-initializer is ill-formed. */
if (uses_unions_p) if (uses_unions_p)
{ {
last_field = NULL_TREE; tree last_field = NULL_TREE;
for (init = init_list; init; init = TREE_CHAIN (init)) for (init = sorted_inits; init; init = TREE_CHAIN (init))
{ {
tree field; tree field;
tree field_type; tree field_type;
int done; int done;
/* Skip uninitialized members. */ /* Skip uninitialized members and base classes. */
if (!TREE_TYPE (init)) if (!TREE_VALUE (init)
|| TREE_CODE (TREE_PURPOSE (init)) != FIELD_DECL)
continue; continue;
/* See if this field is a member of a union, or a member of a /* See if this field is a member of a union, or a member of a
structure contained in a union, etc. */ structure contained in a union, etc. */
...@@ -600,231 +636,73 @@ sort_member_init (t, member_init_list) ...@@ -600,231 +636,73 @@ sort_member_init (t, member_init_list)
} }
} }
return init_list; return sorted_inits;
}
/* Like sort_member_init, but used for initializers of base classes.
*RBASE_PTR is filled in with the initializers for non-virtual bases;
vbase_ptr gets the virtual bases. */
static void
sort_base_init (t, base_init_list, rbase_ptr, vbase_ptr)
tree t;
tree base_init_list;
tree *rbase_ptr, *vbase_ptr;
{
tree binfos = BINFO_BASETYPES (TYPE_BINFO (t));
int n_baseclasses = binfos ? TREE_VEC_LENGTH (binfos) : 0;
int i;
tree x;
tree last;
/* For warn_reorder. */
int last_pos = 0;
tree last_base = NULL_TREE;
tree rbases = NULL_TREE;
tree vbases = NULL_TREE;
/* First walk through and splice out vbase and invalid initializers.
Also replace types with binfos. */
last = tree_cons (NULL_TREE, NULL_TREE, base_init_list);
for (x = TREE_CHAIN (last); x; x = TREE_CHAIN (x))
{
tree basetype = TREE_PURPOSE (x);
tree binfo = (TREE_CODE (basetype) == TREE_VEC
? basetype : binfo_or_else (basetype, t));
if (binfo == NULL_TREE)
/* BASETYPE might be an inaccessible direct base (because it
is also an indirect base). */
continue;
if (TREE_VIA_VIRTUAL (binfo))
{
/* Virtual base classes are special cases. Their
initializers are recorded with this constructor, and they
are used when this constructor is the top-level
constructor called. */
tree v = binfo_for_vbase (BINFO_TYPE (binfo), t);
vbases = tree_cons (v, TREE_VALUE (x), vbases);
}
else
{
/* Otherwise, it must be an immediate base class. */
my_friendly_assert
(same_type_p (BINFO_TYPE (BINFO_INHERITANCE_CHAIN (binfo)),
t), 20011113);
TREE_PURPOSE (x) = binfo;
TREE_CHAIN (last) = x;
last = x;
}
}
TREE_CHAIN (last) = NULL_TREE;
/* Now walk through our regular bases and make sure they're initialized. */
for (i = 0; i < n_baseclasses; ++i)
{
/* The base for which we're currently initializing. */
tree base_binfo = TREE_VEC_ELT (binfos, i);
/* The initializer for BASE_BINFO. */
tree init;
int pos;
if (TREE_VIA_VIRTUAL (base_binfo))
continue;
/* We haven't found the BASE_BINFO yet. */
init = NULL_TREE;
/* Loop through all the explicitly initialized bases, looking
for an appropriate initializer. */
for (x = base_init_list, pos = 0; x; x = TREE_CHAIN (x), ++pos)
{
tree binfo = TREE_PURPOSE (x);
if (binfo == base_binfo && !init)
{
if (warn_reorder)
{
if (pos < last_pos)
{
cp_warning_at ("base initializers for `%#T'", last_base);
cp_warning_at (" and `%#T'", BINFO_TYPE (binfo));
warning (" will be re-ordered to match inheritance order");
}
last_pos = pos;
last_base = BINFO_TYPE (binfo);
}
/* Make sure we won't try to work on this init again. */
TREE_PURPOSE (x) = NULL_TREE;
init = build_tree_list (binfo, TREE_VALUE (x));
}
else if (binfo == base_binfo)
{
error ("base class `%T' already initialized",
BINFO_TYPE (binfo));
break;
}
}
/* If we didn't find BASE_BINFO in the list, create a dummy entry
so the two lists (RBASES and the list of bases) will be
symmetrical. */
if (!init)
init = build_tree_list (NULL_TREE, NULL_TREE);
rbases = chainon (rbases, init);
}
*rbase_ptr = rbases;
*vbase_ptr = vbases;
} }
/* Perform whatever initializations have yet to be done on the base /* Initialize all bases and members of CURRENT_CLASS_TYPE. MEM_INITS
class, and non-static data members, of the CURRENT_CLASS_TYPE. is a TREE_LIST giving the explicit mem-initializer-list for the
These actions are given by the BASE_INIT_LIST and MEM_INIT_LIST, constructor. The TREE_PURPOSE of each entry is a subobject (a
respectively. FIELD_DECL or a BINFO) of the CURRENT_CLASS_TYPE. The TREE_VALUE
is a TREE_LIST giving the arguments to the constructor or
If there is a need for a call to a constructor, we must surround void_type_node for an empty list of arguments. */
that call with a pushlevel/poplevel pair, since we are technically
at the PARM level of scope. */
void void
emit_base_init (mem_init_list, base_init_list) emit_mem_initializers (tree mem_inits)
tree mem_init_list;
tree base_init_list;
{ {
tree member; /* Sort the mem-initializers into the order in which the
tree rbase_init_list, vbase_init_list; initializations should be performed. */
tree t = current_class_type; mem_inits = sort_mem_initializers (current_class_type, mem_inits);
tree t_binfo = TYPE_BINFO (t);
tree binfos = BINFO_BASETYPES (t_binfo); /* Initialize base classes. */
int i; while (mem_inits
int n_baseclasses = BINFO_N_BASETYPES (t_binfo); && TREE_CODE (TREE_PURPOSE (mem_inits)) != FIELD_DECL)
{
mem_init_list = sort_member_init (t, mem_init_list); tree subobject = TREE_PURPOSE (mem_inits);
sort_base_init (t, base_init_list, &rbase_init_list, &vbase_init_list); tree arguments = TREE_VALUE (mem_inits);
/* First, initialize the virtual base classes, if we are /* If these initializations are taking place in a copy
constructing the most-derived object. */ constructor, the base class should probably be explicitly
if (TYPE_USES_VIRTUAL_BASECLASSES (t)) initialized. */
{ if (extra_warnings && !arguments
tree first_arg = TREE_CHAIN (DECL_ARGUMENTS (current_function_decl)); && DECL_COPY_CONSTRUCTOR_P (current_function_decl)
construct_virtual_bases (t, current_class_ref, current_class_ptr, && TYPE_NEEDS_CONSTRUCTING (BINFO_TYPE (subobject)))
vbase_init_list, first_arg); warning ("base class `%#T' should be explicitly initialized in the "
} "copy constructor",
BINFO_TYPE (subobject));
/* Now, perform initialization of non-virtual base classes. */
for (i = 0; i < n_baseclasses; i++) /* If an explicit -- but empty -- initializer list was present,
{ treat it just like default initialization at this point. */
tree base_binfo = TREE_VEC_ELT (binfos, i); if (arguments == void_type_node)
tree init = void_list_node; arguments = NULL_TREE;
if (TREE_VIA_VIRTUAL (base_binfo)) /* Initialize the base. */
continue; if (TREE_VIA_VIRTUAL (subobject))
construct_virtual_base (subobject, arguments);
my_friendly_assert (BINFO_INHERITANCE_CHAIN (base_binfo) == t_binfo, else
999);
if (TREE_PURPOSE (rbase_init_list))
init = TREE_VALUE (rbase_init_list);
else if (TYPE_NEEDS_CONSTRUCTING (BINFO_TYPE (base_binfo)))
{ {
init = NULL_TREE; tree base_addr;
if (extra_warnings
&& DECL_COPY_CONSTRUCTOR_P (current_function_decl))
warning ("base class `%#T' should be explicitly initialized in the copy constructor",
BINFO_TYPE (base_binfo));
}
if (init != void_list_node) base_addr = build_base_path (PLUS_EXPR, current_class_ptr,
{ subobject, 1);
member = build_base_path (PLUS_EXPR, current_class_ptr, expand_aggr_init_1 (subobject, NULL_TREE,
base_binfo, 1); build_indirect_ref (base_addr, NULL),
expand_aggr_init_1 (base_binfo, NULL_TREE, arguments,
build_indirect_ref (member, NULL), init,
LOOKUP_NORMAL); LOOKUP_NORMAL);
expand_cleanup_for_base (subobject, NULL_TREE);
} }
expand_cleanup_for_base (base_binfo, NULL_TREE); mem_inits = TREE_CHAIN (mem_inits);
rbase_init_list = TREE_CHAIN (rbase_init_list);
} }
/* Initialize the vtable pointers for the class. */ /* Initialize the vptrs. */
initialize_vtbl_ptrs (current_class_ptr); initialize_vtbl_ptrs (current_class_ptr);
while (mem_init_list) /* Initialize the data members. */
while (mem_inits)
{ {
tree init; perform_member_init (TREE_PURPOSE (mem_inits),
tree member; TREE_VALUE (mem_inits));
int from_init_list; mem_inits = TREE_CHAIN (mem_inits);
member = TREE_PURPOSE (mem_init_list);
/* See if we had a user-specified member initialization. */
if (TREE_TYPE (mem_init_list))
{
init = TREE_VALUE (mem_init_list);
from_init_list = 1;
}
else
{
init = DECL_INITIAL (member);
from_init_list = 0;
/* Effective C++ rule 12. */
if (warn_ecpp && init == NULL_TREE
&& !DECL_ARTIFICIAL (member)
&& TREE_CODE (TREE_TYPE (member)) != ARRAY_TYPE)
warning ("`%D' should be initialized in the member initialization list", member);
}
perform_member_init (member, init, from_init_list);
mem_init_list = TREE_CHAIN (mem_init_list);
} }
} }
...@@ -948,49 +826,16 @@ expand_cleanup_for_base (binfo, flag) ...@@ -948,49 +826,16 @@ expand_cleanup_for_base (binfo, flag)
finish_eh_cleanup (expr); finish_eh_cleanup (expr);
} }
/* Subroutine of `expand_aggr_vbase_init'. /* Construct the virtual base-class VBASE passing the ARGUMENTS to its
BINFO is the binfo of the type that is being initialized. constructor. */
INIT_LIST is the list of initializers for the virtual baseclass. */
static void static void
expand_aggr_vbase_init_1 (binfo, exp, addr, init_list) construct_virtual_base (tree vbase, tree arguments)
tree binfo, exp, addr, init_list;
{ {
tree init = purpose_member (binfo, init_list);
tree ref = build_indirect_ref (addr, NULL);
if (init)
init = TREE_VALUE (init);
/* Call constructors, but don't set up vtables. */
expand_aggr_init_1 (binfo, exp, ref, init, LOOKUP_COMPLAIN);
}
/* Construct the virtual base-classes of THIS_REF (whose address is
THIS_PTR). The object has the indicated TYPE. The construction
actually takes place only if FLAG is nonzero. INIT_LIST is list
of initializations for constructors to perform. */
static void
construct_virtual_bases (type, this_ref, this_ptr, init_list, flag)
tree type;
tree this_ref;
tree this_ptr;
tree init_list;
tree flag;
{
tree vbases;
/* If there are no virtual baseclasses, we shouldn't even be here. */
my_friendly_assert (TYPE_USES_VIRTUAL_BASECLASSES (type), 19990621);
/* Now, run through the baseclasses, initializing each. */
for (vbases = CLASSTYPE_VBASECLASSES (type); vbases;
vbases = TREE_CHAIN (vbases))
{
tree inner_if_stmt; tree inner_if_stmt;
tree compound_stmt; tree compound_stmt;
tree exp; tree exp;
tree vbase; tree flag;
/* If there are virtual base classes with destructors, we need to /* If there are virtual base classes with destructors, we need to
emit cleanups to destroy them if an exception is thrown during emit cleanups to destroy them if an exception is thrown during
...@@ -1006,6 +851,7 @@ construct_virtual_bases (type, this_ref, this_ptr, init_list, flag) ...@@ -1006,6 +851,7 @@ construct_virtual_bases (type, this_ref, this_ptr, init_list, flag)
in the outer block.) We trust the back-end to figure out in the outer block.) We trust the back-end to figure out
that the FLAG will not change across initializations, and that the FLAG will not change across initializations, and
avoid doing multiple tests. */ avoid doing multiple tests. */
flag = TREE_CHAIN (DECL_ARGUMENTS (current_function_decl));
inner_if_stmt = begin_if_stmt (); inner_if_stmt = begin_if_stmt ();
finish_if_stmt_cond (flag, inner_if_stmt); finish_if_stmt_cond (flag, inner_if_stmt);
compound_stmt = begin_compound_stmt (/*has_no_scope=*/1); compound_stmt = begin_compound_stmt (/*has_no_scope=*/1);
...@@ -1014,23 +860,23 @@ construct_virtual_bases (type, this_ref, this_ptr, init_list, flag) ...@@ -1014,23 +860,23 @@ construct_virtual_bases (type, this_ref, this_ptr, init_list, flag)
constructing virtual bases, then we must be the most derived constructing virtual bases, then we must be the most derived
class. Therefore, we don't have to look up the virtual base; class. Therefore, we don't have to look up the virtual base;
we already know where it is. */ we already know where it is. */
vbase = TREE_VALUE (vbases);
exp = build (PLUS_EXPR, exp = build (PLUS_EXPR,
TREE_TYPE (this_ptr), TREE_TYPE (current_class_ptr),
this_ptr, current_class_ptr,
fold (build1 (NOP_EXPR, TREE_TYPE (this_ptr), fold (build1 (NOP_EXPR, TREE_TYPE (current_class_ptr),
BINFO_OFFSET (vbase)))); BINFO_OFFSET (vbase))));
exp = build1 (NOP_EXPR, exp = build1 (NOP_EXPR,
build_pointer_type (BINFO_TYPE (vbase)), build_pointer_type (BINFO_TYPE (vbase)),
exp); exp);
exp = build1 (INDIRECT_REF, BINFO_TYPE (vbase), exp);
expand_aggr_vbase_init_1 (vbase, this_ref, exp, init_list); expand_aggr_init_1 (vbase, current_class_ref, exp,
arguments, LOOKUP_COMPLAIN);
finish_compound_stmt (/*has_no_scope=*/1, compound_stmt); finish_compound_stmt (/*has_no_scope=*/1, compound_stmt);
finish_then_clause (inner_if_stmt); finish_then_clause (inner_if_stmt);
finish_if_stmt (); finish_if_stmt ();
expand_cleanup_for_base (vbase, flag); expand_cleanup_for_base (vbase, flag);
}
} }
/* Find the context in which this FIELD can be initialized. */ /* Find the context in which this FIELD can be initialized. */
...@@ -1079,46 +925,41 @@ member_init_ok_or_else (field, type, member_name) ...@@ -1079,46 +925,41 @@ member_init_ok_or_else (field, type, member_name)
return 1; return 1;
} }
/* EXP is an expression of aggregate type. NAME is an IDENTIFIER_NODE /* NAME is a FIELD_DECL, an IDENTIFIER_NODE which names a field, or it
which names a field, or it is a _TYPE node or TYPE_DECL which names is a _TYPE node or TYPE_DECL which names a base for that type.
a base for that type. INIT is a parameter list for that field's or INIT is a parameter list for that field's or base's constructor.
base's constructor. Check the validity of NAME, and return a Check the validity of NAME, and return a TREE_LIST of the base
TREE_LIST of the base _TYPE or FIELD_DECL and the INIT. EXP is used _TYPE or FIELD_DECL and the INIT. If NAME is invalid, return
only to get its type. If NAME is invalid, return NULL_TREE and NULL_TREE and issue a diagnostic.
issue a diagnostic.
An old style unnamed direct single base construction is permitted, An old style unnamed direct single base construction is permitted,
where NAME is NULL. */ where NAME is NULL. */
tree tree
expand_member_init (exp, name, init) expand_member_init (tree name, tree init)
tree exp, name, init;
{ {
tree basetype = NULL_TREE, field; tree basetype;
tree type; tree field;
if (exp == NULL_TREE) if (!current_class_ref)
return NULL_TREE; return NULL_TREE;
type = TYPE_MAIN_VARIANT (TREE_TYPE (exp));
my_friendly_assert (IS_AGGR_TYPE (type), 20011113);
if (!name) if (!name)
{ {
/* This is an obsolete unnamed base class initializer. The /* This is an obsolete unnamed base class initializer. The
parser will already have warned about its use. */ parser will already have warned about its use. */
switch (CLASSTYPE_N_BASECLASSES (type)) switch (CLASSTYPE_N_BASECLASSES (current_class_type))
{ {
case 0: case 0:
error ("unnamed initializer for `%T', which has no base classes", error ("unnamed initializer for `%T', which has no base classes",
type); current_class_type);
return NULL_TREE; return NULL_TREE;
case 1: case 1:
basetype = TYPE_BINFO_BASETYPE (type, 0); basetype = TYPE_BINFO_BASETYPE (current_class_type, 0);
break; break;
default: default:
error ("unnamed initializer for `%T', which uses multiple inheritance", error ("unnamed initializer for `%T', which uses multiple inheritance",
type); current_class_type);
return NULL_TREE; return NULL_TREE;
} }
} }
...@@ -1129,44 +970,54 @@ expand_member_init (exp, name, init) ...@@ -1129,44 +970,54 @@ expand_member_init (exp, name, init)
} }
else if (TREE_CODE (name) == TYPE_DECL) else if (TREE_CODE (name) == TYPE_DECL)
basetype = TYPE_MAIN_VARIANT (TREE_TYPE (name)); basetype = TYPE_MAIN_VARIANT (TREE_TYPE (name));
else
basetype = NULL_TREE;
my_friendly_assert (init != NULL_TREE, 0); my_friendly_assert (init != NULL_TREE, 0);
if (init == void_type_node)
init = NULL_TREE;
if (basetype) if (basetype)
{ {
tree binfo;
if (current_template_parms) if (current_template_parms)
; return build_tree_list (basetype, init);
else if (vec_binfo_member (basetype, TYPE_BINFO_BASETYPES (type)))
/* A direct base. */; binfo = lookup_base (current_class_type, basetype,
else if (binfo_for_vbase (basetype, type)) ba_ignore, NULL);
/* A virtual base. */; if (binfo)
else {
if (TREE_VIA_VIRTUAL (binfo))
binfo = binfo_for_vbase (basetype, current_class_type);
else if (BINFO_INHERITANCE_CHAIN (binfo)
!= TYPE_BINFO (current_class_type))
binfo = NULL_TREE;
}
if (!binfo)
{ {
if (TYPE_USES_VIRTUAL_BASECLASSES (type)) if (TYPE_USES_VIRTUAL_BASECLASSES (current_class_type))
error ("type `%D' is not a direct or virtual base of `%T'", error ("type `%D' is not a direct or virtual base of `%T'",
name, type); name, current_class_type);
else else
error ("type `%D' is not a direct base of `%T'", error ("type `%D' is not a direct base of `%T'",
name, type); name, current_class_type);
return NULL_TREE; return NULL_TREE;
} }
init = build_tree_list (basetype, init); if (binfo)
return build_tree_list (binfo, init);
} }
else else
{ {
field = lookup_field (type, name, 1, 0); if (TREE_CODE (name) == IDENTIFIER_NODE)
field = lookup_field (current_class_type, name, 1, 0);
if (! member_init_ok_or_else (field, type, name)) else
return NULL_TREE; field = name;
init = build_tree_list (field, init); if (member_init_ok_or_else (field, current_class_type, name))
return build_tree_list (field, init);
} }
return init; return NULL_TREE;
} }
/* This is like `expand_member_init', only it stores one aggregate /* This is like `expand_member_init', only it stores one aggregate
......
...@@ -536,7 +536,6 @@ do_build_copy_constructor (fndecl) ...@@ -536,7 +536,6 @@ do_build_copy_constructor (fndecl)
int n_bases = CLASSTYPE_N_BASECLASSES (current_class_type); int n_bases = CLASSTYPE_N_BASECLASSES (current_class_type);
tree binfos = TYPE_BINFO_BASETYPES (current_class_type); tree binfos = TYPE_BINFO_BASETYPES (current_class_type);
tree member_init_list = NULL_TREE; tree member_init_list = NULL_TREE;
tree base_init_list = NULL_TREE;
int cvquals = cp_type_quals (TREE_TYPE (parm)); int cvquals = cp_type_quals (TREE_TYPE (parm));
int i; int i;
...@@ -550,10 +549,12 @@ do_build_copy_constructor (fndecl) ...@@ -550,10 +549,12 @@ do_build_copy_constructor (fndecl)
{ {
tree binfo = TREE_VALUE (t); tree binfo = TREE_VALUE (t);
base_init_list = tree_cons (binfo, member_init_list
= tree_cons (binfo,
build_tree_list (NULL_TREE,
build_base_path (PLUS_EXPR, parm, build_base_path (PLUS_EXPR, parm,
binfo, 1), binfo, 1)),
base_init_list); member_init_list);
} }
for (i = 0; i < n_bases; ++i) for (i = 0; i < n_bases; ++i)
...@@ -562,10 +563,12 @@ do_build_copy_constructor (fndecl) ...@@ -562,10 +563,12 @@ do_build_copy_constructor (fndecl)
if (TREE_VIA_VIRTUAL (binfo)) if (TREE_VIA_VIRTUAL (binfo))
continue; continue;
base_init_list = tree_cons (binfo, member_init_list
= tree_cons (binfo,
build_tree_list (NULL_TREE,
build_base_path (PLUS_EXPR, parm, build_base_path (PLUS_EXPR, parm,
binfo, 1), binfo, 1)),
base_init_list); member_init_list);
} }
for (; fields; fields = TREE_CHAIN (fields)) for (; fields; fields = TREE_CHAIN (fields))
...@@ -609,9 +612,7 @@ do_build_copy_constructor (fndecl) ...@@ -609,9 +612,7 @@ do_build_copy_constructor (fndecl)
member_init_list member_init_list
= tree_cons (field, init, member_init_list); = tree_cons (field, init, member_init_list);
} }
member_init_list = nreverse (member_init_list); finish_mem_initializers (member_init_list);
base_init_list = nreverse (base_init_list);
emit_base_init (member_init_list, base_init_list);
} }
} }
......
...@@ -981,31 +981,27 @@ member_init: ...@@ -981,31 +981,27 @@ member_init:
{ {
if (current_class_name) if (current_class_name)
pedwarn ("anachronistic old style base class initializer"); pedwarn ("anachronistic old style base class initializer");
$$ = expand_member_init (current_class_ref, NULL_TREE, $2); $$ = expand_member_init (NULL_TREE, $2);
} }
| LEFT_RIGHT | LEFT_RIGHT
{ {
if (current_class_name) if (current_class_name)
pedwarn ("anachronistic old style base class initializer"); pedwarn ("anachronistic old style base class initializer");
$$ = expand_member_init (current_class_ref, $$ = expand_member_init (NULL_TREE,
NULL_TREE,
void_type_node); void_type_node);
} }
| notype_identifier '(' nonnull_exprlist ')' | notype_identifier '(' nonnull_exprlist ')'
{ $$ = expand_member_init (current_class_ref, $1, $3); } { $$ = expand_member_init ($1, $3); }
| notype_identifier LEFT_RIGHT | notype_identifier LEFT_RIGHT
{ $$ = expand_member_init (current_class_ref, $1, { $$ = expand_member_init ($1, void_type_node); }
void_type_node); }
| nonnested_type '(' nonnull_exprlist ')' | nonnested_type '(' nonnull_exprlist ')'
{ $$ = expand_member_init (current_class_ref, $1, $3); } { $$ = expand_member_init ($1, $3); }
| nonnested_type LEFT_RIGHT | nonnested_type LEFT_RIGHT
{ $$ = expand_member_init (current_class_ref, $1, { $$ = expand_member_init ($1, void_type_node); }
void_type_node); }
| typename_sub '(' nonnull_exprlist ')' | typename_sub '(' nonnull_exprlist ')'
{ $$ = expand_member_init (current_class_ref, $1, $3); } { $$ = expand_member_init ($1, $3); }
| typename_sub LEFT_RIGHT | typename_sub LEFT_RIGHT
{ $$ = expand_member_init (current_class_ref, $1, { $$ = expand_member_init ($1, void_type_node); }
void_type_node); }
| error | error
{ $$ = NULL_TREE; } { $$ = NULL_TREE; }
; ;
......
...@@ -7369,18 +7369,10 @@ tsubst_expr (t, args, complain, in_decl) ...@@ -7369,18 +7369,10 @@ tsubst_expr (t, args, complain, in_decl)
break; break;
case CTOR_INITIALIZER: case CTOR_INITIALIZER:
{
tree member_init_list;
tree base_init_list;
prep_stmt (t); prep_stmt (t);
member_init_list finish_mem_initializers (tsubst_initializer_list
= tsubst_initializer_list (TREE_OPERAND (t, 0), args); (TREE_OPERAND (t, 0), args));
base_init_list
= tsubst_initializer_list (TREE_OPERAND (t, 1), args);
emit_base_init (member_init_list, base_init_list);
break; break;
}
case RETURN_STMT: case RETURN_STMT:
prep_stmt (t); prep_stmt (t);
...@@ -10293,8 +10285,7 @@ static tree ...@@ -10293,8 +10285,7 @@ static tree
tsubst_initializer_list (t, argvec) tsubst_initializer_list (t, argvec)
tree t, argvec; tree t, argvec;
{ {
tree first = NULL_TREE; tree inits = NULL_TREE;
tree *p = &first;
for (; t; t = TREE_CHAIN (t)) for (; t; t = TREE_CHAIN (t))
{ {
...@@ -10312,13 +10303,17 @@ tsubst_initializer_list (t, argvec) ...@@ -10312,13 +10303,17 @@ tsubst_initializer_list (t, argvec)
else if (TREE_CODE (init) == TREE_LIST) else if (TREE_CODE (init) == TREE_LIST)
for (val = init; val; val = TREE_CHAIN (val)) for (val = init; val; val = TREE_CHAIN (val))
TREE_VALUE (val) = convert_from_reference (TREE_VALUE (val)); TREE_VALUE (val) = convert_from_reference (TREE_VALUE (val));
else else if (init != void_type_node)
init = convert_from_reference (init); init = convert_from_reference (init);
*p = build_tree_list (decl, init); init = expand_member_init (decl, init);
p = &TREE_CHAIN (*p); if (init)
{
TREE_CHAIN (init) = inits;
inits = init;
}
} }
return first; return inits;
} }
/* Set CURRENT_ACCESS_SPECIFIER based on the protection of DECL. */ /* Set CURRENT_ACCESS_SPECIFIER based on the protection of DECL. */
......
...@@ -1094,67 +1094,21 @@ begin_mem_initializers () ...@@ -1094,67 +1094,21 @@ begin_mem_initializers ()
error ("only constructors take base initializers"); error ("only constructors take base initializers");
} }
/* The INIT_LIST is a list of mem-initializers, in the order they were /* The MEM_INITS is a list of mem-initializers, in reverse of the
written by the user. The TREE_VALUE of each node is a list of order they were written by the user. Each node is as for
initializers for a particular subobject. The TREE_PURPOSE is a emit_mem_initializers. */
FIELD_DECL is the initializer is for a non-static data member, and
a class type if the initializer is for a base class. */
void void
finish_mem_initializers (init_list) finish_mem_initializers (tree mem_inits)
tree init_list;
{ {
tree member_init_list; /* Reorder the MEM_INITS so that they are in the order they appeared
tree base_init_list; in the source program. */
tree last_base_warned_about; mem_inits = nreverse (mem_inits);
tree next;
tree init;
member_init_list = NULL_TREE;
base_init_list = NULL_TREE;
last_base_warned_about = NULL_TREE;
for (init = init_list; init; init = next)
{
next = TREE_CHAIN (init);
if (TREE_CODE (TREE_PURPOSE (init)) == FIELD_DECL)
{
TREE_CHAIN (init) = member_init_list;
member_init_list = init;
/* We're running through the initializers from right to left
as we process them here. So, if we see a data member
initializer after we see a base initializer, that
actually means that the base initializer preceded the
data member initializer. */
if (warn_reorder && last_base_warned_about != base_init_list)
{
tree base;
for (base = base_init_list;
base != last_base_warned_about;
base = TREE_CHAIN (base))
{
warning ("base initializer for `%T'",
TREE_PURPOSE (base));
warning (" will be re-ordered to precede member initializations");
}
last_base_warned_about = base_init_list;
}
}
else
{
TREE_CHAIN (init) = base_init_list;
base_init_list = init;
}
}
if (processing_template_decl) if (processing_template_decl)
add_stmt (build_min_nt (CTOR_INITIALIZER, add_stmt (build_min_nt (CTOR_INITIALIZER, mem_inits));
member_init_list, base_init_list));
else else
emit_base_init (member_init_list, base_init_list); emit_mem_initializers (mem_inits);
} }
/* Returns the stack of SCOPE_STMTs for the current function. */ /* Returns the stack of SCOPE_STMTs for the current function. */
......
2002-10-02 Mark Mitchell <mark@codesourcery.com>
PR c++/7188.
* g++.dg/template/meminit1.C: New test.
* g++.dg/warn/Wreorder-1.C: Likewise.
* g++.old-deja/g++.mike/warn3.C: Tweak.
* lib/prune.exp: Ingore "in copy constructor".
2002-10-02 Andreas Jaeger <aj@suse.de> 2002-10-02 Andreas Jaeger <aj@suse.de>
* gcc.dg/20020919-1.c, gcc.dg/inline-2.c, gcc.dg/980211-1.c, * gcc.dg/20020919-1.c, gcc.dg/inline-2.c, gcc.dg/980211-1.c,
......
template <class T >
struct S
{
S() : S() {} // { dg-error "base" }
};
S<int> s; // { dg-error "instantiated" }
// { dg-options "-Wreorder -W" }
struct S {
S ();
};
struct T {
T ();
};
struct U : virtual public S, virtual public T {
U () : T (), S () {} // { dg-warning "" }
U (const U&) : S () {} // { dg-warning "copy" }
};
...@@ -7,6 +7,6 @@ public: ...@@ -7,6 +7,6 @@ public:
}; };
class D : public B { class D : public B {
int member; int member; // WARNING - reordered
D() : member(0), B(member) { } // WARNING - reordered D() : member(0), B(member) { } // WARNING - reordered
}; };
# Copyright (C) 1997, 1999, 2000 Free Software Foundation, Inc. # Copyright (C) 1997, 1999, 2000, 2002 Free Software Foundation, Inc.
# This program is free software; you can redistribute it and/or modify # This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by # it under the terms of the GNU General Public License as published by
...@@ -19,7 +19,7 @@ ...@@ -19,7 +19,7 @@
proc prune_gcc_output { text } { proc prune_gcc_output { text } {
#send_user "Before:$text\n" #send_user "Before:$text\n"
regsub -all "(^|\n)\[^\n\]*: In (function|member|method|constructor|instantiation|program|subroutine|block-data) \[^\n\]*" $text "" text regsub -all "(^|\n)\[^\n\]*: In (function|member|method|(copy )?constructor|instantiation|program|subroutine|block-data) \[^\n\]*" $text "" text
regsub -all "(^|\n)\[^\n\]*: At (top level|global scope):\[^\n\]*" $text "" text regsub -all "(^|\n)\[^\n\]*: At (top level|global scope):\[^\n\]*" $text "" text
regsub -all "(^|\n)collect2: ld returned \[^\n\]*" $text "" text regsub -all "(^|\n)collect2: ld returned \[^\n\]*" $text "" text
regsub -all "(^|\n)Please submit.*instructions\[^\n\]*" $text "" text regsub -all "(^|\n)Please submit.*instructions\[^\n\]*" $text "" text
......
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