From 8da894badfcde801cf20a6495cebe7400fc19f04 Mon Sep 17 00:00:00 2001 From: Richard Smith <richard-llvm@metafoo.co.uk> Date: Wed, 11 Oct 2017 01:19:11 +0000 Subject: [PATCH] [modules] Only take visible using-directives into account during name lookup. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@315402 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Sema/SemaLookup.cpp | 30 ++++++++-------- test/Modules/using-directive.cpp | 62 ++++++++++++++++++++++++++++++++ 2 files changed, 78 insertions(+), 14 deletions(-) create mode 100644 test/Modules/using-directive.cpp diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp index 6fb0260075f..8cb4fd63eb8 100644 --- a/lib/Sema/SemaLookup.cpp +++ b/lib/Sema/SemaLookup.cpp @@ -88,13 +88,15 @@ namespace { /// A collection of using directives, as used by C++ unqualified /// lookup. class UnqualUsingDirectiveSet { + Sema &SemaRef; + typedef SmallVector<UnqualUsingEntry, 8> ListTy; ListTy list; llvm::SmallPtrSet<DeclContext*, 8> visited; public: - UnqualUsingDirectiveSet() {} + UnqualUsingDirectiveSet(Sema &SemaRef) : SemaRef(SemaRef) {} void visitScopeChain(Scope *S, Scope *InnermostFileScope) { // C++ [namespace.udir]p1: @@ -113,7 +115,8 @@ namespace { visit(Ctx, Ctx); } else if (!Ctx || Ctx->isFunctionOrMethod()) { for (auto *I : S->using_directives()) - visit(I, InnermostFileDC); + if (SemaRef.isVisible(I)) + visit(I, InnermostFileDC); } } } @@ -152,7 +155,7 @@ namespace { while (true) { for (auto UD : DC->using_directives()) { DeclContext *NS = UD->getNominatedNamespace(); - if (visited.insert(NS).second) { + if (visited.insert(NS).second && SemaRef.isVisible(UD)) { addUsingDirective(UD, EffectiveDC); queue.push_back(NS); } @@ -1085,7 +1088,7 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) { // } // } // - UnqualUsingDirectiveSet UDirs; + UnqualUsingDirectiveSet UDirs(*this); bool VisitedUsingDirectives = false; bool LeftStartingScope = false; DeclContext *OutsideOfTemplateParamDC = nullptr; @@ -1868,22 +1871,19 @@ static bool LookupQualifiedNameInUsingDirectives(Sema &S, LookupResult &R, DeclContext *StartDC) { assert(StartDC->isFileContext() && "start context is not a file context"); - DeclContext::udir_range UsingDirectives = StartDC->using_directives(); - if (UsingDirectives.begin() == UsingDirectives.end()) return false; + // We have not yet looked into these namespaces, much less added + // their "using-children" to the queue. + SmallVector<NamespaceDecl*, 8> Queue; // We have at least added all these contexts to the queue. llvm::SmallPtrSet<DeclContext*, 8> Visited; Visited.insert(StartDC); - // We have not yet looked into these namespaces, much less added - // their "using-children" to the queue. - SmallVector<NamespaceDecl*, 8> Queue; - // We have already looked into the initial namespace; seed the queue // with its using-children. - for (auto *I : UsingDirectives) { + for (auto *I : StartDC->using_directives()) { NamespaceDecl *ND = I->getNominatedNamespace()->getOriginalNamespace(); - if (Visited.insert(ND).second) + if (Visited.insert(ND).second && S.isVisible(I)) Queue.push_back(ND); } @@ -1931,7 +1931,7 @@ static bool LookupQualifiedNameInUsingDirectives(Sema &S, LookupResult &R, for (auto I : ND->using_directives()) { NamespaceDecl *Nom = I->getNominatedNamespace(); - if (Visited.insert(Nom).second) + if (Visited.insert(Nom).second && S.isVisible(I)) Queue.push_back(Nom); } } @@ -3540,6 +3540,8 @@ static void LookupVisibleDecls(DeclContext *Ctx, LookupResult &Result, if (QualifiedNameLookup) { ShadowContextRAII Shadow(Visited); for (auto I : Ctx->using_directives()) { + if (!Result.getSema().isVisible(I)) + continue; LookupVisibleDecls(I->getNominatedNamespace(), Result, QualifiedNameLookup, InBaseClass, Consumer, Visited, IncludeDependentBases); @@ -3746,7 +3748,7 @@ void Sema::LookupVisibleDecls(Scope *S, LookupNameKind Kind, // Determine the set of using directives available during // unqualified name lookup. Scope *Initial = S; - UnqualUsingDirectiveSet UDirs; + UnqualUsingDirectiveSet UDirs(*this); if (getLangOpts().CPlusPlus) { // Find the first namespace or translation-unit scope. while (S && !isNamespaceOrTranslationUnitScope(S)) diff --git a/test/Modules/using-directive.cpp b/test/Modules/using-directive.cpp new file mode 100644 index 00000000000..6ca5c6eab4f --- /dev/null +++ b/test/Modules/using-directive.cpp @@ -0,0 +1,62 @@ +// RUN: %clang_cc1 -fmodules -fmodules-local-submodule-visibility -fno-modules-error-recovery -fno-spell-checking -verify %s + +#pragma clang module build a +module a { explicit module b {} explicit module c {} } +#pragma clang module contents + +#pragma clang module begin a.b +namespace b { int n; } +#pragma clang module end + +#pragma clang module begin a.c +#pragma clang module import a.b +namespace c { using namespace b; } +#pragma clang module end + +#pragma clang module begin a +#pragma clang module import a.c +using namespace c; +#pragma clang module end + +#pragma clang module endbuild + +#pragma clang module import a.b +void use1() { + (void)n; // expected-error {{use of undeclared identifier}} + (void)::n; // expected-error {{no member named 'n' in the global namespace}} + (void)b::n; +} +namespace b { + void use1_in_b() { (void)n; } +} +namespace c { + void use1_in_c() { (void)n; } // expected-error {{use of undeclared identifier}} +} + +#pragma clang module import a.c +void use2() { + (void)n; // expected-error {{use of undeclared identifier}} + (void)::n; // expected-error {{no member named 'n' in the global namespace}} + (void)b::n; + (void)c::n; +} +namespace b { + void use2_in_b() { (void)n; } +} +namespace c { + void use2_in_c() { (void)n; } +} + +#pragma clang module import a +void use3() { + (void)n; + (void)::n; + (void)b::n; + (void)c::n; +} +namespace b { + void use3_in_b() { (void)n; } +} +namespace c { + void use3_in_c() { (void)n; } +} -- GitLab