Friend class name lookup 1/n, PR c++/18471

Friend class name lookup 1/n, PR c++/18471
	* decl.c (lookup_and_check_tag): New function.
	(xref_tag, start_enum): Use it.
	(check_elaborated_type_specifier): Move TEMPLATE_TYPE_PARM check
	before !DECL_IMPLICIT_TYPEDEF_P.  Also display previously declared
	location.
	* name-lookup.c (lookup_name_current_level): Rename to ...
	(lookup_name_innermost_nonclass_level): ... this.
	(lookup_type_scope): New function.
	* name-lookup.h (lookup_name_current_level): Rename to ...
	(lookup_name_innermost_nonclass_level): ... this.
	(lookup_type_scope): Add declaration.

	* g++.dg/lookup/struct1.C: Adjust expected error.
	* g++.dg/parse/elab1.C: Likewise.
	* g++.dg/parse/elab2.C: Likewise.
	* g++.dg/parse/int-as-enum1.C: Likewise.
	* g++.dg/parse/struct-as-enum1.C: Likewise.
	* g++.dg/parse/typedef1.C: Likewise.
	* g++.dg/parse/typedef3.C: Likewise.
	* g++.dg/parse/typedef4.C: Likewise.
	* g++.dg/parse/typedef5.C: Likewise.
	* g++.dg/template/nontype4.C: Likewise.
	* g++.old-deja/g++.benjamin/typedef01.C: Likewise.
	* g++.old-deja/g++.other/elab1.C: Likewise.
	* g++.old-deja/g++.other/syntax4.C: Likewise.

From-SVN: r90657
This commit is contained in:
Kriang Lerdsuwanakij 2004-11-15 10:34:06 +00:00 committed by Kriang Lerdsuwanakij
parent e24b3cc0aa
commit 461c6fce56
19 changed files with 256 additions and 116 deletions

View file

@ -1,3 +1,18 @@
2004-11-15 Kriang Lerdsuwanakij <lerdsuwa@users.sourceforge.net>
Friend class name lookup 1/n, PR c++/18471
* decl.c (lookup_and_check_tag): New function.
(xref_tag, start_enum): Use it.
(check_elaborated_type_specifier): Move TEMPLATE_TYPE_PARM check
before !DECL_IMPLICIT_TYPEDEF_P. Also display previously declared
location.
* name-lookup.c (lookup_name_current_level): Rename to ...
(lookup_name_innermost_nonclass_level): ... this.
(lookup_type_scope): New function.
* name-lookup.h (lookup_name_current_level): Rename to ...
(lookup_name_innermost_nonclass_level): ... this.
(lookup_type_scope): Add declaration.
2004-11-14 Kriang Lerdsuwanakij <lerdsuwa@users.sourceforge.net> 2004-11-14 Kriang Lerdsuwanakij <lerdsuwa@users.sourceforge.net>
PR c++/17344 PR c++/17344

View file

@ -81,7 +81,8 @@ static hashval_t typename_hash (const void *);
static int typename_compare (const void *, const void *); static int typename_compare (const void *, const void *);
static tree local_variable_p_walkfn (tree *, int *, void *); static tree local_variable_p_walkfn (tree *, int *, void *);
static tree record_builtin_java_type (const char *, int); static tree record_builtin_java_type (const char *, int);
static const char *tag_name (enum tag_types code); static const char *tag_name (enum tag_types);
static tree lookup_and_check_tag (enum tag_types, tree, bool globalize, bool);
static int walk_namespaces_r (tree, walk_namespaces_fn, void *); static int walk_namespaces_r (tree, walk_namespaces_fn, void *);
static int walk_globals_r (tree, void*); static int walk_globals_r (tree, void*);
static int walk_vtables_r (tree, void*); static int walk_vtables_r (tree, void*);
@ -9056,6 +9057,14 @@ check_elaborated_type_specifier (enum tag_types tag_code,
type = TREE_TYPE (decl); type = TREE_TYPE (decl);
/* Check TEMPLATE_TYPE_PARM first because DECL_IMPLICIT_TYPEDEF_P
is false for this case as well. */
if (TREE_CODE (type) == TEMPLATE_TYPE_PARM)
{
error ("using template type parameter %qT after %qs",
type, tag_name (tag_code));
return error_mark_node;
}
/* [dcl.type.elab] /* [dcl.type.elab]
If the identifier resolves to a typedef-name or a template If the identifier resolves to a typedef-name or a template
@ -9064,16 +9073,10 @@ check_elaborated_type_specifier (enum tag_types tag_code,
In other words, the only legitimate declaration to use in the In other words, the only legitimate declaration to use in the
elaborated type specifier is the implicit typedef created when elaborated type specifier is the implicit typedef created when
the type is declared. */ the type is declared. */
if (!DECL_IMPLICIT_TYPEDEF_P (decl)) else if (!DECL_IMPLICIT_TYPEDEF_P (decl))
{ {
error ("using typedef-name %qD after %qs", decl, tag_name (tag_code)); error ("using typedef-name %qD after %qs", decl, tag_name (tag_code));
return IS_AGGR_TYPE (type) ? type : error_mark_node; cp_error_at ("%qD has a previous declaration here", decl);
}
if (TREE_CODE (type) == TEMPLATE_TYPE_PARM)
{
error ("using template type parameter %qT after %qs",
type, tag_name (tag_code));
return error_mark_node; return error_mark_node;
} }
else if (TREE_CODE (type) != RECORD_TYPE else if (TREE_CODE (type) != RECORD_TYPE
@ -9081,12 +9084,14 @@ check_elaborated_type_specifier (enum tag_types tag_code,
&& tag_code != enum_type) && tag_code != enum_type)
{ {
error ("%qT referred to as %qs", type, tag_name (tag_code)); error ("%qT referred to as %qs", type, tag_name (tag_code));
cp_error_at ("%qT has a previous declaration here", type);
return error_mark_node; return error_mark_node;
} }
else if (TREE_CODE (type) != ENUMERAL_TYPE else if (TREE_CODE (type) != ENUMERAL_TYPE
&& tag_code == enum_type) && tag_code == enum_type)
{ {
error ("%qT referred to as enum", type); error ("%qT referred to as enum", type);
cp_error_at ("%qT has a previous declaration here", type);
return error_mark_node; return error_mark_node;
} }
else if (!allow_template_p else if (!allow_template_p
@ -9110,57 +9115,21 @@ check_elaborated_type_specifier (enum tag_types tag_code,
return type; return type;
} }
/* Get the struct, enum or union (TAG_CODE says which) with tag NAME. /* Lookup NAME in elaborate type specifier in scope according to
Define the tag as a forward-reference if it is not defined. GLOBALIZE and issue diagnostics if necessary.
Return *_TYPE node upon success, NULL_TREE when the NAME is not
found, and ERROR_MARK_NODE for type error. */
If a declaration is given, process it here, and report an error if static tree
multiple declarations are not identical. lookup_and_check_tag (enum tag_types tag_code, tree name,
GLOBALIZE is false when this is also a definition. Only look in
the current frame for the name (since C++ allows new names in any
scope.)
TEMPLATE_HEADER_P is true when this declaration is preceded by
a set of template parameters. */
tree
xref_tag (enum tag_types tag_code, tree name,
bool globalize, bool template_header_p) bool globalize, bool template_header_p)
{ {
enum tree_code code;
tree t; tree t;
struct cp_binding_level *b = current_binding_level; tree decl;
tree context = NULL_TREE; if (globalize)
decl = lookup_name (name, 2);
timevar_push (TV_NAME_LOOKUP);
gcc_assert (TREE_CODE (name) == IDENTIFIER_NODE);
switch (tag_code)
{
case record_type:
case class_type:
code = RECORD_TYPE;
break;
case union_type:
code = UNION_TYPE;
break;
case enum_type:
code = ENUMERAL_TYPE;
break;
default:
gcc_unreachable ();
}
if (! globalize)
{
/* If we know we are defining this tag, only look it up in
this scope and don't try to find it as a type. */
t = lookup_tag (code, name, b, 1);
}
else else
{ decl = lookup_type_scope (name);
tree decl = lookup_name (name, 2);
if (decl && DECL_CLASS_TEMPLATE_P (decl)) if (decl && DECL_CLASS_TEMPLATE_P (decl))
decl = DECL_TEMPLATE_RESULT (decl); decl = DECL_TEMPLATE_RESULT (decl);
@ -9187,13 +9156,65 @@ xref_tag (enum tag_types tag_code, tree name,
decl, decl,
template_header_p template_header_p
| DECL_SELF_REFERENCE_P (decl)); | DECL_SELF_REFERENCE_P (decl));
if (t == error_mark_node) return t;
POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, error_mark_node);
} }
else else
t = NULL_TREE; return NULL_TREE;
}
if (t && current_class_type /* Get the struct, enum or union (TAG_CODE says which) with tag NAME.
Define the tag as a forward-reference if it is not defined.
If a declaration is given, process it here, and report an error if
multiple declarations are not identical.
GLOBALIZE is false when this is also a definition. Only look in
the current frame for the name (since C++ allows new names in any
scope.)
TEMPLATE_HEADER_P is true when this declaration is preceded by
a set of template parameters. */
tree
xref_tag (enum tag_types tag_code, tree name,
bool globalize, bool template_header_p)
{
enum tree_code code;
tree t;
tree context = NULL_TREE;
timevar_push (TV_NAME_LOOKUP);
gcc_assert (TREE_CODE (name) == IDENTIFIER_NODE);
switch (tag_code)
{
case record_type:
case class_type:
code = RECORD_TYPE;
break;
case union_type:
code = UNION_TYPE;
break;
case enum_type:
code = ENUMERAL_TYPE;
break;
default:
gcc_unreachable ();
}
/* In case of anonymous name, xref_tag is only called to
make type node and push name. Name lookup is not required. */
if (ANON_AGGRNAME_P (name))
t = NULL_TREE;
else
t = lookup_and_check_tag (tag_code, name,
globalize, template_header_p);
if (t == error_mark_node)
POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, error_mark_node);
if (globalize && t && current_class_type
&& template_class_depth (current_class_type) && template_class_depth (current_class_type)
&& template_header_p) && template_header_p)
{ {
@ -9236,7 +9257,6 @@ xref_tag (enum tag_types tag_code, tree name,
context = TYPE_CONTEXT (t); context = TYPE_CONTEXT (t);
t = NULL_TREE; t = NULL_TREE;
} }
}
if (! t) if (! t)
{ {
@ -9482,14 +9502,13 @@ tree
start_enum (tree name) start_enum (tree name)
{ {
tree enumtype = NULL_TREE; tree enumtype = NULL_TREE;
struct cp_binding_level *b = current_binding_level;
/* If this is the real definition for a previous forward reference, /* If this is the real definition for a previous forward reference,
fill in the contents in the same object that used to be the fill in the contents in the same object that used to be the
forward reference. */ forward reference. */
if (name != NULL_TREE) if (name != NULL_TREE)
enumtype = lookup_tag (ENUMERAL_TYPE, name, b, 1); enumtype = lookup_and_check_tag (enum_type, name, 0, 0);
if (enumtype != NULL_TREE && TREE_CODE (enumtype) == ENUMERAL_TYPE) if (enumtype != NULL_TREE && TREE_CODE (enumtype) == ENUMERAL_TYPE)
{ {

View file

@ -43,7 +43,7 @@ struct scope_binding {
static cxx_scope *innermost_nonclass_level (void); static cxx_scope *innermost_nonclass_level (void);
static tree select_decl (const struct scope_binding *, int); static tree select_decl (const struct scope_binding *, int);
static cxx_binding *binding_for_name (cxx_scope *, tree); static cxx_binding *binding_for_name (cxx_scope *, tree);
static tree lookup_name_current_level (tree); static tree lookup_name_innermost_nonclass_level (tree);
static tree push_overloaded_decl (tree, int); static tree push_overloaded_decl (tree, int);
static bool lookup_using_namespace (tree, struct scope_binding *, tree, static bool lookup_using_namespace (tree, struct scope_binding *, tree,
tree, int); tree, int);
@ -678,7 +678,7 @@ pushdecl (tree x)
if (DECL_NAMESPACE_SCOPE_P (x) && namespace_bindings_p ()) if (DECL_NAMESPACE_SCOPE_P (x) && namespace_bindings_p ())
t = namespace_binding (name, DECL_CONTEXT (x)); t = namespace_binding (name, DECL_CONTEXT (x));
else else
t = lookup_name_current_level (name); t = lookup_name_innermost_nonclass_level (name);
/* [basic.link] If there is a visible declaration of an entity /* [basic.link] If there is a visible declaration of an entity
with linkage having the same name and type, ignoring entities with linkage having the same name and type, ignoring entities
@ -1111,7 +1111,7 @@ push_local_binding (tree id, tree decl, int flags)
push_local_binding with a friend decl of a local class. */ push_local_binding with a friend decl of a local class. */
b = innermost_nonclass_level (); b = innermost_nonclass_level ();
if (lookup_name_current_level (id)) if (lookup_name_innermost_nonclass_level (id))
{ {
/* Supplement the existing binding. */ /* Supplement the existing binding. */
if (!supplement_binding (IDENTIFIER_BINDING (id), decl)) if (!supplement_binding (IDENTIFIER_BINDING (id), decl))
@ -1998,7 +1998,7 @@ push_overloaded_decl (tree decl, int flags)
if (doing_global) if (doing_global)
old = namespace_binding (name, DECL_CONTEXT (decl)); old = namespace_binding (name, DECL_CONTEXT (decl));
else else
old = lookup_name_current_level (name); old = lookup_name_innermost_nonclass_level (name);
if (old) if (old)
{ {
@ -2286,7 +2286,7 @@ do_local_using_decl (tree decl, tree scope, tree name)
&& at_function_scope_p ()) && at_function_scope_p ())
add_decl_expr (decl); add_decl_expr (decl);
oldval = lookup_name_current_level (name); oldval = lookup_name_innermost_nonclass_level (name);
oldtype = lookup_type_current_level (name); oldtype = lookup_type_current_level (name);
do_nonmember_using_decl (scope, name, oldval, oldtype, &newval, &newtype); do_nonmember_using_decl (scope, name, oldval, oldtype, &newval, &newtype);
@ -4122,11 +4122,90 @@ lookup_name (tree name, int prefer_type)
0, LOOKUP_COMPLAIN); 0, LOOKUP_COMPLAIN);
} }
/* Look up NAME for type used in elaborated name specifier in
the current scope (possibly more if cleanup or template parameter
scope is encounter). Unlike lookup_name_real, we make sure that
NAME is actually declared in the desired scope, not from inheritance,
using declaration, nor using directive. A TYPE_DECL best matching
the NAME is returned. Catching error and issuing diagnostics are
caller's responsibility. */
tree
lookup_type_scope (tree name)
{
cxx_binding *iter = NULL;
tree val = NULL_TREE;
timevar_push (TV_NAME_LOOKUP);
/* Look in non-namespace scope first. */
if (current_binding_level->kind != sk_namespace)
iter = outer_binding (name, NULL, /*class_p=*/ true);
for (; iter; iter = outer_binding (name, iter, /*class_p=*/ true))
{
/* Check if this is the kind of thing we're looking for.
Make sure it doesn't come from base class. For ITER->VALUE,
we can simply use INHERITED_VALUE_BINDING_P. For ITER->TYPE,
we have to use our own check.
We check ITER->TYPE before ITER->VALUE in order to handle
typedef struct C {} C;
correctly. */
if (qualify_lookup (iter->type, LOOKUP_PREFER_TYPES)
&& (LOCAL_BINDING_P (iter)
|| DECL_CONTEXT (iter->type) == iter->scope->this_entity))
val = iter->type;
else if (!INHERITED_VALUE_BINDING_P (iter)
&& qualify_lookup (iter->value, LOOKUP_PREFER_TYPES))
val = iter->value;
if (val)
break;
}
/* Look in namespace scope. */
if (!val)
{
iter = cxx_scope_find_binding_for_name
(NAMESPACE_LEVEL (current_decl_namespace ()), name);
if (iter)
{
/* If this is the kind of thing we're looking for, we're done. */
if (qualify_lookup (iter->type, LOOKUP_PREFER_TYPES))
val = iter->type;
else if (qualify_lookup (iter->value, LOOKUP_PREFER_TYPES))
val = iter->value;
}
}
/* Type found, check if it is in the current scope, ignoring cleanup
and template parameter scopes. */
if (val)
{
struct cp_binding_level *b = current_binding_level;
while (b)
{
if (iter->scope == b)
POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, val);
if (b->kind == sk_cleanup || b->kind == sk_template_parms)
b = b->level_chain;
else
break;
}
}
POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, NULL_TREE);
}
/* Similar to `lookup_name' but look only in the innermost non-class /* Similar to `lookup_name' but look only in the innermost non-class
binding level. */ binding level. */
static tree static tree
lookup_name_current_level (tree name) lookup_name_innermost_nonclass_level (tree name)
{ {
struct cp_binding_level *b; struct cp_binding_level *b;
tree t = NULL_TREE; tree t = NULL_TREE;
@ -4164,7 +4243,7 @@ lookup_name_current_level (tree name)
POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, t); POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, t);
} }
/* Like lookup_name_current_level, but for types. */ /* Like lookup_name_innermost_nonclass_level, but for types. */
static tree static tree
lookup_type_current_level (tree name) lookup_type_current_level (tree name)

View file

@ -303,6 +303,7 @@ extern tree lookup_tag (enum tree_code, tree, cxx_scope *, int);
extern tree lookup_tag_reverse (tree, tree); extern tree lookup_tag_reverse (tree, tree);
extern tree lookup_name (tree, int); extern tree lookup_name (tree, int);
extern tree lookup_name_real (tree, int, int, bool, int, int); extern tree lookup_name_real (tree, int, int, bool, int, int);
extern tree lookup_type_scope (tree);
extern tree namespace_binding (tree, tree); extern tree namespace_binding (tree, tree);
extern void set_namespace_binding (tree, tree, tree); extern void set_namespace_binding (tree, tree, tree);
extern tree lookup_namespace_name (tree, tree); extern tree lookup_namespace_name (tree, tree);

View file

@ -1,3 +1,21 @@
2004-11-15 Kriang Lerdsuwanakij <lerdsuwa@users.sourceforge.net>
Friend class name lookup 1/n, PR c++/18471
* g++.dg/template/crash26.C: New test.
* g++.dg/lookup/struct1.C: Adjust expected error.
* g++.dg/parse/elab1.C: Likewise.
* g++.dg/parse/elab2.C: Likewise.
* g++.dg/parse/int-as-enum1.C: Likewise.
* g++.dg/parse/struct-as-enum1.C: Likewise.
* g++.dg/parse/typedef1.C: Likewise.
* g++.dg/parse/typedef3.C: Likewise.
* g++.dg/parse/typedef4.C: Likewise.
* g++.dg/parse/typedef5.C: Likewise.
* g++.dg/template/nontype4.C: Likewise.
* g++.old-deja/g++.benjamin/typedef01.C: Likewise.
* g++.old-deja/g++.other/elab1.C: Likewise.
* g++.old-deja/g++.other/syntax4.C: Likewise.
2004-11-15 Eric Botcazou <ebotcazou@libertysurf.fr> 2004-11-15 Eric Botcazou <ebotcazou@libertysurf.fr>
* gcc.dg/intmax_t-1.c: XFAIL on Solaris 2.5.1. * gcc.dg/intmax_t-1.c: XFAIL on Solaris 2.5.1.

View file

@ -3,10 +3,10 @@
struct A; struct A;
typedef struct A B; // { dg-error "previous declaration" } typedef struct A B; // { dg-error "previous declaration" }
struct B; // { dg-error "conflicting declaration" } struct B; // { dg-error "using typedef-name" }
typedef struct { int i; } C; // { dg-error "previous declaration" } typedef struct { int i; } C; // { dg-error "previous declaration" }
struct C; // { dg-error "conflicting declaration" } struct C; // { dg-error "using typedef-name" }
struct D; struct D;
typedef struct D D; typedef struct D D;

View file

@ -1,6 +1,6 @@
namespace Name { namespace Name {
typedef void *(*Function)( void *, int ); typedef void *(*Function)( void *, int ); // { dg-error "previous declaration" }
struct Foo { struct Foo {
struct Function xyz[5]; // { dg-error "" } struct Function xyz[5]; // { dg-error "" }

View file

@ -2,6 +2,6 @@ struct A {};
struct B struct B
{ {
typedef A T; typedef A T; // { dg-error "previous declaration" }
friend struct T; // { dg-error "" } friend struct T; // { dg-error "" }
}; };

View file

@ -2,5 +2,5 @@
// Origin: <wanderer@rsu.ru> // Origin: <wanderer@rsu.ru>
// { dg-do compile } // { dg-do compile }
typedef int A; typedef int A; // { dg-error "previous" }
enum ::A {}; // { dg-error "" } enum ::A {}; // { dg-error "typedef-name|expected unqualified-id" }

View file

@ -4,7 +4,7 @@
namespace N namespace N
{ {
struct A {}; struct A {}; // { dg-error "previous declaration" }
} }
typedef enum N::A B; // { dg-error "enum" } typedef enum N::A B; // { dg-error "enum" }

View file

@ -1,3 +1,3 @@
// PR c++/6477 // PR c++/6477
typedef struct A_ *A; typedef struct A_ *A; // { dg-error "previous declaration" }
typedef struct A B; // { dg-error "" } typedef struct A B; // { dg-error "typedef|invalid type" }

View file

@ -2,6 +2,6 @@
// Origin: Travis J.I. Corcoran <tjic@permabit.com> // Origin: Travis J.I. Corcoran <tjic@permabit.com>
// { dg-do compile } // { dg-do compile }
struct A { typedef A* Ptr; }; struct A { typedef A* Ptr; }; // { dg-error "previous declaration" }
struct A::Ptr; // { dg-error "" } struct A::Ptr; // { dg-error "typedef|not declare anything" }

View file

@ -7,6 +7,6 @@
template<class T> class smart_ptr2 { template<class T> class smart_ptr2 {
T* real_ptr; T* real_ptr;
public: public:
typedef typename T::subT td; typedef typename T::subT td; // { dg-error "previous declaration" }
friend class td; // { dg-error "typedef" } friend class td; // { dg-error "typedef|not name a class" }
}; };

View file

@ -1,6 +1,6 @@
namespace A namespace A
{ {
typedef int T; typedef int T; // { dg-error "previous declaration" }
} }
class A::T x; // { dg-error "" } class A::T x; // { dg-error "using typedef-name" }

View file

@ -0,0 +1,8 @@
// { dg-do compile }
// Origin: Volker Reichelt <reichelt@gcc.gnu.org>
// PR c++/18471: ICE redeclaration of typedef as class template
typedef int X; // { dg-error "previous" }
template<X> struct X {}; // { dg-error "typedef-name" }

View file

@ -7,8 +7,8 @@
template <int> struct A template <int> struct A
{ {
typedef A<0> B; // { dg-error "not a valid type|conflict" } typedef A<0> B; // { dg-error "previous declaration" }
template <B> struct B {}; // { dg-error "not a valid type|declaration" } template <B> struct B {}; // { dg-error "not a valid type|typedef" }
}; };
A<0> a; // { dg-error "instantiated" } A<0> a;

View file

@ -37,7 +37,7 @@ struct S {
~S(); ~S();
}; };
typedef struct S T; typedef struct S T; // { dg-error "previous declaration" }
S a = T(); // OK S a = T(); // OK
struct T * p; // { dg-error "" } using typedef after struct struct T * p; // { dg-error "" } using typedef after struct

View file

@ -1,5 +1,5 @@
// { dg-do assemble } // { dg-do assemble }
typedef struct {} S; typedef struct {} S; // { dg-error "" } Previous declaration of S
S s1; S s1;
struct S* s2; // { dg-error "" } S is a typedef name struct S* s2; // { dg-error "" } S is a typedef name

View file

@ -17,7 +17,7 @@ class X {
class Y { class Y {
public: public:
typedef ::X W; typedef ::X W; // { dg-error "" } previous declaration
class Z; class Z;
}; };