Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[clang] require template arg list after template kw #80801

Merged
merged 8 commits into from
May 31, 2024
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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.

- Require a template argument list after a template keyword.
evelez7 marked this conversation as resolved.
Show resolved Hide resolved
(`CWG96: Syntactic disambiguation using the template keyword <https://cplusplus.github.io/CWG/issues/96.html>`_).

C Language Changes
------------------

Expand Down
4 changes: 4 additions & 0 deletions clang/include/clang/Basic/DiagnosticParseKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -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<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">;
Expand Down
23 changes: 17 additions & 6 deletions clang/lib/Parse/ParseExprCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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++ [template.names]p6
evelez7 marked this conversation as resolved.
Show resolved Hide resolved
// 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 ||
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about type templates: https://godbolt.org/z/1coGTT38P (hmm we may have a wider issue there, from looking at Clang's current behavior, so a FIXME would be reasonable too).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah this case isn't covered here. The error fires before reaching this method. I can try to diagnose it for this patch if needed, or I can do a followup patch.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's reasonable to handle in a follow-up, thanks!

TNK == TNK_Var_template) &&
!Tok.is(tok::less))
Diag(IdLoc, diag::missing_template_arg_list_after_template_kw);
}
return false;
}

Expand Down
3 changes: 2 additions & 1 deletion clang/test/CXX/drs/cwg0xx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<typename T> int f(T);
Expand All @@ -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<int> s;
B<A::template S> b;
}
Expand Down
6 changes: 3 additions & 3 deletions clang/test/SemaCXX/cxx1y-variable-templates_in_class.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 '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<typename T>
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<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 '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 <class T> static T G;
Expand Down
2 changes: 1 addition & 1 deletion clang/test/SemaCXX/template-specialization.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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'}}
}
};

Expand Down
6 changes: 3 additions & 3 deletions clang/test/SemaTemplate/dependent-names.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -420,7 +420,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();
};
Expand All @@ -431,7 +431,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}}
};
Expand All @@ -450,7 +450,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(...);
Expand Down
36 changes: 18 additions & 18 deletions clang/test/SemaTemplate/template-id-expr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,23 +65,23 @@ 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}}

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'}}
}
};

Expand Down Expand Up @@ -109,23 +109,23 @@ 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}}

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'}}
}
};

Expand All @@ -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}}
}
};

Expand All @@ -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}}
Expand Down
13 changes: 0 additions & 13 deletions clang/test/SemaTemplate/template-id-printing.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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>;
Expand All @@ -121,21 +119,10 @@ 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>;
s.template foo<T>;
}

} // namespace DSME

namespace DSDRE_withImplicitTemplateArgs {

template <typename T> void foo() {
// CHECK: T::template bar();
T::template bar();
}

} // namespace DSDRE_withImplicitTemplateArgs
2 changes: 1 addition & 1 deletion clang/www/cxx_dr_status.html
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down
Loading