Skip to content

Commit

Permalink
PR45142: 'template ~X<T>' is ill-formed; reject it rather than crashing.
Browse files Browse the repository at this point in the history
  • Loading branch information
zygoloid committed Mar 23, 2020
1 parent a208623 commit 502915c
Show file tree
Hide file tree
Showing 4 changed files with 26 additions and 7 deletions.
2 changes: 2 additions & 0 deletions clang/include/clang/Basic/DiagnosticParseKinds.td
Expand Up @@ -706,6 +706,8 @@ def err_id_after_template_in_nested_name_spec : Error<
"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<
Expand Down
18 changes: 17 additions & 1 deletion clang/lib/Parse/ParseExprCXX.cpp
Expand Up @@ -2884,6 +2884,22 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, ParsedType ObjectType,
// 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);
Expand All @@ -2903,7 +2919,7 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, ParsedType ObjectType,

// 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.
Expand Down
8 changes: 3 additions & 5 deletions clang/test/CXX/drs/dr4xx.cpp
Expand Up @@ -297,13 +297,11 @@ namespace dr420 { // dr420: yes
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;
Expand Down
5 changes: 4 additions & 1 deletion clang/test/SemaCXX/pseudo-destructors.cpp
@@ -1,4 +1,4 @@
// 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 };
Expand Down Expand Up @@ -92,6 +92,9 @@ namespace PR11339 {
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 {
Expand Down

0 comments on commit 502915c

Please sign in to comment.