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:
parent
854ef3909d
commit
2282d28d48
13 changed files with 354 additions and 502 deletions
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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));
|
||||
|
|
649
gcc/cp/init.c
649
gcc/cp/init.c
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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; }
|
||||
;
|
||||
|
|
31
gcc/cp/pt.c
31
gcc/cp/pt.c
|
@ -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. */
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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,
|
||||
|
|
7
gcc/testsuite/g++.dg/template/meminit1.C
Normal file
7
gcc/testsuite/g++.dg/template/meminit1.C
Normal file
|
@ -0,0 +1,7 @@
|
|||
template <class T >
|
||||
struct S
|
||||
{
|
||||
S() : S() {} // { dg-error "base" }
|
||||
};
|
||||
|
||||
S<int> s; // { dg-error "instantiated" }
|
14
gcc/testsuite/g++.dg/warn/Wreorder-1.C
Normal file
14
gcc/testsuite/g++.dg/warn/Wreorder-1.C
Normal 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" }
|
||||
};
|
|
@ -7,6 +7,6 @@ public:
|
|||
};
|
||||
|
||||
class D : public B {
|
||||
int member;
|
||||
int member; // WARNING - reordered
|
||||
D() : member(0), B(member) { } // WARNING - reordered
|
||||
};
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Reference in a new issue