"expected template name after 'template' keyword in nested name specifier">;
def err_unexpected_template_in_unqualified_id : Error<
"'template' keyword not permitted here">;
+def err_unexpected_template_in_destructor_name : Error<
+ "'template' keyword not permitted in destructor name">;
def err_unexpected_template_after_using : Error<
"'template' keyword not permitted after 'using' keyword">;
def err_two_right_angle_brackets_need_space : Error<
// Parse the '~'.
SourceLocation TildeLoc = ConsumeToken();
+ if (TemplateSpecified) {
+ // C++ [temp.names]p3:
+ // A name prefixed by the keyword template shall be a template-id [...]
+ //
+ // A template-id cannot begin with a '~' token. This would never work
+ // anyway: x.~A<int>() would specify that the destructor is a template,
+ // not that 'A' is a template.
+ //
+ // FIXME: Suggest replacing the attempted destructor name with a correct
+ // destructor name and recover. (This is not trivial if this would become
+ // a pseudo-destructor name).
+ Diag(*TemplateKWLoc, diag::err_unexpected_template_in_destructor_name)
+ << Tok.getLocation();
+ return true;
+ }
+
if (SS.isEmpty() && Tok.is(tok::kw_decltype)) {
DeclSpec DS(AttrFactory);
SourceLocation EndLoc = ParseDecltypeSpecifier(DS);
// If the user wrote ~T::T, correct it to T::~T.
DeclaratorScopeObj DeclScopeObj(*this, SS);
- if (!TemplateSpecified && NextToken().is(tok::coloncolon)) {
+ if (NextToken().is(tok::coloncolon)) {
// Don't let ParseOptionalCXXScopeSpecifier() "correct"
// `int A; struct { ~A::A(); };` to `int A; struct { ~A:A(); };`,
// it will confuse this recovery logic.
void test2(T p) {
p->template Y<int>::~Y<int>();
p->~Y<int>();
- // FIXME: This is ill-formed, but this diagnostic is terrible. We should
- // reject this in the parser.
- p->template ~Y<int>(); // expected-error 2{{no member named '~typename Y<int>'}}
+ p->template ~Y<int>(); // expected-error {{'template' keyword not permitted in destructor name}}
}
template<typename T> struct Y {};
- template void test2(Y<int>*); // expected-note {{instantiation}}
- template void test2(ptr<Y<int> >); // expected-note {{instantiation}}
+ template void test2(Y<int>*);
+ template void test2(ptr<Y<int> >);
void test3(int *p, ptr<int> q) {
typedef int Int;
-// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
+// RUN: %clang_cc1 -emit-llvm-only -verify -std=c++11 %s
struct A {};
enum Foo { F };
template<typename T> using Id = T;
void AliasTemplate(int *p) {
p->~Id<int>();
+ p->template ~Id<int>(); // expected-error {{'template' keyword not permitted in destructor name}}
+ (0).~Id<int>();
+ (0).template ~Id<int>(); // expected-error {{'template' keyword not permitted in destructor name}}
}
namespace dotPointerAccess {