https://github.com/evelez7 updated https://github.com/llvm/llvm-project/pull/80801
>From fd07c0a15eb45c3e7eb400026ea7702ae909a11e Mon Sep 17 00:00:00 2001 From: Erick Velez <erickvel...@gmail.com> Date: Mon, 5 Feb 2024 21:26:07 -0800 Subject: [PATCH 1/4] [clang] require template arg list after template kw Require a template argument list after an identifier prefixed by the template keyword. Introduced by CWG 96. Fixes #53095 --- .../clang/Basic/DiagnosticParseKinds.td | 3 ++ clang/lib/Parse/ParseExprCXX.cpp | 23 ++++++++---- clang/test/CXX/drs/dr0xx.cpp | 2 +- .../cxx1y-variable-templates_in_class.cpp | 6 ++-- .../test/SemaCXX/template-specialization.cpp | 2 +- clang/test/SemaTemplate/dependent-names.cpp | 6 ++-- clang/test/SemaTemplate/template-id-expr.cpp | 36 +++++++++---------- .../SemaTemplate/template-id-printing.cpp | 13 ------- 8 files changed, 46 insertions(+), 45 deletions(-) diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td index a30ab27566ec3e..159600f3e26dc0 100644 --- a/clang/include/clang/Basic/DiagnosticParseKinds.td +++ b/clang/include/clang/Basic/DiagnosticParseKinds.td @@ -868,6 +868,9 @@ 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 err_missing_template_arg_list_after_template_kw : Error< + "a template argument list is expected after a name prefixed by the template " + "keyword">; 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 fd262ff31e661a..b3a1a6f6cf80d0 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" @@ -2995,13 +2996,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++ [template.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::err_missing_template_arg_list_after_template_kw); + } return false; } diff --git a/clang/test/CXX/drs/dr0xx.cpp b/clang/test/CXX/drs/dr0xx.cpp index 5959f0a0c8dd65..127d45be5bda97 100644 --- a/clang/test/CXX/drs/dr0xx.cpp +++ b/clang/test/CXX/drs/dr0xx.cpp @@ -1414,7 +1414,7 @@ namespace dr96 { // dr96: no // FIXME: This is ill-formed, because 'f' is not a template-id and does not // name a class template. // FIXME: What about alias templates? - int k2 = a.template f(1); + int k2 = a.template f(1); // expected-error {{a template argument list is expected after a name prefixed by the template keyword}} A::template S<int> s; B<A::template S> b; } diff --git a/clang/test/SemaCXX/cxx1y-variable-templates_in_class.cpp b/clang/test/SemaCXX/cxx1y-variable-templates_in_class.cpp index af121a8b75d512..37dbe0b212eb6a 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<int = 0> static int n; // expected-note 2{{here}} }; - int &r = A::template n; // expected-error {{use of variable template 'n' requires template arguments}} + int &r = A::template n; // expected-error {{use of variable template 'n' requires template arguments}} expected-error {{a template argument list is expected after a name prefixed by the template keyword}} template<typename T> - int &f() { return T::template n; } // expected-error {{use of variable template 'n' requires template arguments}} + int &f() { return T::template n; } // expected-error {{use of variable template 'n' requires template arguments}} expected-error {{a template argument list is expected after a name prefixed by the template keyword}} int &s = f<A>(); // expected-note {{instantiation of}} namespace B { template<int = 0> static int n; // expected-note {{here}} } - int &t = B::template n; // expected-error {{use of variable template 'n' requires template arguments}} + int &t = B::template n; // expected-error {{use of variable template 'n' requires template arguments}} expected-error {{a template argument list is expected after a name prefixed by the template keyword}} struct C { template <class T> static T G; diff --git a/clang/test/SemaCXX/template-specialization.cpp b/clang/test/SemaCXX/template-specialization.cpp index 7b26ff9f5c5ba4..c57ca51538d8f9 100644 --- a/clang/test/SemaCXX/template-specialization.cpp +++ b/clang/test/SemaCXX/template-specialization.cpp @@ -11,7 +11,7 @@ struct B { template <int i> 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 641ec950054f57..5026004cdcc0c2 100644 --- a/clang/test/SemaTemplate/dependent-names.cpp +++ b/clang/test/SemaTemplate/dependent-names.cpp @@ -418,7 +418,7 @@ template <typename> struct CT2 { template <typename T> int CT2<int>::X<>; // expected-error {{template parameter list matching the non-templated nested type 'CT2<int>' should be empty}} namespace DependentTemplateIdWithNoArgs { - template<typename T> void f() { T::template f(); } + template<typename T> void f() { T::template f(); } // expected-error {{a template argument list is expected after a name prefixed by the template keyword}} struct X { template<int = 0> static void f(); }; @@ -429,7 +429,7 @@ namespace DependentUnresolvedUsingTemplate { template<typename T> 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<int>(); } // expected-error {{does not refer to a template}} }; @@ -448,7 +448,7 @@ namespace DependentUnresolvedUsingTemplate { namespace PR37680 { template <class a> struct b : a { using a::add; - template<int> int add() { return this->template add(0); } + template<int> 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<typename T = void> int add(...); diff --git a/clang/test/SemaTemplate/template-id-expr.cpp b/clang/test/SemaTemplate/template-id-expr.cpp index 0555d8b94504fb..3f1e889d78eeec 100644 --- a/clang/test/SemaTemplate/template-id-expr.cpp +++ b/clang/test/SemaTemplate/template-id-expr.cpp @@ -65,11 +65,11 @@ struct Y0 { template<typename U> void f() { Y0::template f1<U>(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<U>(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<int>(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<int>(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<typename U> void f() { Y1::template f1<U>(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<U>(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<int>(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<int>(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<T> { template<typename U> void f(Y1 *p) { Y1::template f1<U>(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<U>(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<int>(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<int>(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<int I> void f5() { - A::template B<I>::template b1(); // expected-error {{'b1' following the 'template' keyword does not refer to a template}} + A::template B<I>::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 047589b1ce4333..e004bd35e5a0c3 100644 --- a/clang/test/SemaTemplate/template-id-printing.cpp +++ b/clang/test/SemaTemplate/template-id-printing.cpp @@ -99,8 +99,6 @@ template <typename T> void test() { // CHECK: S<T>::foo; S<T>::foo; - // CHECK: S<T>::template foo; - S<T>::template foo; // CHECK: S<T>::template foo<>; S<T>::template foo<>; // CHECK: S<T>::template foo<T>; @@ -121,8 +119,6 @@ void test() { S<T> s; // CHECK: s.foo; s.foo; - // CHECK: s.template foo; - s.template foo; // CHECK: s.template foo<>; s.template foo<>; // CHECK: s.template foo<T>; @@ -130,12 +126,3 @@ void test() { } } // namespace DSME - -namespace DSDRE_withImplicitTemplateArgs { - -template <typename T> void foo() { - // CHECK: T::template bar(); - T::template bar(); -} - -} // namespace DSDRE_withImplicitTemplateArgs >From 4115b127b941028a6160cd1bbc9a7f77d667afbe Mon Sep 17 00:00:00 2001 From: Erick Velez <erickvel...@gmail.com> Date: Wed, 7 Feb 2024 11:35:47 -0800 Subject: [PATCH 2/4] change error to pedenatic warn, regen DR html --- clang/include/clang/Basic/DiagnosticParseKinds.td | 4 ++-- clang/lib/Parse/ParseExprCXX.cpp | 2 +- clang/test/CXX/drs/dr0xx.cpp | 5 +++-- clang/test/Misc/warning-flags.c | 2 +- clang/www/cxx_dr_status.html | 2 +- 5 files changed, 8 insertions(+), 7 deletions(-) diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td index 159600f3e26dc0..58492169b261ee 100644 --- a/clang/include/clang/Basic/DiagnosticParseKinds.td +++ b/clang/include/clang/Basic/DiagnosticParseKinds.td @@ -868,9 +868,9 @@ 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 err_missing_template_arg_list_after_template_kw : Error< +def warn_missing_template_arg_list_after_template_kw : Warning< "a template argument list is expected after a name prefixed by the template " - "keyword">; + "keyword">, InGroup<Pedantic>, 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 b3a1a6f6cf80d0..29fbd275efa8a6 100644 --- a/clang/lib/Parse/ParseExprCXX.cpp +++ b/clang/lib/Parse/ParseExprCXX.cpp @@ -3011,7 +3011,7 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, ParsedType ObjectType, if ((TNK == TNK_Function_template || TNK == TNK_Dependent_template_name || TNK == TNK_Var_template) && !Tok.is(tok::less)) - Diag(IdLoc, diag::err_missing_template_arg_list_after_template_kw); + Diag(IdLoc, diag::warn_missing_template_arg_list_after_template_kw); } return false; } diff --git a/clang/test/CXX/drs/dr0xx.cpp b/clang/test/CXX/drs/dr0xx.cpp index 127d45be5bda97..7352e1d79ac65f 100644 --- a/clang/test/CXX/drs/dr0xx.cpp +++ b/clang/test/CXX/drs/dr0xx.cpp @@ -1400,7 +1400,7 @@ namespace dr95 { // dr95: 3.3 // expected-note@#dr95-C-f {{implicitly declared private here}} } -namespace dr96 { // dr96: no +namespace dr96 { // dr96: sup P1787 struct A { void f(int); template<typename T> int f(T); @@ -1414,7 +1414,8 @@ namespace dr96 { // dr96: no // FIXME: This is ill-formed, because 'f' is not a template-id and does not // name a class template. // FIXME: What about alias templates? - int k2 = a.template f(1); // expected-error {{a template argument list is expected after a name prefixed by the template keyword}} + 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<int> s; B<A::template S> b; } diff --git a/clang/test/Misc/warning-flags.c b/clang/test/Misc/warning-flags.c index c587337da5933a..0e6d45419cd249 100644 --- a/clang/test/Misc/warning-flags.c +++ b/clang/test/Misc/warning-flags.c @@ -88,4 +88,4 @@ CHECK-NEXT: warn_weak_import The list of warnings in -Wpedantic should NEVER grow. -CHECK: Number in -Wpedantic (not covered by other -W flags): 26 +CHECK: Number in -Wpedantic (not covered by other -W flags): 27 diff --git a/clang/www/cxx_dr_status.html b/clang/www/cxx_dr_status.html index 3e13a4d89ef989..bbad3ce3ad533d 100755 --- a/clang/www/cxx_dr_status.html +++ b/clang/www/cxx_dr_status.html @@ -614,7 +614,7 @@ <h2 id="cxxdr">C++ defect report implementation status</h2> <td><a href="https://cplusplus.github.io/CWG/issues/96.html">96</a></td> <td>C++11</td> <td>Syntactic disambiguation using the <TT>template</TT> keyword</td> - <td class="none" align="center">No</td> + <td class="na" align="center">Superseded by <a href="https://wg21.link/P1787">P1787</a></td> </tr> <tr id="97"> <td><a href="https://cplusplus.github.io/CWG/issues/97.html">97</a></td> >From c33b4cafc0180caaba68abefe07fcf77e68b1b72 Mon Sep 17 00:00:00 2001 From: Erick Velez <erickvel...@gmail.com> Date: Wed, 7 Feb 2024 23:35:34 -0800 Subject: [PATCH 3/4] do not modify warning-flags.c --- clang/include/clang/Basic/DiagnosticParseKinds.td | 5 +++-- clang/lib/Parse/ParseExprCXX.cpp | 2 +- clang/test/Misc/warning-flags.c | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td index 58492169b261ee..93d5160a1589af 100644 --- a/clang/include/clang/Basic/DiagnosticParseKinds.td +++ b/clang/include/clang/Basic/DiagnosticParseKinds.td @@ -868,9 +868,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 warn_missing_template_arg_list_after_template_kw : Warning< +def missing_template_arg_list_after_template_kw : Extension< "a template argument list is expected after a name prefixed by the template " - "keyword">, InGroup<Pedantic>, DefaultError; + "keyword">, InGroup<DiagGroup<"missing-template-arg-list-after-template-kw">>, + 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 29fbd275efa8a6..de2810fa145941 100644 --- a/clang/lib/Parse/ParseExprCXX.cpp +++ b/clang/lib/Parse/ParseExprCXX.cpp @@ -3011,7 +3011,7 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, ParsedType ObjectType, if ((TNK == TNK_Function_template || TNK == TNK_Dependent_template_name || TNK == TNK_Var_template) && !Tok.is(tok::less)) - Diag(IdLoc, diag::warn_missing_template_arg_list_after_template_kw); + Diag(IdLoc, diag::missing_template_arg_list_after_template_kw); } return false; } diff --git a/clang/test/Misc/warning-flags.c b/clang/test/Misc/warning-flags.c index 0e6d45419cd249..c587337da5933a 100644 --- a/clang/test/Misc/warning-flags.c +++ b/clang/test/Misc/warning-flags.c @@ -88,4 +88,4 @@ CHECK-NEXT: warn_weak_import The list of warnings in -Wpedantic should NEVER grow. -CHECK: Number in -Wpedantic (not covered by other -W flags): 27 +CHECK: Number in -Wpedantic (not covered by other -W flags): 26 >From 2375746bb32541dd6ba7d3858e704ec571040152 Mon Sep 17 00:00:00 2001 From: Erick Velez <erickvel...@gmail.com> Date: Thu, 8 Feb 2024 08:59:29 -0800 Subject: [PATCH 4/4] remove trailing whitespace in diagnostic --- clang/include/clang/Basic/DiagnosticParseKinds.td | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td index 93d5160a1589af..2a4302d5dab8d7 100644 --- a/clang/include/clang/Basic/DiagnosticParseKinds.td +++ b/clang/include/clang/Basic/DiagnosticParseKinds.td @@ -870,7 +870,7 @@ def err_requires_expr_in_simple_requirement : Error< "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<DiagGroup<"missing-template-arg-list-after-template-kw">>, + "keyword">, InGroup<DiagGroup<"missing-template-arg-list-after-template-kw">>, DefaultError; def err_missing_dependent_template_keyword : Error< _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits