Commit 0ca7178c by Jason Merrill Committed by Jason Merrill

Handle anonymous unions at the tree level.

        C++ ABI change: Mangle anonymous unions using the name of their
        first named field (by depth-first search).  Should not cause
        binary compatibility problems, though, as the compiler previously
        didn't emit anything for affected unions.
        * cp-tree.def (ALIAS_DECL): New tree code.
        * decl2.c (build_anon_union_vars): Build ALIAS_DECLs.  Return the
        first field, not the largest.
        (finish_anon_union): Don't mess with RTL.  Do set DECL_ASSEMBLER_NAME,
        push the decl, and write it out at namespace scope.
        * decl.c (lookup_name_real): See through an ALIAS_DECL.
        (pushdecl): Add namespace bindings for ALIAS_DECLs.
        * rtti.c (unemitted_tinfo_decl_p): Don't try to look at the name
        of a decl which doesn't have one.
        * typeck.c (build_class_member_access_expr): Don't recurse if
        we already have the type we want.

From-SVN: r60314
parent e54b4cae
2002-12-18 Jason Merrill <jason@redhat.com>
Handle anonymous unions at the tree level.
C++ ABI change: Mangle anonymous unions using the name of their
first named field (by depth-first search). Should not cause
binary compatibility problems, though, as the compiler previously
didn't emit anything for affected unions.
* cp-tree.def (ALIAS_DECL): New tree code.
* decl2.c (build_anon_union_vars): Build ALIAS_DECLs. Return the
first field, not the largest.
(finish_anon_union): Don't mess with RTL. Do set DECL_ASSEMBLER_NAME,
push the decl, and write it out at namespace scope.
* decl.c (lookup_name_real): See through an ALIAS_DECL.
(pushdecl): Add namespace bindings for ALIAS_DECLs.
* rtti.c (unemitted_tinfo_decl_p): Don't try to look at the name
of a decl which doesn't have one.
* typeck.c (build_class_member_access_expr): Don't recurse if
we already have the type we want.
2002-12-18 Kriang Lerdsuwanakij <lerdsuwa@users.sourceforge.net> 2002-12-18 Kriang Lerdsuwanakij <lerdsuwa@users.sourceforge.net>
PR c++/8099 PR c++/8099
......
...@@ -89,6 +89,10 @@ DEFTREECODE (THROW_EXPR, "throw_expr", 'e', 1) ...@@ -89,6 +89,10 @@ DEFTREECODE (THROW_EXPR, "throw_expr", 'e', 1)
these to avoid actually creating instances of the empty classes. */ these to avoid actually creating instances of the empty classes. */
DEFTREECODE (EMPTY_CLASS_EXPR, "empty_class_expr", 'e', 0) DEFTREECODE (EMPTY_CLASS_EXPR, "empty_class_expr", 'e', 0)
/* A DECL which is really just a placeholder for an expression. Used to
implement non-class scope anonymous unions. */
DEFTREECODE (ALIAS_DECL, "alias_decl", 'd', 0)
/* A reference to a member function or member functions from a base /* A reference to a member function or member functions from a base
class. BASELINK_FUNCTIONS gives the FUNCTION_DECL, class. BASELINK_FUNCTIONS gives the FUNCTION_DECL,
TEMPLATE_DECL, OVERLOAD, or TEMPLATE_ID_EXPR corresponding to the TEMPLATE_DECL, OVERLOAD, or TEMPLATE_ID_EXPR corresponding to the
......
...@@ -4051,6 +4051,7 @@ pushdecl (x) ...@@ -4051,6 +4051,7 @@ pushdecl (x)
&& t != NULL_TREE) && t != NULL_TREE)
&& (TREE_CODE (x) == TYPE_DECL && (TREE_CODE (x) == TYPE_DECL
|| TREE_CODE (x) == VAR_DECL || TREE_CODE (x) == VAR_DECL
|| TREE_CODE (x) == ALIAS_DECL
|| TREE_CODE (x) == NAMESPACE_DECL || TREE_CODE (x) == NAMESPACE_DECL
|| TREE_CODE (x) == CONST_DECL || TREE_CODE (x) == CONST_DECL
|| TREE_CODE (x) == TEMPLATE_DECL)) || TREE_CODE (x) == TEMPLATE_DECL))
...@@ -6228,6 +6229,9 @@ does not match lookup in the current scope (`%#D')", ...@@ -6228,6 +6229,9 @@ does not match lookup in the current scope (`%#D')",
else if (from_obj) else if (from_obj)
val = from_obj; val = from_obj;
if (val && TREE_CODE (val) == ALIAS_DECL)
val = DECL_INITIAL (val);
return val; return val;
} }
......
...@@ -66,7 +66,7 @@ static int maybe_emit_vtables (tree); ...@@ -66,7 +66,7 @@ static int maybe_emit_vtables (tree);
static int is_namespace_ancestor PARAMS ((tree, tree)); static int is_namespace_ancestor PARAMS ((tree, tree));
static void add_using_namespace PARAMS ((tree, tree, int)); static void add_using_namespace PARAMS ((tree, tree, int));
static tree ambiguous_decl PARAMS ((tree, tree, tree,int)); static tree ambiguous_decl PARAMS ((tree, tree, tree,int));
static tree build_anon_union_vars PARAMS ((tree, tree*, int, int)); static tree build_anon_union_vars PARAMS ((tree));
static int acceptable_java_type PARAMS ((tree)); static int acceptable_java_type PARAMS ((tree));
static void output_vtable_inherit PARAMS ((tree)); static void output_vtable_inherit PARAMS ((tree));
static tree start_objects PARAMS ((int, int)); static tree start_objects PARAMS ((int, int));
...@@ -1269,22 +1269,15 @@ defer_fn (fn) ...@@ -1269,22 +1269,15 @@ defer_fn (fn)
VARRAY_PUSH_TREE (deferred_fns, fn); VARRAY_PUSH_TREE (deferred_fns, fn);
} }
/* Hunts through the global anonymous union ANON_DECL, building /* Walks through the namespace- or function-scope anonymous union OBJECT,
appropriate VAR_DECLs. Stores cleanups on the list of ELEMS, and building appropriate ALIAS_DECLs. Returns one of the fields for use in
returns a VAR_DECL whose size is the same as the size of the the mangled name. */
ANON_DECL, if one is available.
FIXME: we should really handle anonymous unions by binding the names
of the members to COMPONENT_REFs rather than this kludge. */
static tree static tree
build_anon_union_vars (anon_decl, elems, static_p, external_p) build_anon_union_vars (object)
tree anon_decl; tree object;
tree* elems;
int static_p;
int external_p;
{ {
tree type = TREE_TYPE (anon_decl); tree type = TREE_TYPE (object);
tree main_decl = NULL_TREE; tree main_decl = NULL_TREE;
tree field; tree field;
...@@ -1298,12 +1291,14 @@ build_anon_union_vars (anon_decl, elems, static_p, external_p) ...@@ -1298,12 +1291,14 @@ build_anon_union_vars (anon_decl, elems, static_p, external_p)
field = TREE_CHAIN (field)) field = TREE_CHAIN (field))
{ {
tree decl; tree decl;
tree ref;
if (DECL_ARTIFICIAL (field)) if (DECL_ARTIFICIAL (field))
continue; continue;
if (TREE_CODE (field) != FIELD_DECL) if (TREE_CODE (field) != FIELD_DECL)
{ {
cp_pedwarn_at ("`%#D' invalid; an anonymous union can only have non-static data members", cp_pedwarn_at ("\
`%#D' invalid; an anonymous union can only have non-static data members",
field); field);
continue; continue;
} }
...@@ -1313,54 +1308,24 @@ build_anon_union_vars (anon_decl, elems, static_p, external_p) ...@@ -1313,54 +1308,24 @@ build_anon_union_vars (anon_decl, elems, static_p, external_p)
else if (TREE_PROTECTED (field)) else if (TREE_PROTECTED (field))
cp_pedwarn_at ("protected member `%#D' in anonymous union", field); cp_pedwarn_at ("protected member `%#D' in anonymous union", field);
if (DECL_NAME (field) == NULL_TREE ref = build_class_member_access_expr (object, field, NULL_TREE,
&& ANON_AGGR_TYPE_P (TREE_TYPE (field))) false);
{
decl = build_anon_union_vars (field, elems, static_p, external_p); if (DECL_NAME (field))
if (!decl)
continue;
}
else if (DECL_NAME (field) == NULL_TREE)
continue;
else
{ {
decl = build_decl (VAR_DECL, DECL_NAME (field), TREE_TYPE (field)); decl = build_decl (ALIAS_DECL, DECL_NAME (field), TREE_TYPE (field));
/* tell `pushdecl' that this is not tentative. */ DECL_INITIAL (decl) = ref;
DECL_INITIAL (decl) = error_mark_node;
TREE_PUBLIC (decl) = 0; TREE_PUBLIC (decl) = 0;
TREE_STATIC (decl) = static_p; TREE_STATIC (decl) = 0;
DECL_EXTERNAL (decl) = external_p; DECL_EXTERNAL (decl) = 1;
decl = pushdecl (decl); decl = pushdecl (decl);
DECL_INITIAL (decl) = NULL_TREE;
} }
else if (ANON_AGGR_TYPE_P (TREE_TYPE (field)))
decl = build_anon_union_vars (ref);
/* Only write out one anon union element--choose the largest if (main_decl == NULL_TREE)
one. We used to try to find one the same size as the union,
but that fails if the ABI forces us to align the union more
strictly. */
if (main_decl == NULL_TREE
|| tree_int_cst_lt (DECL_SIZE (main_decl), DECL_SIZE (decl)))
{
if (main_decl)
TREE_ASM_WRITTEN (main_decl) = 1;
main_decl = decl; main_decl = decl;
} }
else
/* ??? This causes there to be no debug info written out
about this decl. */
TREE_ASM_WRITTEN (decl) = 1;
if (DECL_NAME (field) == NULL_TREE
&& ANON_AGGR_TYPE_P (TREE_TYPE (field)))
/* The remainder of the processing was already done in the
recursive call. */
continue;
/* If there's a cleanup to do, it belongs in the
TREE_PURPOSE of the following TREE_LIST. */
*elems = tree_cons (NULL_TREE, decl, *elems);
TREE_TYPE (*elems) = type;
}
return main_decl; return main_decl;
} }
...@@ -1376,8 +1341,6 @@ finish_anon_union (anon_union_decl) ...@@ -1376,8 +1341,6 @@ finish_anon_union (anon_union_decl)
tree type = TREE_TYPE (anon_union_decl); tree type = TREE_TYPE (anon_union_decl);
tree main_decl; tree main_decl;
int public_p = TREE_PUBLIC (anon_union_decl); int public_p = TREE_PUBLIC (anon_union_decl);
int static_p = TREE_STATIC (anon_union_decl);
int external_p = DECL_EXTERNAL (anon_union_decl);
/* The VAR_DECL's context is the same as the TYPE's context. */ /* The VAR_DECL's context is the same as the TYPE's context. */
DECL_CONTEXT (anon_union_decl) = DECL_CONTEXT (TYPE_NAME (type)); DECL_CONTEXT (anon_union_decl) = DECL_CONTEXT (TYPE_NAME (type));
...@@ -1393,29 +1356,27 @@ finish_anon_union (anon_union_decl) ...@@ -1393,29 +1356,27 @@ finish_anon_union (anon_union_decl)
if (!processing_template_decl) if (!processing_template_decl)
{ {
main_decl main_decl = build_anon_union_vars (anon_union_decl);
= build_anon_union_vars (anon_union_decl,
&DECL_ANON_UNION_ELEMS (anon_union_decl),
static_p, external_p);
if (main_decl == NULL_TREE) if (main_decl == NULL_TREE)
{ {
warning ("anonymous aggregate with no members"); warning ("anonymous union with no members");
return; return;
} }
if (static_p) /* Use main_decl to set the mangled name. */
{ DECL_NAME (anon_union_decl) = DECL_NAME (main_decl);
make_decl_rtl (main_decl, 0); mangle_decl (anon_union_decl);
COPY_DECL_RTL (main_decl, anon_union_decl); DECL_NAME (anon_union_decl) = NULL_TREE;
expand_anon_union_decl (anon_union_decl,
NULL_TREE,
DECL_ANON_UNION_ELEMS (anon_union_decl));
return;
}
} }
pushdecl (anon_union_decl);
if (building_stmt_tree ()
&& at_function_scope_p ())
add_decl_stmt (anon_union_decl); add_decl_stmt (anon_union_decl);
else if (!processing_template_decl)
rest_of_decl_compilation (anon_union_decl, NULL,
toplevel_bindings_p (), at_eof);
} }
/* Auxiliary functions to make type signatures for /* Auxiliary functions to make type signatures for
......
...@@ -1444,7 +1444,9 @@ unemitted_tinfo_decl_p (t, data) ...@@ -1444,7 +1444,9 @@ unemitted_tinfo_decl_p (t, data)
{ {
if (/* It's a var decl */ if (/* It's a var decl */
TREE_CODE (t) == VAR_DECL TREE_CODE (t) == VAR_DECL
/* whos name points back to itself */ /* which has a name */
&& DECL_NAME (t)
/* whose name points back to itself */
&& IDENTIFIER_GLOBAL_VALUE (DECL_NAME (t)) == t && IDENTIFIER_GLOBAL_VALUE (DECL_NAME (t)) == t
/* whose name's type is non-null */ /* whose name's type is non-null */
&& TREE_TYPE (DECL_NAME (t)) && TREE_TYPE (DECL_NAME (t))
......
...@@ -1987,7 +1987,8 @@ build_class_member_access_expr (tree object, tree member, ...@@ -1987,7 +1987,8 @@ build_class_member_access_expr (tree object, tree member,
OBJECT so that it refers to the class containing the OBJECT so that it refers to the class containing the
anonymous union. Generate a reference to the anonymous union anonymous union. Generate a reference to the anonymous union
itself, and recur to find MEMBER. */ itself, and recur to find MEMBER. */
if (ANON_AGGR_TYPE_P (DECL_CONTEXT (member))) if (ANON_AGGR_TYPE_P (DECL_CONTEXT (member))
&& !same_type_p (object_type, DECL_CONTEXT (member)))
{ {
tree anonymous_union; tree anonymous_union;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment