From 4782bd5bee37845e7489a877239c59a569547e96 Mon Sep 17 00:00:00 2001 From: Richard Sandiford Date: Fri, 12 Apr 2002 10:55:27 +0000 Subject: [PATCH] decl.c (duplicate_decls): Don't try to unify an implicit typedef with an explicit one. * decl.c (duplicate_decls): Don't try to unify an implicit typedef with an explicit one. (follow_tag_typedef): New. (lookup_tag): Use it to extract the tag of an explicit typedef. (xref_tag): Likewise. From-SVN: r52213 --- gcc/cp/ChangeLog | 8 ++++ gcc/cp/decl.c | 95 ++++++++++++++++++++++++++++++++++++++---------- 2 files changed, 84 insertions(+), 19 deletions(-) diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 439a3fcb462..a9b70e9b1d3 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,11 @@ +2002-04-12 Richard Sandiford + + * decl.c (duplicate_decls): Don't try to unify an implicit typedef + with an explicit one. + (follow_tag_typedef): New. + (lookup_tag): Use it to extract the tag of an explicit typedef. + (xref_tag): Likewise. + 2002-04-11 Andrew Haley * typeck.c (type_after_usual_arithmetic_conversions): diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index dc9d37313e7..93e63058b96 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -82,6 +82,7 @@ static tree grokfndecl PARAMS ((tree, tree, tree, tree, int, enum overload_flags, tree, tree, int, int, int, int, int, int, tree)); static tree grokvardecl PARAMS ((tree, tree, RID_BIT_TYPE *, int, int, tree)); +static tree follow_tag_typedef PARAMS ((tree)); static tree lookup_tag PARAMS ((enum tree_code, tree, struct binding_level *, int)); static void set_identifier_type_value_with_scope @@ -3426,6 +3427,18 @@ duplicate_decls (newdecl, olddecl) } } + /* Do not merge an implicit typedef with an explicit one. In: + + class A; + ... + typedef class A A __attribute__ ((foo)); + + the attribute should apply only to the typedef. */ + if (TREE_CODE (olddecl) == TYPE_DECL + && (DECL_IMPLICIT_TYPEDEF_P (olddecl) + || DECL_IMPLICIT_TYPEDEF_P (newdecl))) + return 0; + /* If new decl is `static' and an `extern' was seen previously, warn about it. */ warn_extern_redeclared_static (newdecl, olddecl); @@ -5285,6 +5298,45 @@ storetags (tags) current_binding_level->tags = tags; } +/* Return the type that should be used when TYPE's name is preceded + by a tag such as 'struct' or 'union', or null if the name cannot + be used in this way. + + For example, when processing the third line of: + + struct A; + typedef struct A A; + struct A; + + lookup of A will find the typedef. Given A's typedef, this function + will return the type associated with "struct A". For the tag to be + anything other than TYPE, TYPE must be a typedef whose original type + has the same name and context as TYPE itself. + + It is not valid for a typedef of an anonymous type to be used with + an explicit tag: + + typedef struct { ... } B; + struct B; + + Return null for this case. */ + +static tree +follow_tag_typedef (type) + tree type; +{ + tree original; + + original = original_type (type); + if (TYPE_IDENTIFIER (original) == TYPE_IDENTIFIER (type) + && (CP_DECL_CONTEXT (TYPE_NAME (original)) + == CP_DECL_CONTEXT (TYPE_NAME (type))) + && !(CLASS_TYPE_P (original) && TYPE_WAS_ANONYMOUS (original))) + return original; + else + return NULL_TREE; +} + /* Given NAME, an IDENTIFIER_NODE, return the structure (or union or enum) definition for that name. Searches binding levels from BINDING_LEVEL up to the global level. @@ -5336,18 +5388,23 @@ lookup_tag (form, name, binding_level, thislevel_only) else old = BINDING_TYPE (old); - /* If it has an original type, it is a typedef, and we - should not return it. */ - if (old && DECL_ORIGINAL_TYPE (TYPE_NAME (old))) - old = NULL_TREE; - if (old && TREE_CODE (old) != form - && (form == ENUMERAL_TYPE || TREE_CODE (old) == ENUMERAL_TYPE)) + if (old) { - error ("`%#D' redeclared as %C", old, form); - return NULL_TREE; + /* We've found something at this binding level. If it is + a typedef, extract the tag it refers to. Lookup fails + if the typedef doesn't refer to a taggable type. */ + old = follow_tag_typedef (old); + if (!old) + return NULL_TREE; + if (TREE_CODE (old) != form + && (form == ENUMERAL_TYPE + || TREE_CODE (old) == ENUMERAL_TYPE)) + { + error ("`%#D' redeclared as %C", old, form); + return NULL_TREE; + } + return old; } - if (old) - return old; if (thislevel_only || tail == global_namespace) return NULL_TREE; } @@ -12685,7 +12742,6 @@ xref_tag (code_type_node, name, globalize) enum tree_code code; register tree ref, t; struct binding_level *b = current_binding_level; - int got_type = 0; tree attributes = NULL_TREE; tree context = NULL_TREE; @@ -12722,7 +12778,6 @@ xref_tag (code_type_node, name, globalize) { t = name; name = TYPE_IDENTIFIER (t); - got_type = 1; } else t = IDENTIFIER_TYPE_VALUE (name); @@ -12767,18 +12822,20 @@ xref_tag (code_type_node, name, globalize) { if (t) { + ref = follow_tag_typedef (t); + /* [dcl.type.elab] If the identifier resolves to a typedef-name or a template type-parameter, the elaborated-type-specifier is ill-formed. */ - if (t != TYPE_MAIN_VARIANT (t) - || (CLASS_TYPE_P (t) && TYPE_WAS_ANONYMOUS (t))) - pedwarn ("using typedef-name `%D' after `%s'", - TYPE_NAME (t), tag_name (tag_code)); + if (!ref) + { + pedwarn ("using typedef-name `%D' after `%s'", + TYPE_NAME (t), tag_name (tag_code)); + ref = t; + } else if (TREE_CODE (t) == TEMPLATE_TYPE_PARM) error ("using template type parameter `%T' after `%s'", - t, tag_name (tag_code)); - - ref = t; + t, tag_name (tag_code)); } else ref = lookup_tag (code, name, b, 0); -- 2.30.2