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. /* Initialize all bases and members of CURRENT_CLASS_TYPE. MEM_INITS
*RBASE_PTR is filled in with the initializers for non-virtual bases; is a TREE_LIST giving the explicit mem-initializer-list for the
vbase_ptr gets the virtual bases. */ constructor. The TREE_PURPOSE of each entry is a subobject (a
FIELD_DECL or a BINFO) of the CURRENT_CLASS_TYPE. The TREE_VALUE
static void is a TREE_LIST giving the arguments to the constructor or
sort_base_init (t, base_init_list, rbase_ptr, vbase_ptr) void_type_node for an empty list of arguments. */
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
class, and non-static data members, of the CURRENT_CLASS_TYPE.
These actions are given by the BASE_INIT_LIST and MEM_INIT_LIST,
respectively.
If there is a need for a call to a constructor, we must surround
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;
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)
{ {
member = build_base_path (PLUS_EXPR, current_class_ptr, tree base_addr;
base_binfo, 1);
expand_aggr_init_1 (base_binfo, NULL_TREE, base_addr = build_base_path (PLUS_EXPR, current_class_ptr,
build_indirect_ref (member, NULL), init, subobject, 1);
expand_aggr_init_1 (subobject, NULL_TREE,
build_indirect_ref (base_addr, NULL),
arguments,
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,89 +826,57 @@ expand_cleanup_for_base (binfo, flag) ...@@ -948,89 +826,57 @@ 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 inner_if_stmt;
tree ref = build_indirect_ref (addr, NULL); tree compound_stmt;
tree exp;
if (init) tree flag;
init = TREE_VALUE (init);
/* Call constructors, but don't set up vtables. */ /* If there are virtual base classes with destructors, we need to
expand_aggr_init_1 (binfo, exp, ref, init, LOOKUP_COMPLAIN); emit cleanups to destroy them if an exception is thrown during
} the construction process. These exception regions (i.e., the
period during which the cleanups must occur) begin from the time
/* Construct the virtual base-classes of THIS_REF (whose address is the construction is complete to the end of the function. If we
THIS_PTR). The object has the indicated TYPE. The construction create a conditional block in which to initialize the
actually takes place only if FLAG is nonzero. INIT_LIST is list base-classes, then the cleanup region for the virtual base begins
of initializations for constructors to perform. */ inside a block, and ends outside of that block. This situation
confuses the sjlj exception-handling code. Therefore, we do not
static void create a single conditional block, but one for each
construct_virtual_bases (type, this_ref, this_ptr, init_list, flag) initialization. (That way the cleanup regions always begin
tree type; in the outer block.) We trust the back-end to figure out
tree this_ref; that the FLAG will not change across initializations, and
tree this_ptr; avoid doing multiple tests. */
tree init_list; flag = TREE_CHAIN (DECL_ARGUMENTS (current_function_decl));
tree flag; inner_if_stmt = begin_if_stmt ();
{ finish_if_stmt_cond (flag, inner_if_stmt);
tree vbases; compound_stmt = begin_compound_stmt (/*has_no_scope=*/1);
/* If there are no virtual baseclasses, we shouldn't even be here. */ /* Compute the location of the virtual base. If we're
my_friendly_assert (TYPE_USES_VIRTUAL_BASECLASSES (type), 19990621); constructing virtual bases, then we must be the most derived
class. Therefore, we don't have to look up the virtual base;
/* Now, run through the baseclasses, initializing each. */ we already know where it is. */
for (vbases = CLASSTYPE_VBASECLASSES (type); vbases; exp = build (PLUS_EXPR,
vbases = TREE_CHAIN (vbases)) TREE_TYPE (current_class_ptr),
{ current_class_ptr,
tree inner_if_stmt; fold (build1 (NOP_EXPR, TREE_TYPE (current_class_ptr),
tree compound_stmt; BINFO_OFFSET (vbase))));
tree exp; exp = build1 (NOP_EXPR,
tree vbase; build_pointer_type (BINFO_TYPE (vbase)),
exp);
/* If there are virtual base classes with destructors, we need to exp = build1 (INDIRECT_REF, BINFO_TYPE (vbase), exp);
emit cleanups to destroy them if an exception is thrown during
the construction process. These exception regions (i.e., the expand_aggr_init_1 (vbase, current_class_ref, exp,
period during which the cleanups must occur) begin from the time arguments, LOOKUP_COMPLAIN);
the construction is complete to the end of the function. If we finish_compound_stmt (/*has_no_scope=*/1, compound_stmt);
create a conditional block in which to initialize the finish_then_clause (inner_if_stmt);
base-classes, then the cleanup region for the virtual base begins finish_if_stmt ();
inside a block, and ends outside of that block. This situation
confuses the sjlj exception-handling code. Therefore, we do not expand_cleanup_for_base (vbase, flag);
create a single conditional block, but one for each
initialization. (That way the cleanup regions always begin
in the outer block.) We trust the back-end to figure out
that the FLAG will not change across initializations, and
avoid doing multiple tests. */
inner_if_stmt = begin_if_stmt ();
finish_if_stmt_cond (flag, inner_if_stmt);
compound_stmt = begin_compound_stmt (/*has_no_scope=*/1);
/* Compute the location of the virtual base. If we're
constructing virtual bases, then we must be the most derived
class. Therefore, we don't have to look up the virtual base;
we already know where it is. */
vbase = TREE_VALUE (vbases);
exp = build (PLUS_EXPR,
TREE_TYPE (this_ptr),
this_ptr,
fold (build1 (NOP_EXPR, TREE_TYPE (this_ptr),
BINFO_OFFSET (vbase))));
exp = build1 (NOP_EXPR,
build_pointer_type (BINFO_TYPE (vbase)),
exp);
expand_aggr_vbase_init_1 (vbase, this_ref, exp, init_list);
finish_compound_stmt (/*has_no_scope=*/1, compound_stmt);
finish_then_clause (inner_if_stmt);
finish_if_stmt ();
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
build_base_path (PLUS_EXPR, parm, = tree_cons (binfo,
binfo, 1), build_tree_list (NULL_TREE,
base_init_list); build_base_path (PLUS_EXPR, parm,
binfo, 1)),
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
build_base_path (PLUS_EXPR, parm, = tree_cons (binfo,
binfo, 1), build_tree_list (NULL_TREE,
base_init_list); build_base_path (PLUS_EXPR, parm,
binfo, 1)),
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:
{ prep_stmt (t);
tree member_init_list; finish_mem_initializers (tsubst_initializer_list
tree base_init_list; (TREE_OPERAND (t, 0), args));
break;
prep_stmt (t);
member_init_list
= tsubst_initializer_list (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;
}
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