+1999-05-19 Jason Merrill <jason@yorick.cygnus.com>
+
+ Implement anonymous structs.
+ * cp-tree.h (ANON_AGGR_TYPE_P): Rename from ANON_UNION_TYPE_P.
+ * class.c, decl.c, decl2.c, init.c, pt.c, search.c, typeck.c: Adjust.
+ * class.c (finish_struct_1): Remove redundant check for anon struct.
+ * decl.c (fixup_anonymous_aggr): Renamed from fixup_anonymous_union.
+ (check_tag_decl): Check for anonymous struct here.
+ * decl2.c (build_anon_union_vars): Catch anon struct at file scope.
+ * init.c (sort_member_init, emit_base_init): Handle getting fields
+ as well as names in current_member_init_list.
+ (perform_member_init): Handle getting an anon aggr.
+ * method.c (do_build_assign_ref): Don't descend into anon aggrs.
+ (do_build_copy_constructor): Likewise.
+
1999-05-19 Mark Mitchell <mark@codesourcery.com>
* tree.c (cp_build_qualified_type): Don't allow qualified function
tree prev = 0;
if (DECL_NAME (field) == 0)
{
- if (TREE_CODE (TREE_TYPE (field)) != UNION_TYPE)
+ if (! ANON_AGGR_TYPE_P (TREE_TYPE (field)))
return fields;
for (x = TYPE_FIELDS (TREE_TYPE (field)); x; x = TREE_CHAIN (x))
{
if (DECL_NAME (x) == 0)
{
- if (TREE_CODE (TREE_TYPE (x)) != UNION_TYPE)
+ if (! ANON_AGGR_TYPE_P (TREE_TYPE (x)))
continue;
TYPE_FIELDS (TREE_TYPE (x))
= delete_duplicate_fields_1 (field, TYPE_FIELDS (TREE_TYPE (x)));
continue;
if (DECL_NAME (field) == NULL_TREE
- && TREE_CODE (TREE_TYPE (field)) == UNION_TYPE)
+ && ANON_AGGR_TYPE_P (TREE_TYPE (field)))
{
tree* uelt = &TYPE_FIELDS (TREE_TYPE (field));
for (; *uelt; uelt = &TREE_CHAIN (*uelt))
int has_pointers = 0;
tree inline_friends;
- if (warn_anon && code != UNION_TYPE && ANON_AGGRNAME_P (TYPE_IDENTIFIER (t)))
- pedwarn ("anonymous class type not used to declare any objects");
-
if (TYPE_SIZE (t))
{
if (IS_AGGR_TYPE (t))
unsigned const_needs_init : 1;
unsigned ref_needs_init : 1;
unsigned has_const_assign_ref : 1;
- unsigned anon_union : 1;
+ unsigned anon_aggr : 1;
unsigned has_nonpublic_ctor : 2;
unsigned has_nonpublic_assign_ref : 2;
Just used to communicate formatting information to dbxout.c. */
#define DECL_OPERATOR(NODE) (DECL_LANG_SPECIFIC(NODE)->decl_flags.operator_attr)
-#define ANON_UNION_P(NODE) (DECL_NAME (NODE) == 0)
-
-/* Nonzero if TYPE is an anonymous union type. We have to use a flag for
- this because "A union for which objects or pointers are declared is not
- an anonymous union" [class.union]. */
-#define ANON_UNION_TYPE_P(NODE) \
+/* Nonzero if TYPE is an anonymous union or struct type. We have to use a
+ flag for this because "A union for which objects or pointers are
+ declared is not an anonymous union" [class.union]. */
+#define ANON_AGGR_TYPE_P(NODE) \
(TYPE_LANG_SPECIFIC (NODE) \
- && TYPE_LANG_SPECIFIC (NODE)->type_flags.anon_union)
-#define SET_ANON_UNION_TYPE_P(NODE) \
- (TYPE_LANG_SPECIFIC (NODE)->type_flags.anon_union = 1)
+ && TYPE_LANG_SPECIFIC (NODE)->type_flags.anon_aggr)
+#define SET_ANON_AGGR_TYPE_P(NODE) \
+ (TYPE_LANG_SPECIFIC (NODE)->type_flags.anon_aggr = 1)
#define UNKNOWN_TYPE LANG_TYPE
extern void replace_defarg PROTO((tree, tree));
extern void print_other_binding_stack PROTO((struct binding_level *));
extern void revert_static_member_fn PROTO((tree*, tree*, tree*));
-extern void fixup_anonymous_union PROTO((tree));
+extern void fixup_anonymous_aggr PROTO((tree));
extern int check_static_variable_definition PROTO((tree, tree));
extern void push_local_binding PROTO((tree, tree, int));
extern int push_class_binding PROTO((tree, tree));
if (TREE_CODE (x) == TYPE_DECL)
set_identifier_type_value (name, TREE_TYPE (x));
}
- else if (ANON_UNION_TYPE_P (TREE_TYPE (x)))
+ else if (ANON_AGGR_TYPE_P (TREE_TYPE (x)))
{
tree f;
union type.) */
void
-fixup_anonymous_union (t)
+fixup_anonymous_aggr (t)
tree t;
{
tree *q;
/* Check for an anonymous union. We're careful
accessing TYPE_IDENTIFIER because some built-in types, like
pointer-to-member types, do not have TYPE_NAME. */
- else if (t && TREE_CODE (t) == UNION_TYPE
+ else if (t && IS_AGGR_TYPE_CODE (TREE_CODE (t))
&& TYPE_NAME (t)
&& ANON_AGGRNAME_P (TYPE_IDENTIFIER (t)))
{
/* Anonymous unions are objects, so they can have specifiers. */;
- SET_ANON_UNION_TYPE_P (t);
+ SET_ANON_AGGR_TYPE_P (t);
+
+ if (TREE_CODE (t) != UNION_TYPE && pedantic && ! in_system_header)
+ pedwarn ("ISO C++ prohibits anonymous structs");
}
else if (ob_modifier)
union { ... } ;
because there is no declarator after the union, the parser
sends that declaration here. */
- if (t && ANON_UNION_TYPE_P (t))
+ if (t && ANON_AGGR_TYPE_P (t))
{
- fixup_anonymous_union (t);
+ fixup_anonymous_aggr (t);
if (TYPE_FIELDS (t))
{
/* Static anonymous unions are dealt with here. */
if (staticp && decl_context == TYPENAME
&& TREE_CODE (declspecs) == TREE_LIST
- && ANON_UNION_TYPE_P (TREE_VALUE (declspecs)))
+ && ANON_AGGR_TYPE_P (TREE_VALUE (declspecs)))
decl_context = FIELD;
/* Give error if `const,' `volatile,' `inline,' `friend,' or `virtual'
/* The only case where we need to do anything additional here is an
anonymous union field, e.g.: `struct S { union { int i; }; };'. */
- if (t == NULL_TREE || !ANON_UNION_TYPE_P (t))
+ if (t == NULL_TREE || !ANON_AGGR_TYPE_P (t))
return;
- fixup_anonymous_union (t);
+ fixup_anonymous_aggr (t);
finish_member_declaration (build_lang_field_decl (FIELD_DECL,
NULL_TREE,
t));
tree main_decl = NULL_TREE;
tree field;
+ /* Rather than write the code to handle the non-union case,
+ just give an error. */
+ if (TREE_CODE (type) != UNION_TYPE)
+ error ("anonymous struct not inside named type");
+
for (field = TYPE_FIELDS (type);
field != NULL_TREE;
field = TREE_CHAIN (field))
cp_pedwarn_at ("protected member `%#D' in anonymous union", field);
if (DECL_NAME (field) == NULL_TREE
- && TREE_CODE (TREE_TYPE (field)) == UNION_TYPE)
+ && ANON_AGGR_TYPE_P (TREE_TYPE (field)))
{
decl = build_anon_union_vars (field, elems, static_p, external_p);
if (!decl)
TREE_ASM_WRITTEN (decl) = 1;
if (DECL_NAME (field) == NULL_TREE
- && TREE_CODE (TREE_TYPE (field)) == UNION_TYPE)
+ && ANON_AGGR_TYPE_P (TREE_TYPE (field)))
/* The remainder of the processing was already done in the
recursive call. */
continue;
expand_start_target_temps ();
- if (TYPE_NEEDS_CONSTRUCTING (type)
- || (init && TYPE_HAS_CONSTRUCTOR (type)))
+ decl = build_component_ref (current_class_ref, name, NULL_TREE, explicit);
+
+ /* Deal with this here, as we will get confused if we try to call the
+ assignment op for an anonymous union. This can happen in a
+ synthesized copy constructor. */
+ if (ANON_AGGR_TYPE_P (type))
+ {
+ init = build (INIT_EXPR, type, decl, TREE_VALUE (init));
+ TREE_SIDE_EFFECTS (init) = 1;
+ expand_expr_stmt (init);
+ }
+ else if (TYPE_NEEDS_CONSTRUCTING (type)
+ || (init && TYPE_HAS_CONSTRUCTOR (type)))
{
/* Since `init' is already a TREE_LIST on the current_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_expr_list (NULL_TREE, init);
- decl = build_component_ref (current_class_ref, name, NULL_TREE, explicit);
-
if (explicit
&& TREE_CODE (type) == ARRAY_TYPE
&& init != NULL_TREE
/* default-initialization. */
if (AGGREGATE_TYPE_P (type))
init = build (CONSTRUCTOR, type, NULL_TREE, NULL_TREE);
- else if (TREE_CODE (type) == REFERENCE_TYPE)
+ else if (TREE_CODE (type) == REFERENCE_TYPE)
{
cp_error ("default-initialization of `%#D', which has reference type",
member);
current_member_init_list. */
if (init || explicit)
{
- decl = build_component_ref (current_class_ref, name, NULL_TREE,
- explicit);
expand_expr_stmt (build_modify_expr (decl, INIT_EXPR, init));
}
}
continue;
name = TREE_PURPOSE (x);
-#if 0
- /* This happens in templates, since the IDENTIFIER is replaced
- with the COMPONENT_REF in tsubst_expr. */
- field = (TREE_CODE (name) == COMPONENT_REF
- ? TREE_OPERAND (name, 1) : IDENTIFIER_CLASS_VALUE (name));
-#else
- /* Let's find out when this happens. */
- my_friendly_assert (TREE_CODE (name) != COMPONENT_REF, 348);
- field = IDENTIFIER_CLASS_VALUE (name);
-#endif
+ if (TREE_CODE (name) == IDENTIFIER_NODE)
+ field = IDENTIFIER_CLASS_VALUE (name);
+ 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)
init = TREE_VALUE (mem_init_list);
from_init_list = 1;
-#if 0
- if (TREE_CODE (name) == COMPONENT_REF)
- name = DECL_NAME (TREE_OPERAND (name, 1));
-#else
- /* Also see if it's ever a COMPONENT_REF here. If it is, we
- need to do `expand_assignment (name, init, 0, 0);' and
- a continue. */
- my_friendly_assert (TREE_CODE (name) != COMPONENT_REF, 349);
-#endif
+ my_friendly_assert (TREE_CODE (name) == IDENTIFIER_NODE
+ || TREE_CODE (name) == FIELD_DECL, 349);
}
else
{
{
name = TREE_PURPOSE (mem_init_list);
init = TREE_VALUE (mem_init_list);
- /* XXX: this may need the COMPONENT_REF operand 0 check if
- it turns out we actually get them. */
- field = IDENTIFIER_CLASS_VALUE (name);
+
+ 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)
/* Anonymous union members can be initialized in the first enclosing
non-anonymous union context. */
- while (t && ANON_UNION_TYPE_P (t))
+ while (t && ANON_AGGR_TYPE_P (t))
t = TYPE_CONTEXT (t);
return t;
}
continue;
}
else if ((t = TREE_TYPE (field)) != NULL_TREE
- && ANON_UNION_TYPE_P (t)
+ && ANON_AGGR_TYPE_P (t)
&& TYPE_FIELDS (t) != NULL_TREE)
- {
- do
- {
- init = build (COMPONENT_REF, t, init, field);
- field = largest_union_member (t);
- }
- while ((t = TREE_TYPE (field)) != NULL_TREE
- && ANON_UNION_TYPE_P (t)
- && TYPE_FIELDS (t) != NULL_TREE);
- }
+ /* Just use the field; anonymous types can't have
+ nontrivial copy ctors or assignment ops. */;
else
continue;
init = build_tree_list (NULL_TREE, init);
current_member_init_list
- = tree_cons (DECL_NAME (field), init, current_member_init_list);
+ = tree_cons (field, init, current_member_init_list);
}
current_member_init_list = nreverse (current_member_init_list);
current_base_init_list = nreverse (current_base_init_list);
continue;
}
else if ((t = TREE_TYPE (field)) != NULL_TREE
- && ANON_UNION_TYPE_P (t)
+ && ANON_AGGR_TYPE_P (t)
&& TYPE_FIELDS (t) != NULL_TREE)
- {
- do
- {
- comp = build (COMPONENT_REF, t, comp, field);
- init = build (COMPONENT_REF, t, init, field);
- field = largest_union_member (t);
- }
- while ((t = TREE_TYPE (field)) != NULL_TREE
- && ANON_UNION_TYPE_P (t)
- && TYPE_FIELDS (t) != NULL_TREE);
- }
+ /* Just use the field; anonymous types can't have
+ nontrivial copy ctors or assignment ops. */;
else
continue;
TYPE_PACKED (type) = TYPE_PACKED (pattern);
TYPE_ALIGN (type) = TYPE_ALIGN (pattern);
TYPE_FOR_JAVA (type) = TYPE_FOR_JAVA (pattern); /* For libjava's JArray<T> */
- if (ANON_UNION_TYPE_P (pattern))
- SET_ANON_UNION_TYPE_P (type);
+ if (ANON_AGGR_TYPE_P (pattern))
+ SET_ANON_AGGR_TYPE_P (type);
/* We must copy the arguments to the permanent obstack since
during the tsubst'ing below they may wind up in the
#endif /* GATHER_STATISTICS */
my_friendly_assert (TREE_CODE_CLASS (TREE_CODE (field)) == 'd', 0);
if (DECL_NAME (field) == NULL_TREE
- && TREE_CODE (TREE_TYPE (field)) == UNION_TYPE)
+ && ANON_AGGR_TYPE_P (TREE_TYPE (field)))
{
tree temp = lookup_field_1 (TREE_TYPE (field), name);
if (temp)
declared. */
tree context = DECL_REAL_CONTEXT (decl);
- while (TYPE_P (context) && ANON_UNION_TYPE_P (context))
+ while (TYPE_P (context) && ANON_AGGR_TYPE_P (context))
context = TYPE_CONTEXT (context);
if (!context)
context = global_namespace;
&& TREE_CODE (fields) != USING_DECL)
setup_class_bindings (DECL_NAME (fields), /*type_binding_p=*/0);
else if (TREE_CODE (fields) == FIELD_DECL
- && ANON_UNION_TYPE_P (TREE_TYPE (fields)))
+ && ANON_AGGR_TYPE_P (TREE_TYPE (fields)))
dfs_push_decls (TYPE_BINFO (TREE_TYPE (fields)), data);
method_vec = (CLASS_TYPE_P (type)
TREE_USED (fields) = 0;
if (DECL_NAME (fields) == NULL_TREE
- && TREE_CODE (TREE_TYPE (fields)) == UNION_TYPE)
+ && ANON_AGGR_TYPE_P (TREE_TYPE (fields)))
unuse_fields (TREE_TYPE (fields));
}
/* Otherwise, it could be nested, search harder. */
if (DECL_NAME (field) == NULL_TREE
- && TREE_CODE (TREE_TYPE (field)) == UNION_TYPE)
+ && ANON_AGGR_TYPE_P (TREE_TYPE (field)))
{
tree subfield = lookup_anon_field (TREE_TYPE (field), type);
if (subfield)
tree context = DECL_FIELD_CONTEXT (field);
tree base = context;
while (!same_type_p (base, basetype) && TYPE_NAME (base)
- && ANON_UNION_TYPE_P (base))
+ && ANON_AGGR_TYPE_P (base))
{
base = TYPE_CONTEXT (base);
}
basetype = base;
/* Handle things from anon unions here... */
- if (TYPE_NAME (context) && ANON_UNION_TYPE_P (context))
+ if (TYPE_NAME (context) && ANON_AGGR_TYPE_P (context))
{
tree subfield = lookup_anon_field (basetype, context);
tree subdatum = build_component_ref (datum, subfield,