Index: lib/Sema/SemaExprCXX.cpp =================================================================== --- lib/Sema/SemaExprCXX.cpp +++ lib/Sema/SemaExprCXX.cpp @@ -112,6 +112,7 @@ DeclContext *LookupCtx = nullptr; bool isDependent = false; bool LookInScope = false; + LookupNameKind LookupKind = LookupOrdinaryName; if (SS.isInvalid()) return nullptr; @@ -144,7 +145,9 @@ LookupCtx = DC; isDependent = false; } else if (DC && isa(DC)) { - LookAtPrefix = false; + // Penultimate name is a class-name, we will LookAtPrefix. However, look + // up class-name's in the same scope as the first. + LookupKind = LookupNestedNameSpecifierName; LookInScope = true; } @@ -184,7 +187,7 @@ } TypeDecl *NonMatchingTypeDecl = nullptr; - LookupResult Found(*this, &II, NameLoc, LookupOrdinaryName); + LookupResult Found(*this, &II, NameLoc, LookupKind); for (unsigned Step = 0; Step != 2; ++Step) { // Look for the name first in the computed lookup context (if we // have one) and, if that fails to find a match, in the scope (if Index: test/CXX/drs/dr2xx.cpp =================================================================== --- test/CXX/drs/dr2xx.cpp +++ test/CXX/drs/dr2xx.cpp @@ -502,7 +502,7 @@ f.N::F::~E(); // 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(); // FIXME: expected-error {{expected the class name after '~' to name a destructor}} + f.N::F::~F(); // This is technically ill-formed; G is looked up in 'N::' and is not found; // as above, this is probably a bug in the standard. f.N::F::~G(); Index: test/SemaCXX/destructor.cpp =================================================================== --- test/SemaCXX/destructor.cpp +++ test/SemaCXX/destructor.cpp @@ -493,4 +493,23 @@ x.foo1(); } } + +namespace PR12350 { + class basic_string { + public: + ~basic_string(); + char *something; + }; + + namespace notstd { + typedef basic_string string; + } + + void + foo(notstd::string *bar) + { + bar->notstd::string::~string(); // OK + } +} + #endif // BE_THE_HEADER