Author: Richard Smith Date: 2020-03-23T15:07:06-07:00 New Revision: 502915c619a32972ddc525be585794371bfbd27b
URL: https://github.com/llvm/llvm-project/commit/502915c619a32972ddc525be585794371bfbd27b DIFF: https://github.com/llvm/llvm-project/commit/502915c619a32972ddc525be585794371bfbd27b.diff LOG: PR45142: 'template ~X<T>' is ill-formed; reject it rather than crashing. Added: Modified: clang/include/clang/Basic/DiagnosticParseKinds.td clang/lib/Parse/ParseExprCXX.cpp clang/test/CXX/drs/dr4xx.cpp clang/test/SemaCXX/pseudo-destructors.cpp Removed: ################################################################################ diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td index acb229225ea1..dcbb0d3f8799 100644 --- a/clang/include/clang/Basic/DiagnosticParseKinds.td +++ b/clang/include/clang/Basic/DiagnosticParseKinds.td @@ -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< diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp index b8d91c19228f..a0b97ea7514d 100644 --- a/clang/lib/Parse/ParseExprCXX.cpp +++ b/clang/lib/Parse/ParseExprCXX.cpp @@ -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); @@ -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. diff --git a/clang/test/CXX/drs/dr4xx.cpp b/clang/test/CXX/drs/dr4xx.cpp index 35fd15f0cc64..2c762237037d 100644 --- a/clang/test/CXX/drs/dr4xx.cpp +++ b/clang/test/CXX/drs/dr4xx.cpp @@ -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; diff --git a/clang/test/SemaCXX/pseudo-destructors.cpp b/clang/test/SemaCXX/pseudo-destructors.cpp index 0cd139047432..b71b523de683 100644 --- a/clang/test/SemaCXX/pseudo-destructors.cpp +++ b/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 }; @@ -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 { _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits