Friend class name lookup 1/n, PR c++/18471
authorKriang Lerdsuwanakij <lerdsuwa@users.sourceforge.net>
Mon, 15 Nov 2004 10:34:06 +0000 (10:34 +0000)
committerKriang Lerdsuwanakij <lerdsuwa@gcc.gnu.org>
Mon, 15 Nov 2004 10:34:06 +0000 (10:34 +0000)
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

19 files changed:
gcc/cp/ChangeLog
gcc/cp/decl.c
gcc/cp/name-lookup.c
gcc/cp/name-lookup.h
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/lookup/struct1.C
gcc/testsuite/g++.dg/parse/elab1.C
gcc/testsuite/g++.dg/parse/elab2.C
gcc/testsuite/g++.dg/parse/int-as-enum1.C
gcc/testsuite/g++.dg/parse/struct-as-enum1.C
gcc/testsuite/g++.dg/parse/typedef1.C
gcc/testsuite/g++.dg/parse/typedef3.C
gcc/testsuite/g++.dg/parse/typedef4.C
gcc/testsuite/g++.dg/parse/typedef5.C
gcc/testsuite/g++.dg/template/crash26.C [new file with mode: 0644]
gcc/testsuite/g++.dg/template/nontype4.C
gcc/testsuite/g++.old-deja/g++.benjamin/typedef01.C
gcc/testsuite/g++.old-deja/g++.other/elab1.C
gcc/testsuite/g++.old-deja/g++.other/syntax4.C

index 9ca645afeb6f98fe07ce5f0648bae1714f0e8442..23d6b6a9b91428ea93fefa151739634b0df6de77 100644 (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>
 
        PR c++/17344
index 472b1f92e87292db503ba56597fe91d98ee460e7..f82ec87a1d3a3448e177e2dcc0e4a071ef10b500 100644 (file)
@@ -81,7 +81,8 @@ static hashval_t typename_hash (const void *);
 static int typename_compare (const void *, const void *);
 static tree local_variable_p_walkfn (tree *, int *, void *);
 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_globals_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);
 
+  /* 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]
 
        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
      elaborated type specifier is the implicit typedef created when
      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));
-      return IS_AGGR_TYPE (type) ? type : error_mark_node;
-    }
-
-  if (TREE_CODE (type) == TEMPLATE_TYPE_PARM)
-    {
-      error ("using template type parameter %qT after %qs",
-            type, tag_name (tag_code));
+      cp_error_at ("%qD has a previous declaration here", decl);
       return error_mark_node;
     }
   else if (TREE_CODE (type) != RECORD_TYPE
@@ -9081,12 +9084,14 @@ check_elaborated_type_specifier (enum tag_types tag_code,
           && tag_code != enum_type)
     {
       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;
     }
   else if (TREE_CODE (type) != ENUMERAL_TYPE
           && tag_code == enum_type)
     {
       error ("%qT referred to as enum", type);
+      cp_error_at ("%qT has a previous declaration here", type);
       return error_mark_node;
     }
   else if (!allow_template_p
@@ -9110,6 +9115,53 @@ check_elaborated_type_specifier (enum tag_types tag_code,
   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.
    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,
 {
   enum tree_code code;
   tree t;
-  struct cp_binding_level *b = current_binding_level;
   tree context = NULL_TREE;
 
   timevar_push (TV_NAME_LOOKUP);
@@ -9152,90 +9203,59 @@ xref_tag (enum tag_types tag_code, tree name,
       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);
-    }
+  /* 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
-    {
-      tree decl = lookup_name (name, 2);
+    t = lookup_and_check_tag  (tag_code, name,
+                              globalize, template_header_p);
 
-      if (decl && DECL_CLASS_TEMPLATE_P (decl))
-       decl = DECL_TEMPLATE_RESULT (decl);
+  if (t == error_mark_node)
+    POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, error_mark_node);
 
-      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)
-           POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, error_mark_node);
-       }
-      else
-       t = NULL_TREE;
-
-      if (t && current_class_type
-         && template_class_depth (current_class_type)
-         && template_header_p)
-       {
-         /* Since GLOBALIZE is nonzero, we are not looking at a
-            definition of this tag.  Since, in addition, we are currently
-            processing a (member) template declaration of a template
-            class, we must be very careful; consider:
+  if (globalize && t && current_class_type
+      && template_class_depth (current_class_type)
+      && template_header_p)
+    {
+      /* Since GLOBALIZE is nonzero, we are not looking at a
+        definition of this tag.  Since, in addition, we are currently
+        processing a (member) template declaration of a template
+        class, we must be very careful; consider:
 
-              template <class X>
-              struct S1
+          template <class X>
+          struct S1
 
-              template <class U>
-              struct S2
-              { template <class V>
-              friend struct S1; };
+          template <class U>
+          struct S2
+          { template <class V>
+          friend struct S1; };
 
-            Here, the S2::S1 declaration should not be confused with the
-            outer declaration.  In particular, the inner version should
-            have a template parameter of level 2, not level 1.  This
-            would be particularly important if the member declaration
-            were instead:
+        Here, the S2::S1 declaration should not be confused with the
+        outer declaration.  In particular, the inner version should
+        have a template parameter of level 2, not level 1.  This
+        would be particularly important if the member declaration
+        were instead:
 
-              template <class V = U> friend struct S1;
+          template <class V = U> friend struct S1;
 
-            say, when we should tsubst into `U' when instantiating
-            S2.  On the other hand, when presented with:
+        say, when we should tsubst into `U' when instantiating
+        S2.  On the other hand, when presented with:
 
-                template <class T>
-                struct S1 {
-                  template <class U>
-                  struct S2 {};
-                  template <class U>
-                  friend struct S2;
-                };
+          template <class T>
+          struct S1 {
+            template <class U>
+            struct S2 {};
+            template <class U>
+            friend struct S2;
+          };
 
-              we must find the inner binding eventually.  We
-             accomplish this by making sure that the new type we
-             create to represent this declaration has the right
-             TYPE_CONTEXT.  */
-         context = TYPE_CONTEXT (t);
-         t = NULL_TREE;
-       }
+        we must find the inner binding eventually.  We
+        accomplish this by making sure that the new type we
+        create to represent this declaration has the right
+        TYPE_CONTEXT.  */
+      context = TYPE_CONTEXT (t);
+      t = NULL_TREE;
     }
 
   if (! t)
@@ -9482,14 +9502,13 @@ tree
 start_enum (tree name)
 {
   tree enumtype = NULL_TREE;
-  struct cp_binding_level *b = current_binding_level;
 
   /* If this is the real definition for a previous forward reference,
      fill in the contents in the same object that used to be the
      forward reference.  */
 
   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)
     {
index 9031f05c2a1f70ffa9bd7eb52770669cbd9fb9b8..0abe1eca9cf9a5fd2feb9f17833ccfbc5d377091 100644 (file)
@@ -43,7 +43,7 @@ struct scope_binding {
 static cxx_scope *innermost_nonclass_level (void);
 static tree select_decl (const struct scope_binding *, int);
 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 bool lookup_using_namespace (tree, struct scope_binding *, tree,
                                     tree, int);
@@ -678,7 +678,7 @@ pushdecl (tree x)
       if (DECL_NAMESPACE_SCOPE_P (x) && namespace_bindings_p ())
        t = namespace_binding (name, DECL_CONTEXT (x));
       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
         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.  */
   b = innermost_nonclass_level ();
 
-  if (lookup_name_current_level (id))
+  if (lookup_name_innermost_nonclass_level (id))
     {
       /* Supplement the existing binding.  */
       if (!supplement_binding (IDENTIFIER_BINDING (id), decl))
@@ -1998,7 +1998,7 @@ push_overloaded_decl (tree decl, int flags)
   if (doing_global)
     old = namespace_binding (name, DECL_CONTEXT (decl));
   else
-    old = lookup_name_current_level (name);
+    old = lookup_name_innermost_nonclass_level (name);
 
   if (old)
     {
@@ -2286,7 +2286,7 @@ do_local_using_decl (tree decl, tree scope, tree name)
       && at_function_scope_p ())
     add_decl_expr (decl);
 
-  oldval = lookup_name_current_level (name);
+  oldval = lookup_name_innermost_nonclass_level (name);
   oldtype = lookup_type_current_level (name);
 
   do_nonmember_using_decl (scope, name, oldval, oldtype, &newval, &newtype);
@@ -4122,11 +4122,90 @@ lookup_name (tree name, int prefer_type)
                           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
    binding level.  */
 
 static tree
-lookup_name_current_level (tree name)
+lookup_name_innermost_nonclass_level (tree name)
 {
   struct cp_binding_level *b;
   tree t = NULL_TREE;
@@ -4164,7 +4243,7 @@ lookup_name_current_level (tree name)
   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
 lookup_type_current_level (tree name)
index 7c73f3f1d725916bd891e370dd1857e75b77eb87..b43fa1e4f323de2c0c101a19ca42e0033efe8d32 100644 (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_name        (tree, 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 void set_namespace_binding (tree, tree, tree);
 extern tree lookup_namespace_name (tree, tree);
index cc7cb25c074e02bd2cebccc79b769cd9b1fe8bb2..d3653718546c6ff3df52716dff003794a46815fe 100644 (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>
 
        * gcc.dg/intmax_t-1.c: XFAIL on Solaris 2.5.1.
index dd8d54b85d8fb3a1278ec87b5a91e8af842dc78b..f4b83ecf6b8b568287cf077ee70db88cff9e6baa 100644 (file)
@@ -3,10 +3,10 @@
 
 struct A;
 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" }
-struct C;                      // { dg-error "conflicting declaration" }
+struct C;                      // { dg-error "using typedef-name" }
 
 struct D;
 typedef struct D D;
index 2997eef62557cd77788f45c9478f2faa25b745ac..92fcd1ca69c425fafdb98dff4b983a02102121b0 100644 (file)
@@ -1,6 +1,6 @@
 namespace Name {
 
-    typedef void *(*Function)( void *, int );
+    typedef void *(*Function)( void *, int ); // { dg-error "previous declaration" }
 
     struct Foo {
       struct Function xyz[5]; // { dg-error "" }
index 69273a3fc3173a59cf9125bb570d7ac1a2a3a143..6b42aed67a4c3df37a6fe4b47c91748cec1c4757 100644 (file)
@@ -2,6 +2,6 @@ struct A {};
 
 struct B
 {
-  typedef A T;
+  typedef A T; // { dg-error "previous declaration" }
   friend struct T; // { dg-error "" }
 };
index 2bf9cc0ddb7ab4650c5567546b14993cbad3bf8c..7c37eb08792b0e71e2de5981862f5e1ebba6ea5c 100644 (file)
@@ -2,5 +2,5 @@
 // Origin: <wanderer@rsu.ru>
 // { dg-do compile }
 
-typedef int A;
-enum ::A {}; // { dg-error "" }
+typedef int A; // { dg-error "previous" }
+enum ::A {};   // { dg-error "typedef-name|expected unqualified-id" }
index 016c6035b93a53de27f3a45a7b8e221347595264..bc8c5b530f6b87fa5b19169700aea901566bbb02 100644 (file)
@@ -4,7 +4,7 @@
 
 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" }
index a01a66c1427ab9dd3cde1bb48067d35c10bba4db..c4fbb950cf1acf20fe8d27aa5601222e55068590 100644 (file)
@@ -1,3 +1,3 @@
 // PR c++/6477
-typedef struct A_ *A;
-typedef struct A B;    // { dg-error "" }
+typedef struct A_ *A;  // { dg-error "previous declaration" }
+typedef struct A B;    // { dg-error "typedef|invalid type" }
index 380b75305420b4255565202d1aa858bd94fd45d5..6b4e531b677293423d173b0ae4042d6fbf9575bc 100644 (file)
@@ -2,6 +2,6 @@
 // Origin: Travis J.I. Corcoran <tjic@permabit.com>
 // { 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" }
index 03f709a184d17c05602d028226450328634c6a61..8599fd1d88410ac36ceebeffbf12222024e7fed4 100644 (file)
@@ -7,6 +7,6 @@
 template<class T> class smart_ptr2 {
     T* real_ptr;
  public:
-    typedef typename T::subT  td;
-    friend class td; // { dg-error "typedef" }
+    typedef typename T::subT  td; // { dg-error "previous declaration" }
+    friend class td; // { dg-error "typedef|not name a class" }
 };
index 5f6b18ca395c8516fde7a83e4ff08666335dbc4f..22ba85e0aea561fc6b8f221967b208b412821001 100644 (file)
@@ -1,6 +1,6 @@
 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" }
diff --git a/gcc/testsuite/g++.dg/template/crash26.C b/gcc/testsuite/g++.dg/template/crash26.C
new file mode 100644 (file)
index 0000000..f1bc399
--- /dev/null
@@ -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" }
index 43ef2b0ce6b6fd3d96e64b26fce268d2446a5fa7..ab39ed443976216cc6997a69e5ec7f7d7e80b088 100644 (file)
@@ -7,8 +7,8 @@
 
 template <int> struct A
 {
-    typedef A<0> B;            // { dg-error "not a valid type|conflict" }
-    template <B> struct B {};  // { dg-error "not a valid type|declaration" }
+    typedef A<0> B;            // { dg-error "previous declaration" }
+    template <B> struct B {};  // { dg-error "not a valid type|typedef" }
 };
 
-A<0> a;                                // { dg-error "instantiated" }
+A<0> a;
index 466b866eeed8fa34b67cec3c6628730f0efdc3d4..79a965b16f2539664152cca2677ef8e33ea20899 100644 (file)
@@ -37,7 +37,7 @@ struct S {
   ~S();
 };
 
-typedef struct S T;
+typedef struct S T;            // { dg-error "previous declaration" }
 
 S a = T();                      // OK 
 struct T * p;                   // { dg-error "" } using typedef after struct
index f5f266c54899c9a7c6bbee71d04bd5f331abef11..5588651dfe5fef4152fe6ca9423b0fbebed92df8 100644 (file)
@@ -1,5 +1,5 @@
 // { dg-do assemble  }
-typedef struct {} S;
+typedef struct {} S; // { dg-error "" } Previous declaration of S
 
 S s1;
 struct S* s2; // { dg-error "" } S is a typedef name
index d323ff0dce848b36f7a5b4a85806ebd6aa9a131f..7aed1f5b14070c963f49629bf9268e5247b8c248 100644 (file)
@@ -17,7 +17,7 @@ class X {
 
 class Y {
   public:
-  typedef ::X W;
+  typedef ::X W;   // { dg-error "" } previous declaration
   class Z;
 };