aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/cp/ChangeLog19
-rw-r--r--gcc/cp/cp-tree.def4
-rw-r--r--gcc/cp/decl.c4
-rw-r--r--gcc/cp/decl2.c115
-rw-r--r--gcc/cp/rtti.c4
-rw-r--r--gcc/cp/typeck.c3
6 files changed, 70 insertions, 79 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 1d7d395..b19003e 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,22 @@
+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>
PR c++/8099
diff --git a/gcc/cp/cp-tree.def b/gcc/cp/cp-tree.def
index 1aae797..436f840 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 870a13d..0209e34 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 6734301..f33ba8d 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)))
- {
- decl = build_anon_union_vars (field, elems, static_p, external_p);
- if (!decl)
- continue;
- }
- else if (DECL_NAME (field) == NULL_TREE)
- continue;
- else
+ ref = build_class_member_access_expr (object, field, NULL_TREE,
+ false);
+
+ if (DECL_NAME (field))
{
- 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;
- }
-
- /* 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;
+ else if (ANON_AGGR_TYPE_P (TREE_TYPE (field)))
+ decl = build_anon_union_vars (ref);
- /* 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 d8041ab..495e0d4 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 769702b..9285ec0 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;