Patchwork PR c++/51145 - Alias template in elaborated-type-specifier

login
register
mail settings
Submitter Dodji Seketeli
Date Nov. 21, 2011, 4:41 p.m.
Message ID <m339dhjumo.fsf@redhat.com>
Download mbox | patch
Permalink /patch/126895/
State New
Headers show

Comments

Dodji Seketeli - Nov. 21, 2011, 4:41 p.m.
Jason Merrill <jason@redhat.com> writes:

> See my comment in the PR.

Yes, sorry I have missed it.

Here is an updated patch hopefully addressing that comment.  I have also
updated a bunch of tests as a result of the change from error to note.

Bootstrapped and tested on x86_64-unknown-linux-gnu against trunk.

From: Dodji Seketeli <dodji@redhat.com>
Date: Fri, 18 Nov 2011 00:50:21 +0100
Subject: [PATCH] PR c++/51145 - Alias template in elaborated-type-specifier
 accepted

gcc/cp/

	PR c++/51145
	* decl.c (check_elaborated_type_specifier): Gracefully handle
	error_mark_node.  Accept bound template template parameters.
	Update diagnostics for alias template specializations.  Update
	comment.
	* parser.c (cp_parser_elaborated_type_specifier): Use
	check_elaborated_type_specifier for simple-template-ids as well.

gcc/testsuite/

	PR c++/51145
	* g++.dg/cpp0x/alias-decl-14.C: New test.
	* g++.dg/cpp0x/alias-decl-2.C: Adjust for tests that were wrongly
	passing before.
	* g++.dg/cpp0x/alias-decl-10.C: Likewise and adjust for diagnostic
	change.
	* g++.dg/ext/attrib27.C: Adjust for diagnostic change.
	* g++.dg/lookup/struct1.C: Likewise.
	* g++.dg/parse/elab1.C: Likewise.
	* g++.dg/parse/elab2.C: Likewise.
	* g++.dg/parse/int-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/crash26.C: Likewise.
	* g++.dg/template/nontype4.C: Likewise.
	* g++.old-deja/g++.benjamin/typedef01.C: Likewise.
	* g++.old-deja/g++.brendan/line1.C: Likewise.
	* g++.old-deja/g++.other/elab1.C: Likewise.
	* g++.old-deja/g++.other/syntax4.C: Likewise.
---
 gcc/cp/decl.c                                      |   21 ++++++++++++++++---
 gcc/cp/parser.c                                    |    3 +-
 gcc/testsuite/g++.dg/cpp0x/alias-decl-10.C         |   16 +++++++++++---
 gcc/testsuite/g++.dg/cpp0x/alias-decl-14.C         |   14 +++++++++++++
 gcc/testsuite/g++.dg/cpp0x/alias-decl-2.C          |    2 +-
 gcc/testsuite/g++.dg/ext/attrib27.C                |    2 +-
 gcc/testsuite/g++.dg/lookup/struct1.C              |    4 +-
 gcc/testsuite/g++.dg/parse/elab1.C                 |    2 +-
 gcc/testsuite/g++.dg/parse/elab2.C                 |    2 +-
 gcc/testsuite/g++.dg/parse/int-as-enum1.C          |    2 +-
 gcc/testsuite/g++.dg/parse/typedef1.C              |    2 +-
 gcc/testsuite/g++.dg/parse/typedef3.C              |    2 +-
 gcc/testsuite/g++.dg/parse/typedef4.C              |    2 +-
 gcc/testsuite/g++.dg/parse/typedef5.C              |    2 +-
 gcc/testsuite/g++.dg/template/crash26.C            |    2 +-
 gcc/testsuite/g++.dg/template/nontype4.C           |    2 +-
 .../g++.old-deja/g++.benjamin/typedef01.C          |    4 +-
 gcc/testsuite/g++.old-deja/g++.brendan/line1.C     |    2 +-
 gcc/testsuite/g++.old-deja/g++.other/elab1.C       |    2 +-
 gcc/testsuite/g++.old-deja/g++.other/syntax4.C     |    2 +-
 20 files changed, 63 insertions(+), 27 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp0x/alias-decl-14.C
Jason Merrill - Nov. 22, 2011, 2:15 p.m.
On 11/21/2011 11:41 AM, Dodji Seketeli wrote:
> -template class Ptr<int>;//{ dg-error "explicit instantiation|non-class templ|does not decl|anything" }
> +template class Ptr<int>;//{ dg-error "alias templ|specialization|Ptr<int>|after|class" }

You seem to be using | to mean .* here.  Let's choose one key phrase to 
check for.  :)

> -struct A { typedef int X; };            // { dg-error "previous declaration" }
> +struct A { typedef int X; };

Let's change dg-error to dg-message instead of dropping the check 
entirely on at least one of these tests to avoid a diagnostic quality 
regression.

OK with those changes.

Jason

Patch

diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index b77963b..8406432 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -11342,6 +11342,9 @@  check_elaborated_type_specifier (enum tag_types tag_code,
 {
   tree type;
 
+  if (decl == error_mark_node)
+    return error_mark_node;
+
   /* In the case of:
 
        struct S { struct S *p; };
@@ -11361,10 +11364,15 @@  check_elaborated_type_specifier (enum tag_types tag_code,
 	     type, tag_name (tag_code));
       return error_mark_node;
     }
+  /* Accept bound template template parameters.  */
+  else if (allow_template_p
+	   && TREE_CODE (type) == BOUND_TEMPLATE_TEMPLATE_PARM)
+    ;
   /*   [dcl.type.elab]
 
-       If the identifier resolves to a typedef-name or a template
-       type-parameter, the elaborated-type-specifier is ill-formed.
+       If the identifier resolves to a typedef-name or the
+       simple-template-id resolves to an alias template
+       specialization, the elaborated-type-specifier is ill-formed.
 
      In other words, the only legitimate declaration to use in the
      elaborated type specifier is the implicit typedef created when
@@ -11373,8 +11381,13 @@  check_elaborated_type_specifier (enum tag_types tag_code,
 	   && !DECL_SELF_REFERENCE_P (decl)
 	   && tag_code != typename_type)
     {
-      error ("using typedef-name %qD after %qs", decl, tag_name (tag_code));
-      error ("%q+D has a previous declaration here", decl);
+      if (alias_template_specialization_p (type))
+	error ("using alias template specialization %qT after %qs",
+	       type, tag_name (tag_code));
+      else
+	error ("using typedef-name %qD after %qs", decl, tag_name (tag_code));
+      inform (DECL_SOURCE_LOCATION (decl),
+	      "%qD has a previous declaration here", decl);
       return error_mark_node;
     }
   else if (TREE_CODE (type) != RECORD_TYPE
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index f839112..08b9c13 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -13933,7 +13933,8 @@  cp_parser_elaborated_type_specifier (cp_parser* parser,
       else if (tag_type == typename_type && TREE_CODE (decl) != TYPE_DECL)
         type = NULL_TREE; 
       else 
-	type = TREE_TYPE (decl);
+	type = check_elaborated_type_specifier (tag_type, decl,
+						/*allow_template_p=*/true);
     }
 
   if (!type)
diff --git a/gcc/testsuite/g++.dg/cpp0x/alias-decl-10.C b/gcc/testsuite/g++.dg/cpp0x/alias-decl-10.C
index 856e429..6adb785 100644
--- a/gcc/testsuite/g++.dg/cpp0x/alias-decl-10.C
+++ b/gcc/testsuite/g++.dg/cpp0x/alias-decl-10.C
@@ -3,16 +3,24 @@ 
 template <class T> using Ptr = T*;
 Ptr<unsigned>; // { dg-error "does not declare anything" }
 Ptr<char><int>; // { dg-error "not a template|does not declare anything" }
-template class Ptr<int>;//{ dg-error "explicit instantiation|non-class templ|does not decl|anything" }
+template class Ptr<int>;//{ dg-error "alias templ|specialization|Ptr<int>|after|class" }
 
 template <class T> using Arg = T;
 struct A {};
-template class Arg<A>;// { dg-error "explicit instantiation|non-class templ" }
+template class Arg<A>;// { dg-error "alias templ|specialization|Arg<A>|after|class" }
 
 template <template <class> class TT, class T> using Instantiate = TT<T>;
 template <class> struct Vector {};
-template class Instantiate<Vector, int>; // OK Vector<int> can be explicitely instantiated
+
+// The below is not OK, because of [dcl.type.elab]:
+// 
+//     If the identifier resolves to a typedef-name or the
+//     simple-template-id resolves to an alias template
+//     specialization, the elaborated-type-specifier is ill-formed.
+//
+template class Instantiate<Vector, int>;//{ dg-error "alias templ|after|class" }
 
 template <class T> struct S {};
 template<class T> using SFor = S<T>;
-template class SFor<int>; // OK, S<int> can be explicitely instantiated
+// Likewise, this is not OK.
+template class SFor<int>; //{ dg-error "alias tmpl|after|class" }
diff --git a/gcc/testsuite/g++.dg/cpp0x/alias-decl-14.C b/gcc/testsuite/g++.dg/cpp0x/alias-decl-14.C
new file mode 100644
index 0000000..485802e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/alias-decl-14.C
@@ -0,0 +1,14 @@ 
+// Origin: PR c++/51145
+// { dg-options "-std=c++0x" }
+
+struct A {};
+
+template<class>
+using X = A;
+
+struct X<int>* px; // { dg-error "invalid|alias|specialization|X<int>|after struct" }
+
+template<int>
+using Y = A;
+
+struct Y<0>* py;// { dg-error "invalid|alias|specialization|Y<0>|after struct" }
diff --git a/gcc/testsuite/g++.dg/cpp0x/alias-decl-2.C b/gcc/testsuite/g++.dg/cpp0x/alias-decl-2.C
index 2e03dd8..1d5a996 100644
--- a/gcc/testsuite/g++.dg/cpp0x/alias-decl-2.C
+++ b/gcc/testsuite/g++.dg/cpp0x/alias-decl-2.C
@@ -6,7 +6,7 @@  template<class T> using AS0 = S0<T>;
 template<template<class> class TT>
 void f(TT<int>);
 
-template class AS0<char>;
+template class AS0<char>; // { dg-error "alias templ|specialization|after|class" }
 
 void
 foo()
diff --git a/gcc/testsuite/g++.dg/ext/attrib27.C b/gcc/testsuite/g++.dg/ext/attrib27.C
index 4f629aa..c56c666 100644
--- a/gcc/testsuite/g++.dg/ext/attrib27.C
+++ b/gcc/testsuite/g++.dg/ext/attrib27.C
@@ -1,5 +1,5 @@ 
 //PR c++/29980
 
-struct A { typedef int X; };            // { dg-error "previous declaration" }
+struct A { typedef int X; };
 
 struct __attribute__((unused)) A::X;    // { dg-error "typedef-name" }
diff --git a/gcc/testsuite/g++.dg/lookup/struct1.C b/gcc/testsuite/g++.dg/lookup/struct1.C
index f4b83ec..33082ef 100644
--- a/gcc/testsuite/g++.dg/lookup/struct1.C
+++ b/gcc/testsuite/g++.dg/lookup/struct1.C
@@ -2,10 +2,10 @@ 
 // the definition of C.
 
 struct A;
-typedef struct A B;		// { dg-error "previous declaration" }
+typedef struct A B;
 struct B;			// { dg-error "using typedef-name" }
 
-typedef struct { int i; } C;	// { dg-error "previous declaration" }
+typedef struct { int i; } C;
 struct C;			// { dg-error "using typedef-name" }
 
 struct D;
diff --git a/gcc/testsuite/g++.dg/parse/elab1.C b/gcc/testsuite/g++.dg/parse/elab1.C
index 92fcd1c..2997eef 100644
--- a/gcc/testsuite/g++.dg/parse/elab1.C
+++ b/gcc/testsuite/g++.dg/parse/elab1.C
@@ -1,6 +1,6 @@ 
 namespace Name {
 
-    typedef void *(*Function)( void *, int ); // { dg-error "previous declaration" }
+    typedef void *(*Function)( void *, int );
 
     struct Foo {
       struct Function xyz[5]; // { dg-error "" }
diff --git a/gcc/testsuite/g++.dg/parse/elab2.C b/gcc/testsuite/g++.dg/parse/elab2.C
index 6b42aed..69273a3 100644
--- a/gcc/testsuite/g++.dg/parse/elab2.C
+++ b/gcc/testsuite/g++.dg/parse/elab2.C
@@ -2,6 +2,6 @@  struct A {};
 
 struct B
 {
-  typedef A T; // { dg-error "previous declaration" }
+  typedef A T;
   friend struct T; // { dg-error "" }
 };
diff --git a/gcc/testsuite/g++.dg/parse/int-as-enum1.C b/gcc/testsuite/g++.dg/parse/int-as-enum1.C
index 7c37eb0..ea77f10 100644
--- a/gcc/testsuite/g++.dg/parse/int-as-enum1.C
+++ b/gcc/testsuite/g++.dg/parse/int-as-enum1.C
@@ -2,5 +2,5 @@ 
 // Origin: <wanderer@rsu.ru>
 // { dg-do compile }
 
-typedef int A;	// { dg-error "previous" }
+typedef int A;
 enum ::A {};	// { dg-error "typedef-name|expected unqualified-id" }
diff --git a/gcc/testsuite/g++.dg/parse/typedef1.C b/gcc/testsuite/g++.dg/parse/typedef1.C
index c4fbb95..b2e8dba 100644
--- a/gcc/testsuite/g++.dg/parse/typedef1.C
+++ b/gcc/testsuite/g++.dg/parse/typedef1.C
@@ -1,3 +1,3 @@ 
 // PR c++/6477
-typedef struct A_ *A;	// { dg-error "previous declaration" }
+typedef struct A_ *A;
 typedef struct A B;	// { dg-error "typedef|invalid type" }
diff --git a/gcc/testsuite/g++.dg/parse/typedef3.C b/gcc/testsuite/g++.dg/parse/typedef3.C
index 6b4e531..eed45fe 100644
--- a/gcc/testsuite/g++.dg/parse/typedef3.C
+++ b/gcc/testsuite/g++.dg/parse/typedef3.C
@@ -2,6 +2,6 @@ 
 // Origin: Travis J.I. Corcoran <tjic@permabit.com>
 // { dg-do compile }
 
-struct A { typedef A* Ptr; };	// { dg-error "previous declaration" }
+struct A { typedef A* Ptr; };
 
 struct A::Ptr;			// { dg-error "typedef|not declare anything" }
diff --git a/gcc/testsuite/g++.dg/parse/typedef4.C b/gcc/testsuite/g++.dg/parse/typedef4.C
index 8599fd1..c460964 100644
--- a/gcc/testsuite/g++.dg/parse/typedef4.C
+++ b/gcc/testsuite/g++.dg/parse/typedef4.C
@@ -7,6 +7,6 @@ 
 template<class T> class smart_ptr2 {
     T* real_ptr;
  public:
-    typedef typename T::subT  td; // { dg-error "previous declaration" }
+    typedef typename T::subT  td;
     friend class td; // { dg-error "typedef|not name a class" }
 };
diff --git a/gcc/testsuite/g++.dg/parse/typedef5.C b/gcc/testsuite/g++.dg/parse/typedef5.C
index 7079f37..b7ed0e9 100644
--- a/gcc/testsuite/g++.dg/parse/typedef5.C
+++ b/gcc/testsuite/g++.dg/parse/typedef5.C
@@ -1,6 +1,6 @@ 
 namespace A
 {
-  typedef int T;	// { dg-error "previous declaration" }
+  typedef int T;
 }
 
 class A::T x;		// { dg-error "using typedef-name|invalid type" }
diff --git a/gcc/testsuite/g++.dg/template/crash26.C b/gcc/testsuite/g++.dg/template/crash26.C
index f1bc399..ad0f8fd 100644
--- a/gcc/testsuite/g++.dg/template/crash26.C
+++ b/gcc/testsuite/g++.dg/template/crash26.C
@@ -4,5 +4,5 @@ 
 
 // PR c++/18471: ICE redeclaration of typedef as class template
 
-typedef int X;			// { dg-error "previous" }
+typedef int X;
 template<X> struct X {};	// { dg-error "typedef-name" }
diff --git a/gcc/testsuite/g++.dg/template/nontype4.C b/gcc/testsuite/g++.dg/template/nontype4.C
index ab39ed4..c783992 100644
--- a/gcc/testsuite/g++.dg/template/nontype4.C
+++ b/gcc/testsuite/g++.dg/template/nontype4.C
@@ -7,7 +7,7 @@ 
 
 template <int> struct A
 {
-    typedef A<0> B;		// { dg-error "previous declaration" }
+    typedef A<0> B;
     template <B> struct B {};	// { dg-error "not a valid type|typedef" }
 };
 
diff --git a/gcc/testsuite/g++.old-deja/g++.benjamin/typedef01.C b/gcc/testsuite/g++.old-deja/g++.benjamin/typedef01.C
index 79a965b..ad53de6 100644
--- a/gcc/testsuite/g++.old-deja/g++.benjamin/typedef01.C
+++ b/gcc/testsuite/g++.old-deja/g++.benjamin/typedef01.C
@@ -18,7 +18,7 @@  typedef I I;
 //p3--cannot redefine to a different type in a given scope
 class complex2 { /* ... */ };// { dg-error "" } .*
 typedef int complex2;// { dg-error "" } .*
-typedef int complex3;// { dg-error "" } .*
+typedef int complex3;
 class complex3 { /* ... */ };// { dg-error "" } .*
 
 
@@ -37,7 +37,7 @@  struct S {
   ~S();
 };
 
-typedef struct S T;		// { dg-error "previous declaration" }
+typedef struct S T;
 
 S a = T();                      // OK 
 struct T * p;                   // { dg-error "" } using typedef after struct
diff --git a/gcc/testsuite/g++.old-deja/g++.brendan/line1.C b/gcc/testsuite/g++.old-deja/g++.brendan/line1.C
index b14ed8e..581f1a8 100644
--- a/gcc/testsuite/g++.old-deja/g++.brendan/line1.C
+++ b/gcc/testsuite/g++.old-deja/g++.brendan/line1.C
@@ -1,4 +1,4 @@ 
 // { dg-do assemble  }
 // GROUPS passed error-messages
-typedef struct s S;// { dg-error "" }  previous.*
+typedef struct s S;
 struct S { int member:1; };  // the lineno for this should be 2, not 0// { dg-error "" }  conflicting types.*
diff --git a/gcc/testsuite/g++.old-deja/g++.other/elab1.C b/gcc/testsuite/g++.old-deja/g++.other/elab1.C
index 5588651..f5f266c 100644
--- a/gcc/testsuite/g++.old-deja/g++.other/elab1.C
+++ b/gcc/testsuite/g++.old-deja/g++.other/elab1.C
@@ -1,5 +1,5 @@ 
 // { dg-do assemble  }
-typedef struct {} S; // { dg-error "" } Previous declaration of S
+typedef struct {} S;
 
 S s1;
 struct S* s2; // { dg-error "" } S is a typedef name
diff --git a/gcc/testsuite/g++.old-deja/g++.other/syntax4.C b/gcc/testsuite/g++.old-deja/g++.other/syntax4.C
index 7aed1f5..d323ff0 100644
--- a/gcc/testsuite/g++.old-deja/g++.other/syntax4.C
+++ b/gcc/testsuite/g++.old-deja/g++.other/syntax4.C
@@ -17,7 +17,7 @@  class X {
 
 class Y {
   public:
-  typedef ::X W;   // { dg-error "" } previous declaration
+  typedef ::X W;
   class Z;
 };