diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp --- a/clang/lib/Sema/SemaLookup.cpp +++ b/clang/lib/Sema/SemaLookup.cpp @@ -1298,13 +1298,20 @@ // } // UnqualUsingDirectiveSet UDirs(*this); - bool VisitedUsingDirectives = false; bool LeftStartingScope = false; // When performing a scope lookup, we want to find local extern decls. FindLocalExternScope FindLocals(R); + Scope *InnermostFileScope = nullptr; + DeclContext *InnermostFileScopeDC = nullptr; + + for (; S; S = S->getParent()) { + if (isNamespaceOrTranslationUnitScope(S)) { + if (!InnermostFileScope) + InnermostFileScope = S; + continue; + } - for (; S && !isNamespaceOrTranslationUnitScope(S); S = S->getParent()) { bool SearchNamespaceScope = true; // Check whether the IdResolver has anything in this scope. for (; I != IEnd && S->isDeclScope(*I); ++I) { @@ -1387,34 +1394,8 @@ // If this is a file context, we need to perform unqualified name // lookup considering using directives. if (Ctx->isFileContext()) { - // If we haven't handled using directives yet, do so now. - if (!VisitedUsingDirectives) { - // Add using directives from this context up to the top level. - for (DeclContext *UCtx = Ctx; UCtx; UCtx = UCtx->getParent()) { - if (UCtx->isTransparentContext()) - continue; - - UDirs.visit(UCtx, UCtx); - } - - // Find the innermost file scope, so we can add using directives - // from local scopes. - Scope *InnermostFileScope = S; - while (InnermostFileScope && - !isNamespaceOrTranslationUnitScope(InnermostFileScope)) - InnermostFileScope = InnermostFileScope->getParent(); - UDirs.visitScopeChain(Initial, InnermostFileScope); - - UDirs.done(); - - VisitedUsingDirectives = true; - } - - if (CppNamespaceLookup(*this, R, Context, Ctx, UDirs)) { - R.resolveKind(); - return true; - } - + if (!InnermostFileScopeDC) + InnermostFileScopeDC = Ctx; continue; } @@ -1430,6 +1411,8 @@ } } + S = InnermostFileScope; + // Stop if we ran out of scopes. // FIXME: This really, really shouldn't be happening. if (!S) return false; @@ -1443,11 +1426,45 @@ // // FIXME: Cache this sorted list in Scope structure, and DeclContext, so we // don't build it for each lookup! - if (!VisitedUsingDirectives) { - UDirs.visitScopeChain(Initial, S); - UDirs.done(); + + // Add using directives from the innermost file scope context up to the top + // level. + for (DeclContext *UCtx = InnermostFileScopeDC; UCtx; + UCtx = UCtx->getParent()) { + if (UCtx->isTransparentContext()) + continue; + + UDirs.visit(UCtx, UCtx); } + // Add using directives from local scopes. + UDirs.visitScopeChain(Initial, S); + UDirs.done(); + + // Search the file scope DCs between the innermost file scope DC and the DC + // corresponding to the innermost file scope. This is needed, for example, in + // the following case where namespace 'N' cannot be found on the scope stack: + // + // namespace N { + // struct B { + // B(int); + // }; + // typedef B typedef_B; + // struct D : B { + // D(); + // }; + // } + // + // N::D::D() : typedef_B(0) {} + + for (DeclContext *Ctx = InnermostFileScopeDC, *LastCtx = S->getEntity(); + Ctx && !Ctx->Equals(LastCtx); Ctx = Ctx->getLookupParent()) + if (!Ctx->isTransparentContext() && + CppNamespaceLookup(*this, R, Context, Ctx, UDirs)) { + R.resolveKind(); + return true; + } + // If we're not performing redeclaration lookup, do not look for local // extern declarations outside of a function scope. if (!R.isForRedeclaration()) @@ -1458,6 +1475,9 @@ // that aren't strictly lexical, and therefore we walk through the // context as well as walking through the scopes. for (; S; S = S->getParent()) { + if (!isNamespaceOrTranslationUnitScope(S)) + continue; + // Check whether the IdResolver has anything in this scope. bool Found = false; for (; I != IEnd && S->isDeclScope(*I); ++I) { @@ -1471,11 +1491,6 @@ } } - if (Found && S->isTemplateParamScope()) { - R.resolveKind(); - return true; - } - DeclContext *Ctx = S->getLookupEntity(); if (Ctx) { DeclContext *OuterCtx = findOuterContext(S); @@ -1489,14 +1504,13 @@ // If we have a context, and it's not a context stashed in the // template parameter scope for an out-of-line definition, also // look into that context. - if (!(Found && S->isTemplateParamScope())) { - assert(Ctx->isFileContext() && - "We should have been looking only at file context here already."); + assert( + Ctx->isFileContext() && + "We should have been looking only at file context here already."); - // Look into context considering using-directives. - if (CppNamespaceLookup(*this, R, Context, Ctx, UDirs)) - Found = true; - } + // Look into context considering using-directives. + if (CppNamespaceLookup(*this, R, Context, Ctx, UDirs)) + Found = true; if (Found) { R.resolveKind(); diff --git a/clang/test/SemaCXX/namespace.cpp b/clang/test/SemaCXX/namespace.cpp --- a/clang/test/SemaCXX/namespace.cpp +++ b/clang/test/SemaCXX/namespace.cpp @@ -96,3 +96,12 @@ } } + +namespace N0 { + template class S; + template class C; +} + +template class N0::C { + void foo(S c) {} +};