[clang] 502915c - PR45142: 'template ~X<T>' is ill-formed; reject it rather than crashing.

Richard Smith via cfe-commits cfe-commits at lists.llvm.org
Mon Mar 23 15:07:17 PDT 2020


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 {


        


More information about the cfe-commits mailing list