Endill created this revision.
Endill added a reviewer: clang-language-wg.
Herald added a project: All.
Endill requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

P1787 <https://wg21.link/p1787>: CWG399 is resolved by explicitly appealing to 
the lookup for the last component of any suitable nested-name-specifier.
Wording: Otherwise, its nested-name-specifier N shall nominate a type. If N has 
another nested-name-specifier S, Q is looked up as if its lookup context were 
that nominated by S. ([basic.lookup.qual]/6.2)

CWG399 revisits a resolution to older CWG244. Our test for CWG244 covers many 
examples from CWG399, and it was updated in 2020 presumably aware of P1787 
<https://reviews.llvm.org/P1787>, so I reused CWG244 test. This approach to 
reusing was discussed in a CWG405 patch review 
<https://reviews.llvm.org/D139095>.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D147920

Files:
  clang/test/CXX/drs/dr2xx.cpp
  clang/test/CXX/drs/dr3xx.cpp
  clang/www/cxx_dr_status.html

Index: clang/www/cxx_dr_status.html
===================================================================
--- clang/www/cxx_dr_status.html
+++ clang/www/cxx_dr_status.html
@@ -2433,7 +2433,7 @@
     <td><a href="https://wg21.link/cwg399";>399</a></td>
     <td>CD6</td>
     <td>Destructor lookup redux</td>
-    <td class="none" align="center">Unknown</td>
+    <td class="full" align="center">Clang 11</td>
   </tr>
   <tr id="400">
     <td><a href="https://wg21.link/cwg400";>400</a></td>
Index: clang/test/CXX/drs/dr3xx.cpp
===================================================================
--- clang/test/CXX/drs/dr3xx.cpp
+++ clang/test/CXX/drs/dr3xx.cpp
@@ -1435,3 +1435,83 @@
     }
   }
 }
+
+namespace dr399 { // dr399: 11
+                  // NB: reuse dr244 test 
+  struct B {}; // expected-note {{type 'dr244::B' found by destructor name lookup}}
+  struct D : B {};
+
+  D D_object;
+  typedef B B_alias;
+  B* B_ptr = &D_object;
+
+  void f() {
+    D_object.~B(); // expected-error {{does not match the type 'D' of the object being destroyed}}
+    D_object.B::~B();
+    D_object.D::~B(); // FIXME: Missing diagnostic for this.
+    B_ptr->~B();
+    B_ptr->~B_alias();
+    B_ptr->B_alias::~B();
+    B_ptr->B_alias::~B_alias();
+    B_ptr->dr244::~B(); // expected-error {{refers to a member in namespace}}
+    B_ptr->dr244::~B_alias(); // expected-error {{refers to a member in namespace}}
+  }
+
+  template<typename T, typename U>
+  void f(T *B_ptr, U D_object) {
+    D_object.~B(); // FIXME: Missing diagnostic for this.
+    D_object.B::~B();
+    D_object.D::~B(); // FIXME: Missing diagnostic for this.
+    B_ptr->~B();
+    B_ptr->~B_alias();
+    B_ptr->B_alias::~B();
+    B_ptr->B_alias::~B_alias();
+    B_ptr->dr399::~B(); // expected-error {{does not refer to a type name}}
+    B_ptr->dr399::~B_alias(); // expected-error {{does not refer to a type name}}
+  }
+  template void f<B, D>(B*, D);
+
+  namespace N {
+    template<typename T> struct E {};
+    typedef E<int> F;
+  }
+  void g(N::F f) {
+    typedef N::F G; // expected-note {{found by destructor name lookup}}
+    f.~G();
+    f.G::~E(); // expected-error {{ISO C++ requires the name after '::~' to be found in the same scope as the name before '::~'}}
+    f.G::~F(); // expected-error {{undeclared identifier 'F' in destructor name}}
+    f.G::~G();
+    // This is technically ill-formed; E is looked up in 'N::' and names the
+    // class template, not the injected-class-name of the class. But that's
+    // probably a bug in the standard.
+    f.N::F::~E(); // expected-error {{ISO C++ requires the name after '::~' to be found in the same scope as the name before '::~'}}
+    // This is valid; we look up the second F in the same scope in which we
+    // found the first one, that is, 'N::'.
+    f.N::F::~F();
+    // This is technically ill-formed; G is looked up in 'N::' and is not found.
+    // Rejecting this seems correct, but most compilers accept, so we do also.
+    f.N::F::~G(); // expected-error {{qualified destructor name only found in lexical scope; omit the qualifier to find this type name by unqualified lookup}}
+  }
+
+  // Bizarrely, compilers perform lookup in the scope for qualified destructor
+  // names, if the nested-name-specifier is non-dependent. Ensure we diagnose
+  // this.
+  namespace QualifiedLookupInScope {
+    namespace N {
+      template <typename> struct S { struct Inner {}; };
+    }
+    template <typename U> void f(typename N::S<U>::Inner *p) {
+      typedef typename N::S<U>::Inner T;
+      p->::dr399::QualifiedLookupInScope::N::S<U>::Inner::~T(); // expected-error {{no type named 'T' in}}
+    }
+    template void f<int>(N::S<int>::Inner *); // expected-note {{instantiation of}}
+
+    template <typename U> void g(U *p) {
+      typedef U T;
+      p->T::~T();
+      p->U::~T();
+      p->::dr399::QualifiedLookupInScope::N::S<int>::Inner::~T(); // expected-error {{'T' does not refer to a type name}}
+    }
+    template void g(N::S<int>::Inner *);
+  }
+}
Index: clang/test/CXX/drs/dr2xx.cpp
===================================================================
--- clang/test/CXX/drs/dr2xx.cpp
+++ clang/test/CXX/drs/dr2xx.cpp
@@ -500,6 +500,7 @@
 }
 
 namespace dr244 { // dr244: 11
+                  // NB: this test is reused by dr399
   struct B {}; // expected-note {{type 'dr244::B' found by destructor name lookup}}
   struct D : B {};
 
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to