[clang] 04f131d - DR1753: Don't permit x.NS::~T() as a pseudo-destructor name.

Richard Smith via cfe-commits cfe-commits at lists.llvm.org
Fri Jan 24 18:54:00 PST 2020


Author: Richard Smith
Date: 2020-01-24T18:53:50-08:00
New Revision: 04f131da0b19abff611773c03be9bafb53c753ce

URL: https://github.com/llvm/llvm-project/commit/04f131da0b19abff611773c03be9bafb53c753ce
DIFF: https://github.com/llvm/llvm-project/commit/04f131da0b19abff611773c03be9bafb53c753ce.diff

LOG: DR1753: Don't permit x.NS::~T() as a pseudo-destructor name.

When used as qualified names, pseudo-destructors are always named as if
they were members of the type, never as members of the namespace
enclosing the type.

Added: 
    

Modified: 
    clang/lib/Parse/ParseExprCXX.cpp
    clang/test/CXX/drs/dr17xx.cpp
    clang/test/SemaCXX/pseudo-destructors.cpp
    clang/www/cxx_dr_status.html

Removed: 
    


################################################################################
diff  --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp
index 036eabb94dd7..73d15cbc20c1 100644
--- a/clang/lib/Parse/ParseExprCXX.cpp
+++ b/clang/lib/Parse/ParseExprCXX.cpp
@@ -418,8 +418,7 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
     }
 
     if (Next.is(tok::coloncolon)) {
-      if (CheckForDestructor && GetLookAheadToken(2).is(tok::tilde) &&
-          !Actions.isNonTypeNestedNameSpecifier(getCurScope(), SS, IdInfo)) {
+      if (CheckForDestructor && GetLookAheadToken(2).is(tok::tilde)) {
         *MayBePseudoDestructor = true;
         return false;
       }
@@ -548,7 +547,7 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
   // Even if we didn't see any pieces of a nested-name-specifier, we
   // still check whether there is a tilde in this position, which
   // indicates a potential pseudo-destructor.
-  if (CheckForDestructor && Tok.is(tok::tilde))
+  if (CheckForDestructor && !HasScopeSpecifier && Tok.is(tok::tilde))
     *MayBePseudoDestructor = true;
 
   return false;
@@ -1689,31 +1688,42 @@ ExprResult Parser::ParseCXXUuidof() {
 
 /// Parse a C++ pseudo-destructor expression after the base,
 /// . or -> operator, and nested-name-specifier have already been
-/// parsed.
+/// parsed. We're handling this fragment of the grammar:
+///
+///       postfix-expression: [C++2a expr.post]
+///         postfix-expression . template[opt] id-expression
+///         postfix-expression -> template[opt] id-expression
 ///
-///       postfix-expression: [C++ 5.2]
-///         postfix-expression . pseudo-destructor-name
-///         postfix-expression -> pseudo-destructor-name
+///       id-expression:
+///         qualified-id
+///         unqualified-id
 ///
-///       pseudo-destructor-name:
-///         ::[opt] nested-name-specifier[opt] type-name :: ~type-name
-///         ::[opt] nested-name-specifier template simple-template-id ::
-///                 ~type-name
-///         ::[opt] nested-name-specifier[opt] ~type-name
+///       qualified-id:
+///         nested-name-specifier template[opt] unqualified-id
 ///
+///       nested-name-specifier:
+///         type-name ::
+///         decltype-specifier ::    FIXME: not implemented, but probably only
+///                                         allowed in C++ grammar by accident
+///         nested-name-specifier identifier ::
+///         nested-name-specifier template[opt] simple-template-id ::
+///         [...]
+///
+///       unqualified-id:
+///         ~ type-name
+///         ~ decltype-specifier
+///         [...]
+///
+/// ... where the all but the last component of the nested-name-specifier
+/// has already been parsed, and the base expression is not of a non-dependent
+/// class type.
 ExprResult
 Parser::ParseCXXPseudoDestructor(Expr *Base, SourceLocation OpLoc,
                                  tok::TokenKind OpKind,
                                  CXXScopeSpec &SS,
                                  ParsedType ObjectType) {
-  // We're parsing either a pseudo-destructor-name or a dependent
-  // member access that has the same form as a
-  // pseudo-destructor-name. We parse both in the same way and let
-  // the action model sort them out.
-  //
-  // Note that the ::[opt] nested-name-specifier[opt] has already
-  // been parsed, and if there was a simple-template-id, it has
-  // been coalesced into a template-id annotation token.
+  // If the last component of the (optional) nested-name-specifier is
+  // template[opt] simple-template-id, it has already been annotated.
   UnqualifiedId FirstTypeName;
   SourceLocation CCLoc;
   if (Tok.is(tok::identifier)) {
@@ -1722,14 +1732,13 @@ Parser::ParseCXXPseudoDestructor(Expr *Base, SourceLocation OpLoc,
     assert(Tok.is(tok::coloncolon) &&"ParseOptionalCXXScopeSpecifier fail");
     CCLoc = ConsumeToken();
   } else if (Tok.is(tok::annot_template_id)) {
-    // FIXME: retrieve TemplateKWLoc from template-id annotation and
-    // store it in the pseudo-dtor node (to be used when instantiating it).
     FirstTypeName.setTemplateId(
                               (TemplateIdAnnotation *)Tok.getAnnotationValue());
     ConsumeAnnotationToken();
     assert(Tok.is(tok::coloncolon) &&"ParseOptionalCXXScopeSpecifier fail");
     CCLoc = ConsumeToken();
   } else {
+    assert(SS.isEmpty() && "missing last component of nested name specifier");
     FirstTypeName.setIdentifier(nullptr, SourceLocation());
   }
 
@@ -1737,7 +1746,7 @@ Parser::ParseCXXPseudoDestructor(Expr *Base, SourceLocation OpLoc,
   assert(Tok.is(tok::tilde) && "ParseOptionalCXXScopeSpecifier fail");
   SourceLocation TildeLoc = ConsumeToken();
 
-  if (Tok.is(tok::kw_decltype) && !FirstTypeName.isValid() && SS.isEmpty()) {
+  if (Tok.is(tok::kw_decltype) && !FirstTypeName.isValid()) {
     DeclSpec DS(AttrFactory);
     ParseDecltypeSpecifier(DS);
     if (DS.getTypeSpecType() == TST_error)

diff  --git a/clang/test/CXX/drs/dr17xx.cpp b/clang/test/CXX/drs/dr17xx.cpp
index ca55c42977df..c9f5b2df95a5 100644
--- a/clang/test/CXX/drs/dr17xx.cpp
+++ b/clang/test/CXX/drs/dr17xx.cpp
@@ -3,10 +3,6 @@
 // RUN: %clang_cc1 -std=c++14 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
 // RUN: %clang_cc1 -std=c++1z %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
 
-#if __cplusplus < 201103L
-// expected-no-diagnostics
-#endif
-
 namespace dr1715 { // dr1715: 3.9
 #if __cplusplus >= 201103L
   struct B {
@@ -47,6 +43,32 @@ S s(q); // expected-note {{instantiation of}}
 #endif
 }
 
+namespace dr1753 { // dr1753: 11
+  typedef int T;
+  struct A { typedef int T; };
+  namespace B { typedef int T; }
+
+  void f(T n) {
+    n.~T();
+    n.T::~T();
+
+    n.dr1753::~T(); // expected-error {{'dr1753' does not refer to a type name in pseudo-destructor}}
+    n.dr1753::T::~T();
+
+    n.A::~T(); // expected-error {{the type of object expression ('dr1753::T' (aka 'int')) does not match the type being destroyed ('dr1753::A') in pseudo-destructor expression}}
+    n.A::T::~T();
+
+    n.B::~T(); // expected-error {{'B' does not refer to a type name in pseudo-destructor expression}}
+    n.B::T::~T();
+
+  #if __cplusplus >= 201103L
+    n.decltype(n)::~T(); // expected-error {{not a class, namespace, or enumeration}}
+    n.T::~decltype(n)(); // expected-error {{expected a class name after '~'}}
+    n.~decltype(n)(); // OK
+  #endif
+  }
+}
+
 namespace dr1756 { // dr1756: 3.7
 #if __cplusplus >= 201103L
   // Direct-list-initialization of a non-class object

diff  --git a/clang/test/SemaCXX/pseudo-destructors.cpp b/clang/test/SemaCXX/pseudo-destructors.cpp
index fb2d0afdc3fa..dfdd1174b8a4 100644
--- a/clang/test/SemaCXX/pseudo-destructors.cpp
+++ b/clang/test/SemaCXX/pseudo-destructors.cpp
@@ -33,17 +33,21 @@ void f(A* a, Foo *f, int *i, double *d, int ii) {
   
   g().~Bar(); // expected-error{{non-scalar}}
   
-  f->::~Bar();
+  f->::~Bar(); // expected-error {{not a structure or union}}
+  f->::Bar::~Bar();
   f->N::~Wibble(); // expected-error{{'N' does not refer to a type}} expected-error{{'Wibble' does not refer to a type}}
   
-  f->::~Bar(17, 42); // expected-error{{cannot have any arguments}}
+  f->Bar::~Bar(17, 42); // expected-error{{cannot have any arguments}}
 
   i->~Integer();
   i->Integer::~Integer();
-  i->N::~OtherInteger();
+  i->N::~OtherInteger(); // expected-error{{'N' does not refer to a type name in pseudo-destructor expression; expected the name of type 'int'}}
+                         // expected-error at -1{{'OtherInteger' does not refer to a type name in pseudo-destructor expression; expected the name of type 'int'}}
   i->N::OtherInteger::~OtherInteger();
+  i->N::OtherInteger::~OtherInteger();
+  i->N::OtherInteger::~Integer(); // expected-error{{'Integer' does not refer to a type name in pseudo-destructor expression; expected the name of type 'int'}}
+  i->N::~Integer(); // expected-error{{'N' does not refer to a type name in pseudo-destructor expression; expected the name of type 'int'}}
   i->N::OtherInteger::~Integer(); // expected-error{{'Integer' does not refer to a type name in pseudo-destructor expression; expected the name of type 'int'}}
-  i->N::~Integer(); // expected-error{{'Integer' does not refer to a type name in pseudo-destructor expression; expected the name of type 'int'}}
   i->Integer::~Double(); // expected-error{{the type of object expression ('int') does not match the type being destroyed ('Double' (aka 'double')) in pseudo-destructor expression}}
 
   ii->~Integer(); // expected-error{{member reference type 'int' is not a pointer; did you mean to use '.'?}}

diff  --git a/clang/www/cxx_dr_status.html b/clang/www/cxx_dr_status.html
index eff9fd5dc185..1a00b4e06860 100755
--- a/clang/www/cxx_dr_status.html
+++ b/clang/www/cxx_dr_status.html
@@ -10333,7 +10333,7 @@ <h2 id="cxxdr">C++ defect report implementation status</h2>
     <td><a href="https://wg21.link/cwg1753">1753</a></td>
     <td>CD4</td>
     <td><I>decltype-specifier</I> in <I>nested-name-specifier</I> of destructor</td>
-    <td class="none" align="center">Unknown</td>
+    <td class="unreleased" align="center">Clang 11</td>
   </tr>
   <tr id="1754">
     <td><a href="https://wg21.link/cwg1754">1754</a></td>


        


More information about the cfe-commits mailing list