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