diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 9dc93f53fe716..cffcac2bfa3e7 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -251,6 +251,9 @@ Resolutions to C++ Defect Reports - P0522 implementation is enabled by default in all language versions, and provisional wording for CWG2398 is implemented. +- Clang now requires a template argument list after a template keyword. + (`CWG96: Syntactic disambiguation using the template keyword `_). + C Language Changes ------------------ diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td index f8328be5890dd..d8c3fee7841f4 100644 --- a/clang/include/clang/Basic/DiagnosticParseKinds.td +++ b/clang/include/clang/Basic/DiagnosticParseKinds.td @@ -887,6 +887,10 @@ def err_requires_expr_in_simple_requirement : Error< "requires expression in requirement body; did " "you intend to place it in a nested requirement? (add another 'requires' " "before the expression)">; +def missing_template_arg_list_after_template_kw : Extension< + "a template argument list is expected after a name prefixed by the template " + "keyword">, InGroup>, + DefaultError; def err_missing_dependent_template_keyword : Error< "use 'template' keyword to treat '%0' as a dependent template name">; diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp index e149b1a0fb5ef..1558e3dcb8974 100644 --- a/clang/lib/Parse/ParseExprCXX.cpp +++ b/clang/lib/Parse/ParseExprCXX.cpp @@ -14,6 +14,7 @@ #include "clang/AST/DeclTemplate.h" #include "clang/AST/ExprCXX.h" #include "clang/Basic/PrettyStackTrace.h" +#include "clang/Basic/TemplateKinds.h" #include "clang/Basic/TokenKinds.h" #include "clang/Lex/LiteralSupport.h" #include "clang/Parse/ParseDiagnostic.h" @@ -3026,13 +3027,23 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, ParsedType ObjectType, SS, ObjectType, ObjectHadErrors, TemplateKWLoc ? *TemplateKWLoc : SourceLocation(), Id, IdLoc, EnteringContext, Result, TemplateSpecified); - else if (TemplateSpecified && - Actions.ActOnTemplateName( - getCurScope(), SS, *TemplateKWLoc, Result, ObjectType, - EnteringContext, Template, - /*AllowInjectedClassName*/ true) == TNK_Non_template) - return true; + if (TemplateSpecified) { + TemplateNameKind TNK = + Actions.ActOnTemplateName(getCurScope(), SS, *TemplateKWLoc, Result, + ObjectType, EnteringContext, Template, + /*AllowInjectedClassName=*/true); + if (TNK == TNK_Non_template) + return true; + + // C++2c [tem.names]p6 + // A name prefixed by the keyword template shall be followed by a template + // argument list or refer to a class template or an alias template. + if ((TNK == TNK_Function_template || TNK == TNK_Dependent_template_name || + TNK == TNK_Var_template) && + !Tok.is(tok::less)) + Diag(IdLoc, diag::missing_template_arg_list_after_template_kw); + } return false; } diff --git a/clang/test/CXX/drs/cwg0xx.cpp b/clang/test/CXX/drs/cwg0xx.cpp index 6c600bbc7c3f6..fe3e0cfc1d421 100644 --- a/clang/test/CXX/drs/cwg0xx.cpp +++ b/clang/test/CXX/drs/cwg0xx.cpp @@ -1404,7 +1404,7 @@ namespace cwg95 { // cwg95: 3.3 // expected-note@#cwg95-C-f {{implicitly declared private here}} } -namespace cwg96 { // cwg96: no +namespace cwg96 { // cwg96: sup P1787 struct A { void f(int); template int f(T); @@ -1419,6 +1419,7 @@ namespace cwg96 { // cwg96: no // name a class template. // FIXME: What about alias templates? int k2 = a.template f(1); + // expected-error@-1 {{a template argument list is expected after a name prefixed by the template keyword}} A::template S s; B b; } diff --git a/clang/test/SemaCXX/cxx1y-variable-templates_in_class.cpp b/clang/test/SemaCXX/cxx1y-variable-templates_in_class.cpp index f42c812a860d0..2196bfb6eaac3 100644 --- a/clang/test/SemaCXX/cxx1y-variable-templates_in_class.cpp +++ b/clang/test/SemaCXX/cxx1y-variable-templates_in_class.cpp @@ -384,16 +384,16 @@ namespace dependent_static_var_template { struct A { template static int n; // expected-note 2{{here}} }; - int &r = A::template n; // expected-error {{use of variable template 'A::template n' requires template arguments}} + int &r = A::template n; // expected-error {{use of variable template 'A::template n' requires template arguments}} expected-error {{a template argument list is expected after a name prefixed by the template keyword}} template - int &f() { return T::template n; } // expected-error {{use of variable template 'A::template n' requires template arguments}} + int &f() { return T::template n; } // expected-error {{use of variable template 'A::template n' requires template arguments}} expected-error {{a template argument list is expected after a name prefixed by the template keyword}} int &s = f(); // expected-note {{instantiation of}} namespace B { template static int n; // expected-note {{here}} } - int &t = B::template n; // expected-error {{use of variable template 'B::template n' requires template arguments}} + int &t = B::template n; // expected-error {{use of variable template 'B::template n' requires template arguments}} expected-error {{a template argument list is expected after a name prefixed by the template keyword}} struct C { template static T G; diff --git a/clang/test/SemaCXX/template-specialization.cpp b/clang/test/SemaCXX/template-specialization.cpp index eabb84f2e13d3..1832aafa4b883 100644 --- a/clang/test/SemaCXX/template-specialization.cpp +++ b/clang/test/SemaCXX/template-specialization.cpp @@ -11,7 +11,7 @@ struct B { template static void foo() { int array[i]; - A::template bar(array[0]); // expected-error {{no matching function for call to 'bar'}} + A::template bar(array[0]); // expected-error {{a template argument list is expected after a name prefixed by the template keyword}} expected-error {{no matching function for call to 'bar'}} } }; diff --git a/clang/test/SemaTemplate/dependent-names.cpp b/clang/test/SemaTemplate/dependent-names.cpp index a7260b194462c..92620e862fe3a 100644 --- a/clang/test/SemaTemplate/dependent-names.cpp +++ b/clang/test/SemaTemplate/dependent-names.cpp @@ -420,7 +420,7 @@ template struct CT2 { template int CT2::X<>; // expected-error {{template parameter list matching the non-templated nested type 'CT2' should be empty}} namespace DependentTemplateIdWithNoArgs { - template void f() { T::template f(); } + template void f() { T::template f(); } // expected-error {{a template argument list is expected after a name prefixed by the template keyword}} struct X { template static void f(); }; @@ -431,7 +431,7 @@ namespace DependentUnresolvedUsingTemplate { template struct X : T { using T::foo; - void f() { this->template foo(); } // expected-error {{does not refer to a template}} + void f() { this->template foo(); } // expected-error {{does not refer to a template}} expected-error {{a template argument list is expected after a name prefixed by the template keyword}} void g() { this->template foo<>(); } // expected-error {{does not refer to a template}} void h() { this->template foo(); } // expected-error {{does not refer to a template}} }; @@ -450,7 +450,7 @@ namespace DependentUnresolvedUsingTemplate { namespace PR37680 { template struct b : a { using a::add; - template int add() { return this->template add(0); } + template int add() { return this->template add(0); } // expected-error {{a template argument list is expected after a name prefixed by the template keyword}} }; struct a { template int add(...); diff --git a/clang/test/SemaTemplate/template-id-expr.cpp b/clang/test/SemaTemplate/template-id-expr.cpp index ce40aade9cf17..6c98e29cdaa95 100644 --- a/clang/test/SemaTemplate/template-id-expr.cpp +++ b/clang/test/SemaTemplate/template-id-expr.cpp @@ -65,11 +65,11 @@ struct Y0 { template void f() { Y0::template f1(0); - Y0::template f1(0); - this->template f1(0); + Y0::template f1(0); // expected-error {{a template argument list is expected after a name prefixed by the template keyword}} + this->template f1(0); // expected-error {{a template argument list is expected after a name prefixed by the template keyword}} Y0::template f2(0); - Y0::template f2(0); + Y0::template f2(0); // expected-error {{a template argument list is expected after a name prefixed by the template keyword}} Y0::template f3(0); // expected-error {{'f3' following the 'template' keyword does not refer to a template}} Y0::template f3(); // expected-error {{'f3' following the 'template' keyword does not refer to a template}} @@ -77,11 +77,11 @@ struct Y0 { int x; x = Y0::f4(0); x = Y0::f4(0); // expected-error {{assigning to 'int' from incompatible type 'void'}} - x = Y0::template f4(0); // expected-error {{assigning to 'int' from incompatible type 'void'}} + x = Y0::template f4(0); // expected-error {{a template argument list is expected after a name prefixed by the template keyword}} expected-error {{assigning to 'int' from incompatible type 'void'}} x = this->f4(0); x = this->f4(0); // expected-error {{assigning to 'int' from incompatible type 'void'}} - x = this->template f4(0); // expected-error {{assigning to 'int' from incompatible type 'void'}} + x = this->template f4(0); // expected-error {{a template argument list is expected after a name prefixed by the template keyword}} expected-error {{assigning to 'int' from incompatible type 'void'}} } }; @@ -109,11 +109,11 @@ struct Y1 { template void f() { Y1::template f1(0); - Y1::template f1(0); - this->template f1(0); + Y1::template f1(0); // expected-error {{a template argument list is expected after a name prefixed by the template keyword}} + this->template f1(0); // expected-error {{a template argument list is expected after a name prefixed by the template keyword}} Y1::template f2(0); - Y1::template f2(0); + Y1::template f2(0); // expected-error {{a template argument list is expected after a name prefixed by the template keyword}} Y1::template f3(0); // expected-error {{'f3' following the 'template' keyword does not refer to a template}} Y1::template f3(); // expected-error {{'f3' following the 'template' keyword does not refer to a template}} @@ -121,11 +121,11 @@ struct Y1 { int x; x = Y1::f4(0); x = Y1::f4(0); // expected-error {{assigning to 'int' from incompatible type 'void'}} - x = Y1::template f4(0); // expected-error {{assigning to 'int' from incompatible type 'void'}} + x = Y1::template f4(0); // expected-error {{a template argument list is expected after a name prefixed by the template keyword}} expected-error {{assigning to 'int' from incompatible type 'void'}} x = this->f4(0); x = this->f4(0); // expected-error {{assigning to 'int' from incompatible type 'void'}} - x = this->template f4(0); // expected-error {{assigning to 'int' from incompatible type 'void'}} + x = this->template f4(0); // expected-error {{a template argument list is expected after a name prefixed by the template keyword}} expected-error {{assigning to 'int' from incompatible type 'void'}} } }; @@ -138,23 +138,23 @@ struct Y2 : Y1 { template void f(Y1 *p) { Y1::template f1(0); - Y1::template f1(0); - p->template f1(0); + Y1::template f1(0); // expected-error {{a template argument list is expected after a name prefixed by the template keyword}} + p->template f1(0); // expected-error {{a template argument list is expected after a name prefixed by the template keyword}} Y1::template f2(0); - Y1::template f2(0); + Y1::template f2(0); // expected-error {{a template argument list is expected after a name prefixed by the template keyword}} - Y1::template f3(0); // expected-error {{'f3' following the 'template' keyword does not refer to a template}} - Y1::template f3(); // expected-error {{'f3' following the 'template' keyword does not refer to a template}} + Y1::template f3(0); // expected-error {{'f3' following the 'template' keyword does not refer to a template}} expected-error {{a template argument list is expected after a name prefixed by the template keyword}} + Y1::template f3(); // expected-error {{'f3' following the 'template' keyword does not refer to a template}} expected-error {{a template argument list is expected after a name prefixed by the template keyword}} int x; x = Y1::f4(0); x = Y1::f4(0); // expected-error {{use 'template'}} expected-error {{assigning to 'int' from incompatible type 'void'}} - x = Y1::template f4(0); // expected-error {{assigning to 'int' from incompatible type 'void'}} + x = Y1::template f4(0); // expected-error {{assigning to 'int' from incompatible type 'void'}} expected-error {{a template argument list is expected after a name prefixed by the template keyword}} x = p->f4(0); x = p->f4(0); // expected-error {{assigning to 'int' from incompatible type 'void'}} expected-error {{use 'template'}} - x = p->template f4(0); // expected-error {{assigning to 'int' from incompatible type 'void'}} + x = p->template f4(0); // expected-error {{assigning to 'int' from incompatible type 'void'}} expected-error {{a template argument list is expected after a name prefixed by the template keyword}} } }; @@ -169,7 +169,7 @@ struct A { template void f5() { - A::template B::template b1(); // expected-error {{'b1' following the 'template' keyword does not refer to a template}} + A::template B::template b1(); // expected-error {{'b1' following the 'template' keyword does not refer to a template}} expected-error {{a template argument list is expected after a name prefixed by the template keyword}} } template void f5<0>(); // expected-note {{in instantiation of function template specialization 'f5<0>' requested here}} diff --git a/clang/test/SemaTemplate/template-id-printing.cpp b/clang/test/SemaTemplate/template-id-printing.cpp index d9fc7201eee06..44a33555f512d 100644 --- a/clang/test/SemaTemplate/template-id-printing.cpp +++ b/clang/test/SemaTemplate/template-id-printing.cpp @@ -99,8 +99,6 @@ template void test() { // CHECK: S::foo; S::foo; - // CHECK: S::template foo; - S::template foo; // CHECK: S::template foo<>; S::template foo<>; // CHECK: S::template foo; @@ -121,8 +119,6 @@ void test() { S s; // CHECK: s.foo; s.foo; - // CHECK: s.template foo; - s.template foo; // CHECK: s.template foo<>; s.template foo<>; // CHECK: s.template foo; @@ -130,12 +126,3 @@ void test() { } } // namespace DSME - -namespace DSDRE_withImplicitTemplateArgs { - -template void foo() { - // CHECK: T::template bar(); - T::template bar(); -} - -} // namespace DSDRE_withImplicitTemplateArgs diff --git a/clang/www/cxx_dr_status.html b/clang/www/cxx_dr_status.html index 4cce88fe0490f..32d7c39c49548 100755 --- a/clang/www/cxx_dr_status.html +++ b/clang/www/cxx_dr_status.html @@ -614,7 +614,7 @@

C++ defect report implementation status

96 C++11 Syntactic disambiguation using the template keyword - No + Superseded by P1787 97