Commit 461c6fce by Kriang Lerdsuwanakij Committed by Kriang Lerdsuwanakij

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
parent e24b3cc0
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
......
...@@ -81,7 +81,8 @@ static hashval_t typename_hash (const void *); ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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,6 +9115,53 @@ check_elaborated_type_specifier (enum tag_types tag_code, ...@@ -9110,6 +9115,53 @@ check_elaborated_type_specifier (enum tag_types tag_code,
return type; return type;
} }
/* Lookup NAME in elaborate type specifier in scope according to
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. */
static tree
lookup_and_check_tag (enum tag_types tag_code, tree name,
bool globalize, bool template_header_p)
{
tree t;
tree decl;
if (globalize)
decl = lookup_name (name, 2);
else
decl = lookup_type_scope (name);
if (decl && DECL_CLASS_TEMPLATE_P (decl))
decl = DECL_TEMPLATE_RESULT (decl);
if (decl && TREE_CODE (decl) == TYPE_DECL)
{
/* Two cases we need to consider when deciding if a class
template is allowed as an elaborated type specifier:
1. It is a self reference to its own class.
2. It comes with a template header.
For example:
template <class T> class C {
class C *c1; // DECL_SELF_REFERENCE_P is true
class D;
};
template <class U> class C; // template_header_p is true
template <class T> class C<T>::D {
class C *c2; // DECL_SELF_REFERENCE_P is true
}; */
t = check_elaborated_type_specifier (tag_code,
decl,
template_header_p
| DECL_SELF_REFERENCE_P (decl));
return t;
}
else
return NULL_TREE;
}
/* Get the struct, enum or union (TAG_CODE says which) with tag NAME. /* 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. Define the tag as a forward-reference if it is not defined.
...@@ -9129,7 +9181,6 @@ xref_tag (enum tag_types tag_code, tree name, ...@@ -9129,7 +9181,6 @@ xref_tag (enum tag_types tag_code, tree name,
{ {
enum tree_code code; enum tree_code code;
tree t; tree t;
struct cp_binding_level *b = current_binding_level;
tree context = NULL_TREE; tree context = NULL_TREE;
timevar_push (TV_NAME_LOOKUP); timevar_push (TV_NAME_LOOKUP);
...@@ -9152,48 +9203,18 @@ xref_tag (enum tag_types tag_code, tree name, ...@@ -9152,48 +9203,18 @@ xref_tag (enum tag_types tag_code, tree name,
gcc_unreachable (); gcc_unreachable ();
} }
if (! globalize) /* In case of anonymous name, xref_tag is only called to
{ make type node and push name. Name lookup is not required. */
/* If we know we are defining this tag, only look it up in if (ANON_AGGRNAME_P (name))
this scope and don't try to find it as a type. */ t = NULL_TREE;
t = lookup_tag (code, name, b, 1);
}
else else
{ t = lookup_and_check_tag (tag_code, name,
tree decl = lookup_name (name, 2); globalize, template_header_p);
if (decl && DECL_CLASS_TEMPLATE_P (decl))
decl = DECL_TEMPLATE_RESULT (decl);
if (decl && TREE_CODE (decl) == TYPE_DECL)
{
/* Two cases we need to consider when deciding if a class
template is allowed as an elaborated type specifier:
1. It is a self reference to its own class.
2. It comes with a template header.
For example:
template <class T> class C {
class C *c1; // DECL_SELF_REFERENCE_P is true
class D;
};
template <class U> class C; // template_header_p is true
template <class T> class C<T>::D {
class C *c2; // DECL_SELF_REFERENCE_P is true
}; */
t = check_elaborated_type_specifier (tag_code,
decl,
template_header_p
| DECL_SELF_REFERENCE_P (decl));
if (t == error_mark_node) if (t == error_mark_node)
POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, error_mark_node); POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, error_mark_node);
}
else
t = NULL_TREE;
if (t && current_class_type 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, ...@@ -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 ...@@ -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)
{ {
......
...@@ -43,7 +43,7 @@ struct scope_binding { ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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)
......
...@@ -303,6 +303,7 @@ extern tree lookup_tag (enum tree_code, tree, cxx_scope *, int); ...@@ -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);
......
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.
......
...@@ -3,10 +3,10 @@ ...@@ -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;
......
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 "" }
......
...@@ -2,6 +2,6 @@ struct A {}; ...@@ -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 "" }
}; };
...@@ -2,5 +2,5 @@ ...@@ -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" }
...@@ -4,7 +4,7 @@ ...@@ -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" }
// 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" }
...@@ -2,6 +2,6 @@ ...@@ -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" }
...@@ -7,6 +7,6 @@ ...@@ -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" }
}; };
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" }
// { 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" }
...@@ -7,8 +7,8 @@ ...@@ -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;
...@@ -37,7 +37,7 @@ struct S { ...@@ -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
......
// { 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
......
...@@ -17,7 +17,7 @@ class X { ...@@ -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;
}; };
......
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