diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h index 30923a4fa05c..d124ed282bb1 100644 --- a/clang/include/clang/AST/Decl.h +++ b/clang/include/clang/AST/Decl.h @@ -614,7 +614,9 @@ public: if (!isInline()) return false; auto X = lookup(Name); - auto Y = getParent()->lookup(Name); + // We should not perform a lookup within a transparent context, so find a + // non-transparent parent context. + auto Y = getParent()->getNonTransparentContext()->lookup(Name); return std::distance(X.begin(), X.end()) == std::distance(Y.begin(), Y.end()); } diff --git a/clang/include/clang/AST/DeclBase.h b/clang/include/clang/AST/DeclBase.h index 482d2889a25a..18468c8ca1c4 100644 --- a/clang/include/clang/AST/DeclBase.h +++ b/clang/include/clang/AST/DeclBase.h @@ -1997,6 +1997,12 @@ public: return const_cast(this)->getNonClosureAncestor(); } + // Retrieve the nearest context that is not a transparent context. + DeclContext *getNonTransparentContext(); + const DeclContext *getNonTransparentContext() const { + return const_cast(this)->getNonTransparentContext(); + } + /// getPrimaryContext - There may be many different /// declarations of the same entity (including forward declarations /// of classes, multiple definitions of namespaces, etc.), each with diff --git a/clang/lib/AST/DeclBase.cpp b/clang/lib/AST/DeclBase.cpp index 3467da2b549e..53dd2ae3cbd3 100644 --- a/clang/lib/AST/DeclBase.cpp +++ b/clang/lib/AST/DeclBase.cpp @@ -1217,6 +1217,13 @@ bool DeclContext::Encloses(const DeclContext *DC) const { return false; } +DeclContext *DeclContext::getNonTransparentContext() { + DeclContext *DC = this; + while (DC && DC->isTransparentContext()) + DC = DC->getParent(); + return DC; +} + DeclContext *DeclContext::getPrimaryContext() { switch (getDeclKind()) { case Decl::ExternCContext: diff --git a/clang/test/Misc/diag-inline-namespace.cpp b/clang/test/Misc/diag-inline-namespace.cpp index 74bdeed68d21..34d549bc1cc0 100644 --- a/clang/test/Misc/diag-inline-namespace.cpp +++ b/clang/test/Misc/diag-inline-namespace.cpp @@ -48,3 +48,14 @@ namespace N { T t4; // expected-error {{implicit instantiation of undefined template 'N::T'}} T t5; // expected-error {{implicit instantiation of undefined template 'N::T'}} } + +namespace dont_crash { +// A malformed lookup involving inline namespaces in a linkage specification +// would previous cause an assertion due to the way diagnostics are emitted. +extern "C++" inline namespace { +namespace a { + a : b // expected-error {{unexpected ':' in nested name specifier; did you mean '::'?}} \ + // expected-error {{no type named 'b' in namespace 'dont_crash::a'}} +} // expected-error {{expected unqualified-id}} +} // inline namespace +} // dont_crash