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 static tree
of the members to COMPONENT_REFs rather than this kludge. */ build_anon_union_vars (object)
tree object;
static tree
build_anon_union_vars (anon_decl, elems, static_p, external_p)
tree anon_decl;
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,55 +1308,25 @@ build_anon_union_vars (anon_decl, elems, static_p, external_p) ...@@ -1313,55 +1308,25 @@ 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;
}
/* Only write out one anon union element--choose the largest
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;
} }
else else if (ANON_AGGR_TYPE_P (TREE_TYPE (field)))
/* ??? This causes there to be no debug info written out decl = build_anon_union_vars (ref);
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 if (main_decl == NULL_TREE)
TREE_PURPOSE of the following TREE_LIST. */ main_decl = decl;
*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;
}
} }
add_decl_stmt (anon_union_decl); pushdecl (anon_union_decl);
if (building_stmt_tree ()
&& at_function_scope_p ())
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