decl2.c (finish_anon_union): Generalize error messages to handle anonymous structures.

* decl2.c (finish_anon_union): Generalize error messages to handle
	anonymous structures.
	* init.c (perform_member_init): Remove `name' parameter.
	(build_field_list): New function.
	(sort_member_init): Handle anonymous union initialization order
	correctly.  Check for multiple initializations of the same union.
	(emit_base_init): Don't look up fields by name here.
	(expand_member_init): Record the result of name lookup for future
	reference.
	* typeck.c (build_component_ref): Fix formatting.

From-SVN: r33963
This commit is contained in:
Mark Mitchell 2000-05-17 18:46:32 +00:00 committed by Mark Mitchell
parent 2c0b35cb89
commit ff9f1a5d55
6 changed files with 261 additions and 120 deletions

View File

@ -1,3 +1,16 @@
2000-05-17 Mark Mitchell <mark@codesourcery.com>
* decl2.c (finish_anon_union): Generalize error messages to handle
anonymous structures.
* init.c (perform_member_init): Remove `name' parameter.
(build_field_list): New function.
(sort_member_init): Handle anonymous union initialization order
correctly. Check for multiple initializations of the same union.
(emit_base_init): Don't look up fields by name here.
(expand_member_init): Record the result of name lookup for future
reference.
* typeck.c (build_component_ref): Fix formatting.
Wed May 17 17:27:44 2000 Andrew Cagney <cagney@b1.cygnus.com> Wed May 17 17:27:44 2000 Andrew Cagney <cagney@b1.cygnus.com>
* decl.c (pop_label): Replace warn_unused with warn_unused_label. * decl.c (pop_label): Replace warn_unused with warn_unused_label.

View File

@ -2172,7 +2172,7 @@ finish_anon_union (anon_union_decl)
if (public_p) if (public_p)
{ {
error ("global anonymous unions must be declared static"); error ("namespace-scope anonymous aggregates must be static");
return; return;
} }
@ -2182,7 +2182,7 @@ finish_anon_union (anon_union_decl)
if (main_decl == NULL_TREE) if (main_decl == NULL_TREE)
{ {
warning ("anonymous union with no members"); warning ("anonymous aggregate with no members");
return; return;
} }

View File

@ -39,7 +39,7 @@ 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, tree, int)); static tree build_vec_delete_1 PARAMS ((tree, tree, tree, tree, int));
static void perform_member_init PARAMS ((tree, tree, tree, int)); static void perform_member_init PARAMS ((tree, tree, int));
static void sort_base_init PARAMS ((tree, tree *, tree *)); static void sort_base_init PARAMS ((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, const char *)); static int member_init_ok_or_else PARAMS ((tree, tree, const char *));
@ -52,6 +52,7 @@ static tree dfs_initialize_vtbl_ptrs PARAMS ((tree, void *));
static tree build_new_1 PARAMS ((tree)); static tree build_new_1 PARAMS ((tree));
static tree get_cookie_size PARAMS ((tree)); static tree get_cookie_size PARAMS ((tree));
static tree build_dtor_call PARAMS ((tree, tree, int)); static tree build_dtor_call PARAMS ((tree, tree, int));
static tree build_field_list PARAMS ((tree, tree, int *));
/* Set up local variable for this file. MUST BE CALLED AFTER /* Set up local variable for this file. MUST BE CALLED AFTER
INIT_DECL_PROCESSING. */ INIT_DECL_PROCESSING. */
@ -175,14 +176,14 @@ initialize_vtbl_ptrs (type, addr)
/* Subroutine of emit_base_init. */ /* Subroutine of emit_base_init. */
static void static void
perform_member_init (member, name, init, explicit) perform_member_init (member, init, explicit)
tree member, name, init; tree member, init;
int explicit; int explicit;
{ {
tree decl; tree decl;
tree type = TREE_TYPE (member); tree type = TREE_TYPE (member);
decl = build_component_ref (current_class_ref, name, NULL_TREE, explicit); decl = build_component_ref (current_class_ref, member, NULL_TREE, explicit);
if (decl == error_mark_node) if (decl == error_mark_node)
return; return;
@ -191,10 +192,13 @@ perform_member_init (member, name, init, explicit)
assignment op for an anonymous union. This can happen in a assignment op for an anonymous union. This can happen in a
synthesized copy constructor. */ synthesized copy constructor. */
if (ANON_AGGR_TYPE_P (type)) if (ANON_AGGR_TYPE_P (type))
{
if (init)
{ {
init = build (INIT_EXPR, type, decl, TREE_VALUE (init)); init = build (INIT_EXPR, type, decl, TREE_VALUE (init));
finish_expr_stmt (init); finish_expr_stmt (init);
} }
}
else if (TYPE_NEEDS_CONSTRUCTING (type) else if (TYPE_NEEDS_CONSTRUCTING (type)
|| (init && TYPE_HAS_CONSTRUCTOR (type))) || (init && TYPE_HAS_CONSTRUCTOR (type)))
{ {
@ -268,7 +272,7 @@ perform_member_init (member, name, init, explicit)
{ {
tree expr; tree expr;
expr = build_component_ref (current_class_ref, name, NULL_TREE, expr = build_component_ref (current_class_ref, member, NULL_TREE,
explicit); explicit);
expr = build_delete (type, expr, integer_zero_node, expr = build_delete (type, expr, integer_zero_node,
LOOKUP_NONVIRTUAL|LOOKUP_DESTRUCTOR, 0); LOOKUP_NONVIRTUAL|LOOKUP_DESTRUCTOR, 0);
@ -278,91 +282,198 @@ perform_member_init (member, name, init, explicit)
} }
} }
/* Returns a TREE_LIST containing (as the TREE_PURPOSE of each node) all
the FIELD_DECLs on the TYPE_FIELDS list for T, in reverse order. */
static tree
build_field_list (t, list, uses_unions_p)
tree t;
tree list;
int *uses_unions_p;
{
tree fields;
/* Note whether or not T is a union. */
if (TREE_CODE (t) == UNION_TYPE)
*uses_unions_p = 1;
for (fields = TYPE_FIELDS (t); fields; fields = TREE_CHAIN (fields))
{
/* Skip CONST_DECLs for enumeration constants and so forth. */
if (TREE_CODE (fields) != FIELD_DECL)
continue;
/* Keep track of whether or not any fields are unions. */
if (TREE_CODE (TREE_TYPE (fields)) == UNION_TYPE)
*uses_unions_p = 1;
/* For an anonymous struct or union, we must recursively
consider the fields of the anonymous type. They can be
directly initialized from the constructor. */
if (ANON_AGGR_TYPE_P (TREE_TYPE (fields)))
{
/* Add this field itself. Synthesized copy constructors
initialize the entire aggregate. */
list = tree_cons (fields, NULL_TREE, list);
/* And now add the fields in the anonymous aggregate. */
list = build_field_list (TREE_TYPE (fields), list,
uses_unions_p);
}
/* Add this field. */
else if (DECL_NAME (fields))
list = tree_cons (fields, NULL_TREE, list);
}
return list;
}
/* Subroutine of emit_member_init. */ /* Subroutine of emit_member_init. */
static tree static tree
sort_member_init (t) sort_member_init (t)
tree t; tree t;
{ {
tree x, member, name, field; tree init_list;
tree init_list = NULL_TREE; tree last_field;
int last_pos = 0; tree init;
tree last_field = NULL_TREE; int uses_unions_p;
for (member = TYPE_FIELDS (t); member ; member = TREE_CHAIN (member)) /* 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 = current_member_init_list; init; init = TREE_CHAIN (init))
{ {
int pos; tree f;
tree initialized_field;
/* member could be, for example, a CONST_DECL for an enumerated initialized_field = TREE_PURPOSE (init);
tag; we don't want to try to initialize that, since it already my_friendly_assert (TREE_CODE (initialized_field) == FIELD_DECL,
has a value. */ 20000516);
if (TREE_CODE (member) != FIELD_DECL || !DECL_NAME (member))
continue;
for (x = current_member_init_list, pos = 0; x; x = TREE_CHAIN (x), ++pos) /* If the explicit initializers are in sorted order, then the
{ INITIALIZED_FIELD will be for a field following the
/* If we cleared this out, then pay no attention to it. */ LAST_FIELD. */
if (TREE_PURPOSE (x) == NULL_TREE) for (f = last_field; f; f = TREE_CHAIN (f))
continue; if (TREE_PURPOSE (f) == initialized_field)
name = TREE_PURPOSE (x); break;
if (TREE_CODE (name) == IDENTIFIER_NODE) /* Give a warning, if appropriate. */
field = IDENTIFIER_CLASS_VALUE (name); if (warn_reorder && !f)
else
{
my_friendly_assert (TREE_CODE (name) == FIELD_DECL, 348);
field = name;
}
/* If one member shadows another, get the outermost one. */
if (TREE_CODE (field) == TREE_LIST)
field = TREE_VALUE (field);
if (field == member)
{
if (warn_reorder)
{
if (pos < last_pos)
{ {
cp_warning_at ("member initializers for `%#D'", last_field); cp_warning_at ("member initializers for `%#D'", last_field);
cp_warning_at (" and `%#D'", field); cp_warning_at (" and `%#D'", initialized_field);
warning (" will be re-ordered to match declaration order"); warning (" will be re-ordered to match declaration order");
} }
last_pos = pos;
last_field = field; /* Look again, from the beginning of the list. We must find the
field on this loop. */
if (!f)
{
f = init_list;
while (TREE_PURPOSE (f) != initialized_field)
f = TREE_CHAIN (f);
} }
/* Make sure we won't try to work on this init again. */ /* If there was already an explicit initializer for this field,
TREE_PURPOSE (x) = NULL_TREE; issue an error. */
x = build_tree_list (name, TREE_VALUE (x)); if (TREE_TYPE (f))
goto got_it;
}
}
/* If we didn't find MEMBER in the list, create a dummy entry
so the two lists (INIT_LIST and the list of members) will be
symmetrical. */
x = build_tree_list (NULL_TREE, NULL_TREE);
got_it:
init_list = chainon (init_list, x);
}
/* Initializers for base members go at the end. */
for (x = current_member_init_list ; x ; x = TREE_CHAIN (x))
{
name = TREE_PURPOSE (x);
if (name)
{
if (purpose_member (name, init_list))
{
cp_error ("multiple initializations given for member `%D'", cp_error ("multiple initializations given for member `%D'",
IDENTIFIER_CLASS_VALUE (name)); 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;
}
/* [class.base.init]
If a ctor-initializer specifies more than one mem-initializer for
multiple members of the same union (including members of
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 field;
tree field_type;
int done;
/* Skip uninitialized members. */
if (!TREE_TYPE (init))
continue;
/* See if this field is a member of a union, or a member of a
structure contained in a union, etc. */
field = TREE_PURPOSE (init);
for (field_type = DECL_CONTEXT (field);
!same_type_p (field_type, t);
field_type = TYPE_CONTEXT (field_type))
if (TREE_CODE (field_type) == UNION_TYPE)
break;
/* If this field is not a member of a union, skip it. */
if (TREE_CODE (field_type) != UNION_TYPE)
continue;
/* It's only an error if we have two initializers for the same
union type. */
if (!last_field)
{
last_field = field;
continue; continue;
} }
init_list = chainon (init_list, /* See if LAST_FIELD and the field initialized by INIT are
build_tree_list (name, TREE_VALUE (x))); members of the same union. If so, there's a problem,
TREE_PURPOSE (x) = NULL_TREE; unless they're actually members of the same structure
which is itself a member of a union. For example, given:
union { struct { int i; int j; }; };
initializing both `i' and `j' makes sense. */
field_type = DECL_CONTEXT (field);
done = 0;
do
{
tree last_field_type;
last_field_type = DECL_CONTEXT (last_field);
while (1)
{
if (same_type_p (last_field_type, field_type))
{
if (TREE_CODE (field_type) == UNION_TYPE)
cp_error ("initializations for multiple members of `%T'",
last_field_type);
done = 1;
break;
}
if (same_type_p (last_field_type, t))
break;
last_field_type = TYPE_CONTEXT (last_field_type);
}
/* If we've reached the outermost class, then we're
done. */
if (same_type_p (field_type, t))
break;
field_type = TYPE_CONTEXT (field_type);
}
while (!done);
last_field = field;
} }
} }
@ -586,32 +697,23 @@ emit_base_init (t)
/* Initialize the vtable pointers for the class. */ /* Initialize the vtable pointers for the class. */
initialize_vtbl_ptrs (t, current_class_ptr); initialize_vtbl_ptrs (t, current_class_ptr);
for (member = TYPE_FIELDS (t); member; member = TREE_CHAIN (member)) while (mem_init_list)
{ {
tree init, name; tree init;
tree member;
int from_init_list; int from_init_list;
/* member could be, for example, a CONST_DECL for an enumerated member = TREE_PURPOSE (mem_init_list);
tag; we don't want to try to initialize that, since it already
has a value. */
if (TREE_CODE (member) != FIELD_DECL || !DECL_NAME (member))
continue;
/* See if we had a user-specified member initialization. */ /* See if we had a user-specified member initialization. */
if (TREE_PURPOSE (mem_init_list)) if (TREE_TYPE (mem_init_list))
{ {
name = TREE_PURPOSE (mem_init_list);
init = TREE_VALUE (mem_init_list); init = TREE_VALUE (mem_init_list);
from_init_list = 1; from_init_list = 1;
my_friendly_assert (TREE_CODE (name) == IDENTIFIER_NODE
|| TREE_CODE (name) == FIELD_DECL, 349);
} }
else else
{ {
name = DECL_NAME (member);
init = DECL_INITIAL (member); init = DECL_INITIAL (member);
from_init_list = 0; from_init_list = 0;
/* Effective C++ rule 12. */ /* Effective C++ rule 12. */
@ -621,35 +723,7 @@ emit_base_init (t)
cp_warning ("`%D' should be initialized in the member initialization list", member); cp_warning ("`%D' should be initialized in the member initialization list", member);
} }
perform_member_init (member, name, init, from_init_list); perform_member_init (member, init, from_init_list);
mem_init_list = TREE_CHAIN (mem_init_list);
}
/* Now initialize any members from our bases. */
while (mem_init_list)
{
tree name, init, field;
if (TREE_PURPOSE (mem_init_list))
{
name = TREE_PURPOSE (mem_init_list);
init = TREE_VALUE (mem_init_list);
if (TREE_CODE (name) == IDENTIFIER_NODE)
field = IDENTIFIER_CLASS_VALUE (name);
else
field = name;
/* If one member shadows another, get the outermost one. */
if (TREE_CODE (field) == TREE_LIST)
{
field = TREE_VALUE (field);
if (decl_type_context (field) != current_class_type)
cp_error ("field `%D' not in immediate context", field);
}
perform_member_init (field, name, init, 1);
}
mem_init_list = TREE_CHAIN (mem_init_list); mem_init_list = TREE_CHAIN (mem_init_list);
} }
} }
@ -992,7 +1066,7 @@ expand_member_init (exp, name, init)
return; return;
} }
member_init = build_tree_list (name, init); member_init = build_tree_list (field, init);
current_member_init_list = chainon (current_member_init_list, member_init); current_member_init_list = chainon (current_member_init_list, member_init);
} }
} }

View File

@ -2189,9 +2189,7 @@ build_component_ref (datum, component, basetype_path, protect)
tree base = context; tree base = context;
while (!same_type_p (base, basetype) && TYPE_NAME (base) while (!same_type_p (base, basetype) && TYPE_NAME (base)
&& ANON_AGGR_TYPE_P (base)) && ANON_AGGR_TYPE_P (base))
{
base = TYPE_CONTEXT (base); base = TYPE_CONTEXT (base);
}
/* Handle base classes here... */ /* Handle base classes here... */
if (base != basetype && TYPE_BASE_CONVS_MAY_REQUIRE_CODE_P (basetype)) if (base != basetype && TYPE_BASE_CONVS_MAY_REQUIRE_CODE_P (basetype))

View File

@ -0,0 +1,23 @@
// Origin: Mark Mitchell <mark@codesourcery.com>
struct A
{
union
{
int i;
};
int j;
A ();
};
A::A ()
: i (1), j (i = 0)
{
}
int main ()
{
A a;
return a.i;
}

View File

@ -0,0 +1,33 @@
// Build don't link:
// Origin: Mark Mitchell <mark@codesourcery.com>
// Special g++ Options:
union A
{
int i;
int j;
A () : i (3), j (2) {} // ERROR - multiple initializations
};
union B
{
int i;
union {
int j;
};
B () : i (3), j (2) {} // ERROR - multiple initializations
};
union C
{
union {
struct {
int i;
int j;
};
};
C () : i (3), j (2) {}
};