diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 1d7d395e344..b19003eccd5 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,22 @@ +2002-12-18 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. + 2002-12-18 Kriang Lerdsuwanakij PR c++/8099 diff --git a/gcc/cp/cp-tree.def b/gcc/cp/cp-tree.def index 1aae797a4c2..436f8406973 100644 --- a/gcc/cp/cp-tree.def +++ b/gcc/cp/cp-tree.def @@ -89,6 +89,10 @@ DEFTREECODE (THROW_EXPR, "throw_expr", 'e', 1) these to avoid actually creating instances of the empty classes. */ 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 class. BASELINK_FUNCTIONS gives the FUNCTION_DECL, TEMPLATE_DECL, OVERLOAD, or TEMPLATE_ID_EXPR corresponding to the diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 870a13dd283..0209e344be1 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -4051,6 +4051,7 @@ pushdecl (x) && t != NULL_TREE) && (TREE_CODE (x) == TYPE_DECL || TREE_CODE (x) == VAR_DECL + || TREE_CODE (x) == ALIAS_DECL || TREE_CODE (x) == NAMESPACE_DECL || TREE_CODE (x) == CONST_DECL || TREE_CODE (x) == TEMPLATE_DECL)) @@ -6228,6 +6229,9 @@ does not match lookup in the current scope (`%#D')", else if (from_obj) val = from_obj; + if (val && TREE_CODE (val) == ALIAS_DECL) + val = DECL_INITIAL (val); + return val; } diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index 6734301f2df..f33ba8d211b 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -66,7 +66,7 @@ static int maybe_emit_vtables (tree); static int is_namespace_ancestor PARAMS ((tree, tree)); static void add_using_namespace PARAMS ((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 void output_vtable_inherit PARAMS ((tree)); static tree start_objects PARAMS ((int, int)); @@ -1269,22 +1269,15 @@ defer_fn (fn) VARRAY_PUSH_TREE (deferred_fns, fn); } -/* Hunts through the global anonymous union ANON_DECL, building - appropriate VAR_DECLs. Stores cleanups on the list of ELEMS, and - returns a VAR_DECL whose size is the same as the size of the - ANON_DECL, if one is available. +/* Walks through the namespace- or function-scope anonymous union OBJECT, + building appropriate ALIAS_DECLs. Returns one of the fields for use in + the mangled name. */ - FIXME: we should really handle anonymous unions by binding the names - of the members to COMPONENT_REFs rather than this kludge. */ - -static tree -build_anon_union_vars (anon_decl, elems, static_p, external_p) - tree anon_decl; - tree* elems; - int static_p; - int external_p; +static tree +build_anon_union_vars (object) + tree object; { - tree type = TREE_TYPE (anon_decl); + tree type = TREE_TYPE (object); tree main_decl = NULL_TREE; tree field; @@ -1298,12 +1291,14 @@ build_anon_union_vars (anon_decl, elems, static_p, external_p) field = TREE_CHAIN (field)) { tree decl; + tree ref; if (DECL_ARTIFICIAL (field)) continue; 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); continue; } @@ -1313,55 +1308,25 @@ build_anon_union_vars (anon_decl, elems, static_p, external_p) else if (TREE_PROTECTED (field)) cp_pedwarn_at ("protected member `%#D' in anonymous union", field); - if (DECL_NAME (field) == NULL_TREE - && ANON_AGGR_TYPE_P (TREE_TYPE (field))) + ref = build_class_member_access_expr (object, field, NULL_TREE, + false); + + if (DECL_NAME (field)) { - decl = build_anon_union_vars (field, elems, static_p, external_p); - if (!decl) - continue; - } - else if (DECL_NAME (field) == NULL_TREE) - continue; - else - { - decl = build_decl (VAR_DECL, DECL_NAME (field), TREE_TYPE (field)); - /* tell `pushdecl' that this is not tentative. */ - DECL_INITIAL (decl) = error_mark_node; + decl = build_decl (ALIAS_DECL, DECL_NAME (field), TREE_TYPE (field)); + DECL_INITIAL (decl) = ref; TREE_PUBLIC (decl) = 0; - TREE_STATIC (decl) = static_p; - DECL_EXTERNAL (decl) = external_p; + TREE_STATIC (decl) = 0; + DECL_EXTERNAL (decl) = 1; 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 - 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 - /* ??? 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; + if (main_decl == NULL_TREE) + main_decl = decl; } - + return main_decl; } @@ -1376,8 +1341,6 @@ finish_anon_union (anon_union_decl) tree type = TREE_TYPE (anon_union_decl); tree main_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. */ DECL_CONTEXT (anon_union_decl) = DECL_CONTEXT (TYPE_NAME (type)); @@ -1393,29 +1356,27 @@ finish_anon_union (anon_union_decl) if (!processing_template_decl) { - main_decl - = build_anon_union_vars (anon_union_decl, - &DECL_ANON_UNION_ELEMS (anon_union_decl), - static_p, external_p); - + main_decl = build_anon_union_vars (anon_union_decl); + if (main_decl == NULL_TREE) { - warning ("anonymous aggregate with no members"); + warning ("anonymous union with no members"); return; } - if (static_p) - { - make_decl_rtl (main_decl, 0); - COPY_DECL_RTL (main_decl, anon_union_decl); - expand_anon_union_decl (anon_union_decl, - NULL_TREE, - DECL_ANON_UNION_ELEMS (anon_union_decl)); - return; - } + /* Use main_decl to set the mangled name. */ + DECL_NAME (anon_union_decl) = DECL_NAME (main_decl); + mangle_decl (anon_union_decl); + DECL_NAME (anon_union_decl) = NULL_TREE; } - 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 diff --git a/gcc/cp/rtti.c b/gcc/cp/rtti.c index d8041ab53e4..495e0d4576a 100644 --- a/gcc/cp/rtti.c +++ b/gcc/cp/rtti.c @@ -1444,7 +1444,9 @@ unemitted_tinfo_decl_p (t, data) { if (/* It's a 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 /* whose name's type is non-null */ && TREE_TYPE (DECL_NAME (t)) diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index 769702b8a1d..9285ec01686 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -1987,7 +1987,8 @@ build_class_member_access_expr (tree object, tree member, OBJECT so that it refers to the class containing the anonymous union. Generate a reference to the anonymous union 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;