diff options
author | Richard Smith <richard-llvm@metafoo.co.uk> | 2017-07-05 07:47:11 +0000 |
---|---|---|
committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2017-07-05 07:47:11 +0000 |
commit | c5dd58546ce4d20cd71cc26cb790e7f91c8f908f (patch) | |
tree | a0e99619e42cf34795c1d662079bbec52905a30e /lib/Sema/SemaLookup.cpp | |
parent | 50f735245d0803846df474e9f3229ac7f4d9f9b0 (diff) |
[modules ts] Improve merging of module-private declarations.
These cases occur frequently for declarations in the global module (above the
module-declaration) in a Modules TS module interface. When we merge a
definition from another module into such a module-private definition, ensure
that we transitively make everything lexically within that definition visible
to that translation unit.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@307129 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Sema/SemaLookup.cpp')
-rw-r--r-- | lib/Sema/SemaLookup.cpp | 92 |
1 files changed, 60 insertions, 32 deletions
diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp index 63b3f6a1cb..85596ed52e 100644 --- a/lib/Sema/SemaLookup.cpp +++ b/lib/Sema/SemaLookup.cpp @@ -1396,6 +1396,13 @@ bool Sema::hasVisibleMergedDefinition(NamedDecl *Def) { } bool Sema::hasMergedDefinitionInCurrentModule(NamedDecl *Def) { + // FIXME: When not in local visibility mode, we can't tell the difference + // between a declaration being visible because we merged a local copy of + // the same declaration into it, and it being visible because its owning + // module is visible. + if (Def->getModuleOwnershipKind() == Decl::ModuleOwnershipKind::Visible && + getLangOpts().ModulesLocalVisibility) + return true; for (Module *Merged : Context.getModulesWithMergedDefinition(Def)) if (Merged->getTopLevelModuleName() == getLangOpts().CurrentModule) return true; @@ -1509,25 +1516,33 @@ bool LookupResult::isVisibleSlow(Sema &SemaRef, NamedDecl *D) { // FIXME: Don't assume that "same translation unit" means the same thing // as "not from an AST file". assert(D->isModulePrivate() && "hidden decl has no module"); - return !D->isFromASTFile(); + if (!D->isFromASTFile() || SemaRef.hasMergedDefinitionInCurrentModule(D)) + return true; + } else { + // If the owning module is visible, and the decl is not module private, + // then the decl is visible too. (Module private is ignored within the same + // top-level module.) + if (D->isModulePrivate() + ? DeclModule->getTopLevelModuleName() == + SemaRef.getLangOpts().CurrentModule || + SemaRef.hasMergedDefinitionInCurrentModule(D) + : SemaRef.isModuleVisible(DeclModule) || + SemaRef.hasVisibleMergedDefinition(D)) + return true; } - // If the owning module is visible, and the decl is not module private, - // then the decl is visible too. (Module private is ignored within the same - // top-level module.) - if (D->isModulePrivate() - ? DeclModule->getTopLevelModuleName() == - SemaRef.getLangOpts().CurrentModule || - SemaRef.hasMergedDefinitionInCurrentModule(D) - : SemaRef.isModuleVisible(DeclModule) || - SemaRef.hasVisibleMergedDefinition(D)) - return true; + // Determine whether a decl context is a file context for the purpose of + // visibility. This looks through some (export and linkage spec) transparent + // contexts, but not others (enums). + auto IsEffectivelyFileContext = [](const DeclContext *DC) { + return DC->isFileContext() || isa<LinkageSpecDecl>(DC) || + isa<ExportDecl>(DC); + }; - // If this declaration is not at namespace scope nor module-private, + // If this declaration is not at namespace scope // then it is visible if its lexical parent has a visible definition. DeclContext *DC = D->getLexicalDeclContext(); - if (!D->isModulePrivate() && DC && !DC->isFileContext() && - !isa<LinkageSpecDecl>(DC) && !isa<ExportDecl>(DC)) { + if (DC && !IsEffectivelyFileContext(DC)) { // For a parameter, check whether our current template declaration's // lexical context is visible, not whether there's some other visible // definition of it, because parameters aren't "within" the definition. @@ -1535,32 +1550,45 @@ bool LookupResult::isVisibleSlow(Sema &SemaRef, NamedDecl *D) { // In C++ we need to check for a visible definition due to ODR merging, // and in C we must not because each declaration of a function gets its own // set of declarations for tags in prototype scope. - if ((D->isTemplateParameter() || isa<ParmVarDecl>(D) - || (isa<FunctionDecl>(DC) && !SemaRef.getLangOpts().CPlusPlus)) - ? isVisible(SemaRef, cast<NamedDecl>(DC)) - : SemaRef.hasVisibleDefinition(cast<NamedDecl>(DC))) { - if (SemaRef.CodeSynthesisContexts.empty() && - // FIXME: Do something better in this case. - !SemaRef.getLangOpts().ModulesLocalVisibility) { - // Cache the fact that this declaration is implicitly visible because - // its parent has a visible definition. - D->setVisibleDespiteOwningModule(); - } - return true; + bool VisibleWithinParent; + if (D->isTemplateParameter() || isa<ParmVarDecl>(D) || + (isa<FunctionDecl>(DC) && !SemaRef.getLangOpts().CPlusPlus)) + VisibleWithinParent = isVisible(SemaRef, cast<NamedDecl>(DC)); + else if (D->isModulePrivate()) { + // A module-private declaration is only visible if an enclosing lexical + // parent was merged with another definition in the current module. + VisibleWithinParent = false; + do { + if (SemaRef.hasMergedDefinitionInCurrentModule(cast<NamedDecl>(DC))) { + VisibleWithinParent = true; + break; + } + DC = DC->getLexicalParent(); + } while (!IsEffectivelyFileContext(DC)); + } else { + VisibleWithinParent = SemaRef.hasVisibleDefinition(cast<NamedDecl>(DC)); } - return false; + + if (VisibleWithinParent && SemaRef.CodeSynthesisContexts.empty() && + // FIXME: Do something better in this case. + !SemaRef.getLangOpts().ModulesLocalVisibility) { + // Cache the fact that this declaration is implicitly visible because + // its parent has a visible definition. + D->setVisibleDespiteOwningModule(); + } + return VisibleWithinParent; } + // FIXME: All uses of DeclModule below this point should also check merged + // modules. + if (!DeclModule) + return false; + // Find the extra places where we need to look. llvm::DenseSet<Module*> &LookupModules = SemaRef.getLookupModules(); if (LookupModules.empty()) return false; - if (!DeclModule) { - DeclModule = SemaRef.getOwningModule(D); - assert(DeclModule && "hidden decl not from a module"); - } - // If our lookup set contains the decl's module, it's visible. if (LookupModules.count(DeclModule)) return true; |