Skip to content

Commit

Permalink
[clang] Add test for CWG399
Browse files Browse the repository at this point in the history
[[https://wg21.link/p1787 | 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, so I reused CWG244 test. This approach to reusing was discussed in [[https://reviews.llvm.org/D139095 | a CWG405 patch review]].

Reviewed By: #clang-language-wg, aaron.ballman, shafik

Differential Revision: https://reviews.llvm.org/D147920
  • Loading branch information
Endilll committed May 20, 2023
1 parent a4f366d commit 14f245d
Show file tree
Hide file tree
Showing 3 changed files with 82 additions and 1 deletion.
1 change: 1 addition & 0 deletions clang/test/CXX/drs/dr2xx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -500,6 +500,7 @@ namespace dr243 { // dr243: yes
}

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 {};

Expand Down
80 changes: 80 additions & 0 deletions clang/test/CXX/drs/dr3xx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1435,3 +1435,83 @@ namespace dr398 { // dr398: yes
}
}
}

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 *);
}
}
2 changes: 1 addition & 1 deletion clang/www/cxx_dr_status.html
Original file line number Diff line number Diff line change
Expand Up @@ -2433,7 +2433,7 @@ <h2 id="cxxdr">C++ defect report implementation status</h2>
<td><a href="https://cplusplus.github.io/CWG/issues/399.html">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://cplusplus.github.io/CWG/issues/400.html">400</a></td>
Expand Down

0 comments on commit 14f245d

Please sign in to comment.