Jason Merrill <ja...@redhat.com> writes: > 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. :)
Actually, I wanted to avoid the verbosity of \[^\n\r\]*, as .* is so greedy that it eats even end of lines. Now I just did bite the bullet and used \[^\n\r\]* instead. > >> -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. I did the change on all the tests. > OK with those changes. Thanks. I am running the test suite again, just in case, with the patch below. I'll commit it tomorrow if it passes. From: Dodji Seketeli <do...@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/ChangeLog | 10 ++++++++ gcc/cp/decl.c | 21 ++++++++++++++--- gcc/cp/parser.c | 3 +- gcc/testsuite/ChangeLog | 24 ++++++++++++++++++++ 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 +- 22 files changed, 97 insertions(+), 27 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp0x/alias-decl-14.C 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 d0adaa0..2fdd675 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -13960,7 +13960,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..733e791 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 template specialization\[^\n\r\]*after\[^\n\r\]*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\[^\n\r\]*specialization\[^\n\r\]*Arg<A>\[^\n\r\]*after\[^\n\r\]*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 template specialization\[^\n\r\]*after\[^\n\r\]*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 template specialization\[^\n\r\]*after\[^\n\r\]*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..1a99802 --- /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 "using\[^\n\r\]*alias\[^\n\r\]*specialization\[^\n\r\]*X<int>\[^\n\r\]*after\[^\n\r\]*struct|invalid type in declaration before\[^\n\r\]*;" } + +template<int> +using Y = A; + +struct Y<0>* py;// { dg-error "alias\[^\n\r\]*specialization\[^\n\r\]*Y<0>\[^\n\r\]*after\[^\n\r\]*struct|invalid type in declaration before\[^\n\r\]*;" } diff --git a/gcc/testsuite/g++.dg/cpp0x/alias-decl-2.C b/gcc/testsuite/g++.dg/cpp0x/alias-decl-2.C index 2e03dd8..6b5b42f 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\[^\n\r\]*specialization\[^\n\r\]*after\[^\n\r\]*class" } void foo() diff --git a/gcc/testsuite/g++.dg/ext/attrib27.C b/gcc/testsuite/g++.dg/ext/attrib27.C index 4f629aa..b770c1c 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; }; // { dg-message "previous declaration" } 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..7c1e38c 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; // { dg-message "previous declaration" } struct B; // { dg-error "using typedef-name" } -typedef struct { int i; } C; // { dg-error "previous declaration" } +typedef struct { int i; } C; // { dg-message "previous declaration" } 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..8108e1d 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 ); // { dg-message "previous declaration" } 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..bf59f1b 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; // { dg-message "previous declaration" } 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..c5ed261 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: <wande...@rsu.ru> // { dg-do compile } -typedef int A; // { dg-error "previous" } +typedef int A; // { dg-message "previous" } 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..4d6f5b4 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; // { dg-message "previous declaration" } 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..3f6a7cb 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 <t...@permabit.com> // { dg-do compile } -struct A { typedef A* Ptr; }; // { dg-error "previous declaration" } +struct A { typedef A* Ptr; }; // { dg-message "previous declaration" } 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..d4cec7f 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; // { dg-message "previous declaration" } 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..ecd1d51 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; // { dg-message "previous declaration" } } 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..3be7ff9 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; // { dg-message "previous" } 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..41e3e22 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; // { dg-message "previous declaration" } 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..d5ed39a 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;// { dg-message "" } .* class complex3 { /* ... */ };// { dg-error "" } .* @@ -37,7 +37,7 @@ struct S { ~S(); }; -typedef struct S T; // { dg-error "previous declaration" } +typedef struct S T; // { dg-message "previous declaration" } 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..94130ec 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;// { dg-message "" } previous.* 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..f09ff6f 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; // { dg-message "" } Previous declaration of 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..445c539 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; // { dg-message "" } previous declaration class Z; }; -- 1.7.6.4 -- Dodji