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
This commit is contained in:
Mark Mitchell 2002-10-02 20:01:38 +00:00 committed by Mark Mitchell
parent 854ef3909d
commit 2282d28d48
13 changed files with 354 additions and 502 deletions

View File

@ -1,3 +1,29 @@
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>
PR optimization/6627

View File

@ -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
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 (TRY_BLOCK, "try_block", 'e', 2)
DEFTREECODE (EH_SPEC_BLOCK, "eh_spec_block", 'e', 2)

View File

@ -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));
/* in init.c */
extern void emit_base_init PARAMS ((tree, tree));
extern tree expand_member_init PARAMS ((tree, tree, tree));
extern tree expand_member_init (tree, tree);
extern void emit_mem_initializers (tree);
extern tree build_aggr_init PARAMS ((tree, tree, int));
extern tree build_init PARAMS ((tree, tree, int));
extern int is_aggr_type PARAMS ((tree, int));

View File

@ -34,17 +34,15 @@ Boston, MA 02111-1307, USA. */
#include "toplev.h"
#include "ggc.h"
static void expand_aggr_vbase_init_1 PARAMS ((tree, tree, tree, tree));
static void construct_virtual_bases PARAMS ((tree, tree, tree, tree, tree));
static void construct_virtual_base (tree, tree);
static void expand_aggr_init_1 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 void perform_member_init PARAMS ((tree, tree, int));
static void sort_base_init PARAMS ((tree, tree, tree *, tree *));
static void perform_member_init (tree, tree);
static tree build_builtin_delete_call PARAMS ((tree));
static int member_init_ok_or_else PARAMS ((tree, 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 void expand_cleanup_for_base PARAMS ((tree, tree));
static tree get_temp_regvar PARAMS ((tree, tree));
@ -303,16 +301,30 @@ build_default_init (type)
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
perform_member_init (member, init, explicit)
tree member, init;
int explicit;
perform_member_init (tree member, tree init)
{
tree decl;
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,
/*access_path=*/NULL_TREE,
/*preserve_reference=*/true);
@ -333,11 +345,6 @@ perform_member_init (member, init, explicit)
else if (TYPE_NEEDS_CONSTRUCTING (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
&& TREE_CODE (type) == ARRAY_TYPE
&& init != NULL_TREE
@ -443,79 +450,107 @@ build_field_list (t, list, uses_unions_p)
return list;
}
/* The MEMBER_INIT_LIST is a TREE_LIST. The TREE_PURPOSE of each list
gives a FIELD_DECL in T that needs initialization. The TREE_VALUE
gives the initializer, or list of initializer arguments. Sort the
MEMBER_INIT_LIST, returning a version that contains the same
information but in the order that the fields should actually be
initialized. Perform error-checking in the process. */
/* The MEM_INITS are a TREE_LIST. The TREE_PURPOSE of each list gives
a FIELD_DECL or BINFO in T that needs initialization. The
TREE_VALUE gives the initializer, or list of initializer arguments.
Return a TREE_LIST containing all of the initializations required
for T, in the order in which they should be performed. The output
list has the same format as the input. */
static tree
sort_member_init (t, member_init_list)
tree t;
tree member_init_list;
sort_mem_initializers (tree t, tree mem_inits)
{
tree init_list;
tree last_field;
tree init;
tree base;
tree sorted_inits;
tree next_subobject;
int i;
int uses_unions_p;
/* Build up a list of the various fields, in sorted order. */
init_list = nreverse (build_field_list (t, NULL_TREE, &uses_unions_p));
/* Go through the explicit initializers, adding them to the
INIT_LIST. */
last_field = init_list;
for (init = member_init_list; init; init = TREE_CHAIN (init))
/* Build up a list of initializations. The TREE_PURPOSE of entry
will be the subobject (a FIELD_DECL or BINFO) to initialize. The
TREE_VALUE will be the constructor arguments, or NULL if no
explicit initialization was provided. */
sorted_inits = NULL_TREE;
/* Process the virtual bases. */
for (base = CLASSTYPE_VBASECLASSES (t); base; base = TREE_CHAIN (base))
sorted_inits = tree_cons (TREE_VALUE (base), NULL_TREE, sorted_inits);
/* Process the direct bases. */
for (i = 0; i < CLASSTYPE_N_BASECLASSES (t); ++i)
{
tree f;
tree initialized_field;
base = BINFO_BASETYPE (TYPE_BINFO (t), i);
if (!TREE_VIA_VIRTUAL (base))
sorted_inits = tree_cons (base, NULL_TREE, sorted_inits);
}
/* Process the non-static data members. */
sorted_inits = build_field_list (t, sorted_inits, &uses_unions_p);
/* Reverse the entire list of initializations, so that they are in
the order that they will actually be performed. */
sorted_inits = nreverse (sorted_inits);
initialized_field = TREE_PURPOSE (init);
my_friendly_assert (TREE_CODE (initialized_field) == FIELD_DECL,
20000516);
/* 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;
/* If the explicit initializers are in sorted order, then the
INITIALIZED_FIELD will be for a field following the
LAST_FIELD. */
for (f = last_field; f; f = TREE_CHAIN (f))
if (TREE_PURPOSE (f) == initialized_field)
/* 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;
/* Give a warning, if appropriate. */
if (warn_reorder && !f)
/* Issue a warning if the explicit initializer order does not
match that which will actually occur. */
if (warn_reorder && !subobject_init)
{
cp_warning_at ("member initializers for `%#D'",
TREE_PURPOSE (last_field));
cp_warning_at (" and `%#D'", initialized_field);
warning (" will be re-ordered to match declaration order");
if (TREE_CODE (TREE_PURPOSE (next_subobject)) == FIELD_DECL)
cp_warning_at ("`%D' will be initialized after",
TREE_PURPOSE (next_subobject));
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
field on this loop. */
if (!f)
/* Look again, from the beginning of the list. */
if (!subobject_init)
{
f = init_list;
while (TREE_PURPOSE (f) != initialized_field)
f = TREE_CHAIN (f);
subobject_init = sorted_inits;
while (TREE_PURPOSE (subobject_init) != subobject)
subobject_init = TREE_CHAIN (subobject_init);
}
/* It is invalid to initialize the same subobject more than
once. */
if (TREE_VALUE (subobject_init))
{
if (TREE_CODE (subobject) == FIELD_DECL)
error ("multiple initializations given for `%D'", subobject);
else
error ("multiple initializations given for base `%T'",
subobject);
}
/* If there was already an explicit initializer for this field,
issue an error. */
if (TREE_TYPE (f))
error ("multiple initializations given for member `%D'",
initialized_field);
else
{
/* Mark the field as explicitly initialized. */
TREE_TYPE (f) = error_mark_node;
/* And insert the initializer. */
TREE_VALUE (f) = TREE_VALUE (init);
}
/* Remember the location of the last explicitly initialized
field. */
last_field = f;
/* Record the initialization. */
TREE_VALUE (subobject_init) = TREE_VALUE (init);
next_subobject = subobject_init;
}
/* [class.base.init]
@ -525,15 +560,16 @@ sort_member_init (t, member_init_list)
anonymous unions), the ctor-initializer is ill-formed. */
if (uses_unions_p)
{
last_field = NULL_TREE;
for (init = init_list; init; init = TREE_CHAIN (init))
tree last_field = NULL_TREE;
for (init = sorted_inits; init; init = TREE_CHAIN (init))
{
tree field;
tree field_type;
int done;
/* Skip uninitialized members. */
if (!TREE_TYPE (init))
/* Skip uninitialized members and base classes. */
if (!TREE_VALUE (init)
|| TREE_CODE (TREE_PURPOSE (init)) != FIELD_DECL)
continue;
/* See if this field is a member of a union, or a member of a
structure contained in a union, etc. */
@ -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
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. */
/* Initialize all bases and members of CURRENT_CLASS_TYPE. MEM_INITS
is a TREE_LIST giving the explicit mem-initializer-list for the
constructor. The TREE_PURPOSE of each entry is a subobject (a
FIELD_DECL or a BINFO) of the CURRENT_CLASS_TYPE. The TREE_VALUE
is a TREE_LIST giving the arguments to the constructor or
void_type_node for an empty list of arguments. */
void
emit_base_init (mem_init_list, base_init_list)
tree mem_init_list;
tree base_init_list;
emit_mem_initializers (tree mem_inits)
{
tree member;
tree rbase_init_list, vbase_init_list;
tree t = current_class_type;
tree t_binfo = TYPE_BINFO (t);
tree binfos = BINFO_BASETYPES (t_binfo);
int i;
int n_baseclasses = BINFO_N_BASETYPES (t_binfo);
/* Sort the mem-initializers into the order in which the
initializations should be performed. */
mem_inits = sort_mem_initializers (current_class_type, mem_inits);
mem_init_list = sort_member_init (t, mem_init_list);
sort_base_init (t, base_init_list, &rbase_init_list, &vbase_init_list);
/* First, initialize the virtual base classes, if we are
constructing the most-derived object. */
if (TYPE_USES_VIRTUAL_BASECLASSES (t))
/* Initialize base classes. */
while (mem_inits
&& TREE_CODE (TREE_PURPOSE (mem_inits)) != FIELD_DECL)
{
tree first_arg = TREE_CHAIN (DECL_ARGUMENTS (current_function_decl));
construct_virtual_bases (t, current_class_ref, current_class_ptr,
vbase_init_list, first_arg);
}
tree subobject = TREE_PURPOSE (mem_inits);
tree arguments = TREE_VALUE (mem_inits);
/* Now, perform initialization of non-virtual base classes. */
for (i = 0; i < n_baseclasses; i++)
{
tree base_binfo = TREE_VEC_ELT (binfos, i);
tree init = void_list_node;
/* If these initializations are taking place in a copy
constructor, the base class should probably be explicitly
initialized. */
if (extra_warnings && !arguments
&& DECL_COPY_CONSTRUCTOR_P (current_function_decl)
&& TYPE_NEEDS_CONSTRUCTING (BINFO_TYPE (subobject)))
warning ("base class `%#T' should be explicitly initialized in the "
"copy constructor",
BINFO_TYPE (subobject));
if (TREE_VIA_VIRTUAL (base_binfo))
continue;
/* If an explicit -- but empty -- initializer list was present,
treat it just like default initialization at this point. */
if (arguments == void_type_node)
arguments = NULL_TREE;
my_friendly_assert (BINFO_INHERITANCE_CHAIN (base_binfo) == t_binfo,
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,
base_binfo, 1);
expand_aggr_init_1 (base_binfo, NULL_TREE,
build_indirect_ref (member, NULL), init,
LOOKUP_NORMAL);
}
expand_cleanup_for_base (base_binfo, NULL_TREE);
rbase_init_list = TREE_CHAIN (rbase_init_list);
}
/* Initialize the vtable pointers for the class. */
initialize_vtbl_ptrs (current_class_ptr);
while (mem_init_list)
{
tree init;
tree member;
int from_init_list;
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;
}
/* Initialize the base. */
if (TREE_VIA_VIRTUAL (subobject))
construct_virtual_base (subobject, arguments);
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);
tree base_addr;
base_addr = build_base_path (PLUS_EXPR, current_class_ptr,
subobject, 1);
expand_aggr_init_1 (subobject, NULL_TREE,
build_indirect_ref (base_addr, NULL),
arguments,
LOOKUP_NORMAL);
expand_cleanup_for_base (subobject, NULL_TREE);
}
perform_member_init (member, init, from_init_list);
mem_init_list = TREE_CHAIN (mem_init_list);
mem_inits = TREE_CHAIN (mem_inits);
}
/* Initialize the vptrs. */
initialize_vtbl_ptrs (current_class_ptr);
/* Initialize the data members. */
while (mem_inits)
{
perform_member_init (TREE_PURPOSE (mem_inits),
TREE_VALUE (mem_inits));
mem_inits = TREE_CHAIN (mem_inits);
}
}
@ -948,89 +826,57 @@ expand_cleanup_for_base (binfo, flag)
finish_eh_cleanup (expr);
}
/* Subroutine of `expand_aggr_vbase_init'.
BINFO is the binfo of the type that is being initialized.
INIT_LIST is the list of initializers for the virtual baseclass. */
/* Construct the virtual base-class VBASE passing the ARGUMENTS to its
constructor. */
static void
expand_aggr_vbase_init_1 (binfo, exp, addr, init_list)
tree binfo, exp, addr, init_list;
construct_virtual_base (tree vbase, tree arguments)
{
tree init = purpose_member (binfo, init_list);
tree ref = build_indirect_ref (addr, NULL);
tree inner_if_stmt;
tree compound_stmt;
tree exp;
tree flag;
if (init)
init = TREE_VALUE (init);
/* Call constructors, but don't set up vtables. */
expand_aggr_init_1 (binfo, exp, ref, init, LOOKUP_COMPLAIN);
}
/* If there are virtual base classes with destructors, we need to
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
the construction is complete to the end of the function. If we
create a conditional block in which to initialize the
base-classes, then the cleanup region for the virtual base begins
inside a block, and ends outside of that block. This situation
confuses the sjlj exception-handling code. Therefore, we do not
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. */
flag = TREE_CHAIN (DECL_ARGUMENTS (current_function_decl));
inner_if_stmt = begin_if_stmt ();
finish_if_stmt_cond (flag, inner_if_stmt);
compound_stmt = begin_compound_stmt (/*has_no_scope=*/1);
/* 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. */
/* 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. */
exp = build (PLUS_EXPR,
TREE_TYPE (current_class_ptr),
current_class_ptr,
fold (build1 (NOP_EXPR, TREE_TYPE (current_class_ptr),
BINFO_OFFSET (vbase))));
exp = build1 (NOP_EXPR,
build_pointer_type (BINFO_TYPE (vbase)),
exp);
exp = build1 (INDIRECT_REF, BINFO_TYPE (vbase), exp);
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;
expand_aggr_init_1 (vbase, current_class_ref, exp,
arguments, LOOKUP_COMPLAIN);
finish_compound_stmt (/*has_no_scope=*/1, compound_stmt);
finish_then_clause (inner_if_stmt);
finish_if_stmt ();
/* 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 compound_stmt;
tree exp;
tree vbase;
/* If there are virtual base classes with destructors, we need to
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
the construction is complete to the end of the function. If we
create a conditional block in which to initialize the
base-classes, then the cleanup region for the virtual base begins
inside a block, and ends outside of that block. This situation
confuses the sjlj exception-handling code. Therefore, we do not
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);
}
expand_cleanup_for_base (vbase, flag);
}
/* Find the context in which this FIELD can be initialized. */
@ -1079,46 +925,41 @@ member_init_ok_or_else (field, type, member_name)
return 1;
}
/* EXP is an expression of aggregate type. NAME is an IDENTIFIER_NODE
which names a field, or it is a _TYPE node or TYPE_DECL which names
a base for that type. INIT is a parameter list for that field's or
base's constructor. Check the validity of NAME, and return a
TREE_LIST of the base _TYPE or FIELD_DECL and the INIT. EXP is used
only to get its type. If NAME is invalid, return NULL_TREE and
issue a diagnostic.
/* NAME is a FIELD_DECL, an IDENTIFIER_NODE which names a field, or it
is a _TYPE node or TYPE_DECL which names a base for that type.
INIT is a parameter list for that field's or base's constructor.
Check the validity of NAME, and return a TREE_LIST of the base
_TYPE or FIELD_DECL and the INIT. If NAME is invalid, return
NULL_TREE and issue a diagnostic.
An old style unnamed direct single base construction is permitted,
where NAME is NULL. */
tree
expand_member_init (exp, name, init)
tree exp, name, init;
expand_member_init (tree name, tree init)
{
tree basetype = NULL_TREE, field;
tree type;
tree basetype;
tree field;
if (exp == NULL_TREE)
if (!current_class_ref)
return NULL_TREE;
type = TYPE_MAIN_VARIANT (TREE_TYPE (exp));
my_friendly_assert (IS_AGGR_TYPE (type), 20011113);
if (!name)
{
/* This is an obsolete unnamed base class initializer. The
parser will already have warned about its use. */
switch (CLASSTYPE_N_BASECLASSES (type))
switch (CLASSTYPE_N_BASECLASSES (current_class_type))
{
case 0:
error ("unnamed initializer for `%T', which has no base classes",
type);
current_class_type);
return NULL_TREE;
case 1:
basetype = TYPE_BINFO_BASETYPE (type, 0);
basetype = TYPE_BINFO_BASETYPE (current_class_type, 0);
break;
default:
error ("unnamed initializer for `%T', which uses multiple inheritance",
type);
current_class_type);
return NULL_TREE;
}
}
@ -1129,44 +970,54 @@ expand_member_init (exp, name, init)
}
else if (TREE_CODE (name) == TYPE_DECL)
basetype = TYPE_MAIN_VARIANT (TREE_TYPE (name));
else
basetype = NULL_TREE;
my_friendly_assert (init != NULL_TREE, 0);
if (init == void_type_node)
init = NULL_TREE;
if (basetype)
{
tree binfo;
if (current_template_parms)
;
else if (vec_binfo_member (basetype, TYPE_BINFO_BASETYPES (type)))
/* A direct base. */;
else if (binfo_for_vbase (basetype, type))
/* A virtual base. */;
else
return build_tree_list (basetype, init);
binfo = lookup_base (current_class_type, basetype,
ba_ignore, NULL);
if (binfo)
{
if (TYPE_USES_VIRTUAL_BASECLASSES (type))
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 (current_class_type))
error ("type `%D' is not a direct or virtual base of `%T'",
name, type);
name, current_class_type);
else
error ("type `%D' is not a direct base of `%T'",
name, type);
name, current_class_type);
return NULL_TREE;
}
init = build_tree_list (basetype, init);
if (binfo)
return build_tree_list (binfo, init);
}
else
{
field = lookup_field (type, name, 1, 0);
if (TREE_CODE (name) == IDENTIFIER_NODE)
field = lookup_field (current_class_type, name, 1, 0);
else
field = name;
if (! member_init_ok_or_else (field, type, name))
return NULL_TREE;
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

View File

@ -536,7 +536,6 @@ do_build_copy_constructor (fndecl)
int n_bases = CLASSTYPE_N_BASECLASSES (current_class_type);
tree binfos = TYPE_BINFO_BASETYPES (current_class_type);
tree member_init_list = NULL_TREE;
tree base_init_list = NULL_TREE;
int cvquals = cp_type_quals (TREE_TYPE (parm));
int i;
@ -550,10 +549,12 @@ do_build_copy_constructor (fndecl)
{
tree binfo = TREE_VALUE (t);
base_init_list = tree_cons (binfo,
build_base_path (PLUS_EXPR, parm,
binfo, 1),
base_init_list);
member_init_list
= tree_cons (binfo,
build_tree_list (NULL_TREE,
build_base_path (PLUS_EXPR, parm,
binfo, 1)),
member_init_list);
}
for (i = 0; i < n_bases; ++i)
@ -562,10 +563,12 @@ do_build_copy_constructor (fndecl)
if (TREE_VIA_VIRTUAL (binfo))
continue;
base_init_list = tree_cons (binfo,
build_base_path (PLUS_EXPR, parm,
binfo, 1),
base_init_list);
member_init_list
= tree_cons (binfo,
build_tree_list (NULL_TREE,
build_base_path (PLUS_EXPR, parm,
binfo, 1)),
member_init_list);
}
for (; fields; fields = TREE_CHAIN (fields))
@ -609,9 +612,7 @@ do_build_copy_constructor (fndecl)
member_init_list
= tree_cons (field, init, member_init_list);
}
member_init_list = nreverse (member_init_list);
base_init_list = nreverse (base_init_list);
emit_base_init (member_init_list, base_init_list);
finish_mem_initializers (member_init_list);
}
}

View File

@ -981,31 +981,27 @@ member_init:
{
if (current_class_name)
pedwarn ("anachronistic old style base class initializer");
$$ = expand_member_init (current_class_ref, NULL_TREE, $2);
$$ = expand_member_init (NULL_TREE, $2);
}
| LEFT_RIGHT
{
if (current_class_name)
pedwarn ("anachronistic old style base class initializer");
$$ = expand_member_init (current_class_ref,
NULL_TREE,
$$ = expand_member_init (NULL_TREE,
void_type_node);
}
| notype_identifier '(' nonnull_exprlist ')'
{ $$ = expand_member_init (current_class_ref, $1, $3); }
{ $$ = expand_member_init ($1, $3); }
| notype_identifier LEFT_RIGHT
{ $$ = expand_member_init (current_class_ref, $1,
void_type_node); }
{ $$ = expand_member_init ($1, void_type_node); }
| nonnested_type '(' nonnull_exprlist ')'
{ $$ = expand_member_init (current_class_ref, $1, $3); }
{ $$ = expand_member_init ($1, $3); }
| nonnested_type LEFT_RIGHT
{ $$ = expand_member_init (current_class_ref, $1,
void_type_node); }
{ $$ = expand_member_init ($1, void_type_node); }
| typename_sub '(' nonnull_exprlist ')'
{ $$ = expand_member_init (current_class_ref, $1, $3); }
{ $$ = expand_member_init ($1, $3); }
| typename_sub LEFT_RIGHT
{ $$ = expand_member_init (current_class_ref, $1,
void_type_node); }
{ $$ = expand_member_init ($1, void_type_node); }
| error
{ $$ = NULL_TREE; }
;

View File

@ -7369,18 +7369,10 @@ tsubst_expr (t, args, complain, in_decl)
break;
case CTOR_INITIALIZER:
{
tree member_init_list;
tree base_init_list;
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;
}
prep_stmt (t);
finish_mem_initializers (tsubst_initializer_list
(TREE_OPERAND (t, 0), args));
break;
case RETURN_STMT:
prep_stmt (t);
@ -10293,8 +10285,7 @@ static tree
tsubst_initializer_list (t, argvec)
tree t, argvec;
{
tree first = NULL_TREE;
tree *p = &first;
tree inits = NULL_TREE;
for (; t; t = TREE_CHAIN (t))
{
@ -10312,13 +10303,17 @@ tsubst_initializer_list (t, argvec)
else if (TREE_CODE (init) == TREE_LIST)
for (val = init; val; val = TREE_CHAIN (val))
TREE_VALUE (val) = convert_from_reference (TREE_VALUE (val));
else
else if (init != void_type_node)
init = convert_from_reference (init);
*p = build_tree_list (decl, init);
p = &TREE_CHAIN (*p);
init = expand_member_init (decl, init);
if (init)
{
TREE_CHAIN (init) = inits;
inits = init;
}
}
return first;
return inits;
}
/* Set CURRENT_ACCESS_SPECIFIER based on the protection of DECL. */

View File

@ -1094,67 +1094,21 @@ begin_mem_initializers ()
error ("only constructors take base initializers");
}
/* The INIT_LIST is a list of mem-initializers, in the order they were
written by the user. The TREE_VALUE of each node is a list of
initializers for a particular subobject. The TREE_PURPOSE is a
FIELD_DECL is the initializer is for a non-static data member, and
a class type if the initializer is for a base class. */
/* The MEM_INITS is a list of mem-initializers, in reverse of the
order they were written by the user. Each node is as for
emit_mem_initializers. */
void
finish_mem_initializers (init_list)
tree init_list;
finish_mem_initializers (tree mem_inits)
{
tree member_init_list;
tree base_init_list;
tree last_base_warned_about;
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;
}
}
/* Reorder the MEM_INITS so that they are in the order they appeared
in the source program. */
mem_inits = nreverse (mem_inits);
if (processing_template_decl)
add_stmt (build_min_nt (CTOR_INITIALIZER,
member_init_list, base_init_list));
add_stmt (build_min_nt (CTOR_INITIALIZER, mem_inits));
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. */

View File

@ -1,3 +1,11 @@
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>
* gcc.dg/20020919-1.c, gcc.dg/inline-2.c, gcc.dg/980211-1.c,

View File

@ -0,0 +1,7 @@
template <class T >
struct S
{
S() : S() {} // { dg-error "base" }
};
S<int> s; // { dg-error "instantiated" }

View File

@ -0,0 +1,14 @@
// { 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" }
};

View File

@ -7,6 +7,6 @@ public:
};
class D : public B {
int member;
int member; // WARNING - reordered
D() : member(0), B(member) { } // WARNING - reordered
};

View File

@ -1,4 +1,4 @@
# 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
# it under the terms of the GNU General Public License as published by
@ -19,7 +19,7 @@
proc prune_gcc_output { text } {
#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)collect2: ld returned \[^\n\]*" $text "" text
regsub -all "(^|\n)Please submit.*instructions\[^\n\]*" $text "" text