summaryrefslogtreecommitdiffstats
path: root/clang/lib
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib')
-rw-r--r--clang/lib/AST/ASTContext.cpp25
-rw-r--r--clang/lib/AST/ASTDumper.cpp4
-rw-r--r--clang/lib/AST/Decl.cpp19
-rw-r--r--clang/lib/AST/DeclBase.cpp6
-rw-r--r--clang/lib/CodeGen/CodeGenModule.cpp2
-rw-r--r--clang/lib/Frontend/CompilerInstance.cpp5
-rw-r--r--clang/lib/Frontend/CompilerInvocation.cpp6
-rw-r--r--clang/lib/Lex/ModuleMap.cpp60
-rw-r--r--clang/lib/Lex/PPLexerChange.cpp19
-rw-r--r--clang/lib/Lex/PPMacroExpansion.cpp2
-rw-r--r--clang/lib/Parse/Parser.cpp8
-rw-r--r--clang/lib/Sema/Sema.cpp1
-rw-r--r--clang/lib/Sema/SemaDecl.cpp50
-rw-r--r--clang/lib/Sema/SemaLookup.cpp115
-rw-r--r--clang/lib/Sema/SemaType.cpp8
-rw-r--r--clang/lib/Serialization/ASTReader.cpp7
-rw-r--r--clang/lib/Serialization/ASTReaderDecl.cpp45
-rw-r--r--clang/lib/Serialization/ASTWriter.cpp4
18 files changed, 293 insertions, 93 deletions
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index 0fc9a4e96b0..770a2cf4df5 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -866,6 +866,31 @@ void ASTContext::PrintStats() const {
BumpAlloc.PrintStats();
}
+void ASTContext::mergeDefinitionIntoModule(NamedDecl *ND, Module *M,
+ bool NotifyListeners) {
+ if (NotifyListeners)
+ if (auto *Listener = getASTMutationListener())
+ Listener->RedefinedHiddenDefinition(ND, M);
+
+ if (getLangOpts().ModulesLocalVisibility)
+ MergedDefModules[ND].push_back(M);
+ else
+ ND->setHidden(false);
+}
+
+void ASTContext::deduplicateMergedDefinitonsFor(NamedDecl *ND) {
+ auto It = MergedDefModules.find(ND);
+ if (It == MergedDefModules.end())
+ return;
+
+ auto &Merged = It->second;
+ llvm::DenseSet<Module*> Found;
+ for (Module *&M : Merged)
+ if (!Found.insert(M).second)
+ M = nullptr;
+ Merged.erase(std::remove(Merged.begin(), Merged.end(), nullptr), Merged.end());
+}
+
ExternCContextDecl *ASTContext::getExternCContextDecl() const {
if (!ExternCContext)
ExternCContext = ExternCContextDecl::Create(*this, getTranslationUnitDecl());
diff --git a/clang/lib/AST/ASTDumper.cpp b/clang/lib/AST/ASTDumper.cpp
index 711c3292760..60cbb060113 100644
--- a/clang/lib/AST/ASTDumper.cpp
+++ b/clang/lib/AST/ASTDumper.cpp
@@ -977,8 +977,10 @@ void ASTDumper::dumpDecl(const Decl *D) {
dumpSourceRange(D->getSourceRange());
OS << ' ';
dumpLocation(D->getLocation());
- if (Module *M = D->getOwningModule())
+ if (Module *M = D->getImportedOwningModule())
OS << " in " << M->getFullModuleName();
+ else if (Module *M = D->getLocalOwningModule())
+ OS << " in (local) " << M->getFullModuleName();
if (const NamedDecl *ND = dyn_cast<NamedDecl>(D))
if (ND->isHidden())
OS << " hidden";
diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp
index 550810367d9..4a8eaaf99ad 100644
--- a/clang/lib/AST/Decl.cpp
+++ b/clang/lib/AST/Decl.cpp
@@ -44,6 +44,12 @@ bool Decl::isOutOfLine() const {
return !getLexicalDeclContext()->Equals(getDeclContext());
}
+TranslationUnitDecl::TranslationUnitDecl(ASTContext &ctx)
+ : Decl(TranslationUnit, nullptr, SourceLocation()),
+ DeclContext(TranslationUnit), Ctx(ctx), AnonymousNamespace(nullptr) {
+ Hidden = Ctx.getLangOpts().ModulesLocalVisibility;
+}
+
//===----------------------------------------------------------------------===//
// NamedDecl Implementation
//===----------------------------------------------------------------------===//
@@ -3934,10 +3940,17 @@ TypedefDecl *TypedefDecl::Create(ASTContext &C, DeclContext *DC,
void TypedefNameDecl::anchor() { }
-TagDecl *TypedefNameDecl::getAnonDeclWithTypedefName() const {
- if (auto *TT = getTypeSourceInfo()->getType()->getAs<TagType>())
- if (TT->getDecl()->getTypedefNameForAnonDecl() == this)
+TagDecl *TypedefNameDecl::getAnonDeclWithTypedefName(bool AnyRedecl) const {
+ if (auto *TT = getTypeSourceInfo()->getType()->getAs<TagType>()) {
+ auto *OwningTypedef = TT->getDecl()->getTypedefNameForAnonDecl();
+ auto *ThisTypedef = this;
+ if (AnyRedecl && OwningTypedef) {
+ OwningTypedef = OwningTypedef->getCanonicalDecl();
+ ThisTypedef = ThisTypedef->getCanonicalDecl();
+ }
+ if (OwningTypedef == ThisTypedef)
return TT->getDecl();
+ }
return nullptr;
}
diff --git a/clang/lib/AST/DeclBase.cpp b/clang/lib/AST/DeclBase.cpp
index 2f0fffea64c..79cadcfcb16 100644
--- a/clang/lib/AST/DeclBase.cpp
+++ b/clang/lib/AST/DeclBase.cpp
@@ -66,6 +66,12 @@ void *Decl::operator new(std::size_t Size, const ASTContext &Context,
void *Decl::operator new(std::size_t Size, const ASTContext &Ctx,
DeclContext *Parent, std::size_t Extra) {
assert(!Parent || &Parent->getParentASTContext() == &Ctx);
+ // With local visibility enabled, we track the owning module even for local
+ // declarations.
+ if (Ctx.getLangOpts().ModulesLocalVisibility) {
+ void *Buffer = ::operator new(sizeof(Module *) + Size + Extra, Ctx);
+ return new (Buffer) Module*(nullptr) + 1;
+ }
return ::operator new(Size + Extra, Ctx);
}
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index e0c4faad45a..7c091923b31 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -3359,7 +3359,7 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) {
auto *Import = cast<ImportDecl>(D);
// Ignore import declarations that come from imported modules.
- if (clang::Module *Owner = Import->getOwningModule()) {
+ if (clang::Module *Owner = Import->getImportedOwningModule()) {
if (getLangOpts().CurrentModule.empty() ||
Owner->getTopLevelModule()->Name == getLangOpts().CurrentModule)
break;
diff --git a/clang/lib/Frontend/CompilerInstance.cpp b/clang/lib/Frontend/CompilerInstance.cpp
index 2583ad199de..b64424a9aed 100644
--- a/clang/lib/Frontend/CompilerInstance.cpp
+++ b/clang/lib/Frontend/CompilerInstance.cpp
@@ -1637,6 +1637,11 @@ CompilerInstance::loadModule(SourceLocation ImportLoc,
void CompilerInstance::makeModuleVisible(Module *Mod,
Module::NameVisibilityKind Visibility,
SourceLocation ImportLoc) {
+ if (!ModuleManager)
+ createModuleManager();
+ if (!ModuleManager)
+ return;
+
ModuleManager->makeModuleVisible(Mod, Visibility, ImportLoc);
}
diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp
index 1d6723f33a0..11750224d8c 100644
--- a/clang/lib/Frontend/CompilerInvocation.cpp
+++ b/clang/lib/Frontend/CompilerInvocation.cpp
@@ -1597,6 +1597,12 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
<< Opts.CurrentModule << Opts.ImplementationOfModule;
}
+ // For now, we only support local submodule visibility in C++ (because we
+ // heavily depend on the ODR for merging redefinitions).
+ if (Opts.ModulesLocalVisibility && !Opts.CPlusPlus)
+ Diags.Report(diag::err_drv_argument_not_allowed_with)
+ << "-fmodules-local-submodule-visibility" << "C";
+
if (Arg *A = Args.getLastArg(OPT_faddress_space_map_mangling_EQ)) {
switch (llvm::StringSwitch<unsigned>(A->getValue())
.Case("target", LangOptions::ASMM_Target)
diff --git a/clang/lib/Lex/ModuleMap.cpp b/clang/lib/Lex/ModuleMap.cpp
index 29594994ff6..287ee146c6b 100644
--- a/clang/lib/Lex/ModuleMap.cpp
+++ b/clang/lib/Lex/ModuleMap.cpp
@@ -865,50 +865,44 @@ void ModuleMap::dump() {
}
bool ModuleMap::resolveExports(Module *Mod, bool Complain) {
- bool HadError = false;
- for (unsigned I = 0, N = Mod->UnresolvedExports.size(); I != N; ++I) {
- Module::ExportDecl Export = resolveExport(Mod, Mod->UnresolvedExports[I],
- Complain);
+ auto Unresolved = std::move(Mod->UnresolvedExports);
+ Mod->UnresolvedExports.clear();
+ for (auto &UE : Unresolved) {
+ Module::ExportDecl Export = resolveExport(Mod, UE, Complain);
if (Export.getPointer() || Export.getInt())
Mod->Exports.push_back(Export);
else
- HadError = true;
+ Mod->UnresolvedExports.push_back(UE);
}
- Mod->UnresolvedExports.clear();
- return HadError;
+ return !Mod->UnresolvedExports.empty();
}
bool ModuleMap::resolveUses(Module *Mod, bool Complain) {
- bool HadError = false;
- for (unsigned I = 0, N = Mod->UnresolvedDirectUses.size(); I != N; ++I) {
- Module *DirectUse =
- resolveModuleId(Mod->UnresolvedDirectUses[I], Mod, Complain);
+ auto Unresolved = std::move(Mod->UnresolvedDirectUses);
+ Mod->UnresolvedDirectUses.clear();
+ for (auto &UDU : Unresolved) {
+ Module *DirectUse = resolveModuleId(UDU, Mod, Complain);
if (DirectUse)
Mod->DirectUses.push_back(DirectUse);
else
- HadError = true;
+ Mod->UnresolvedDirectUses.push_back(UDU);
}
- Mod->UnresolvedDirectUses.clear();
- return HadError;
+ return !Mod->UnresolvedDirectUses.empty();
}
bool ModuleMap::resolveConflicts(Module *Mod, bool Complain) {
- bool HadError = false;
- for (unsigned I = 0, N = Mod->UnresolvedConflicts.size(); I != N; ++I) {
- Module *OtherMod = resolveModuleId(Mod->UnresolvedConflicts[I].Id,
- Mod, Complain);
- if (!OtherMod) {
- HadError = true;
- continue;
- }
-
- Module::Conflict Conflict;
- Conflict.Other = OtherMod;
- Conflict.Message = Mod->UnresolvedConflicts[I].Message;
- Mod->Conflicts.push_back(Conflict);
- }
+ auto Unresolved = std::move(Mod->UnresolvedConflicts);
Mod->UnresolvedConflicts.clear();
- return HadError;
+ for (auto &UC : Unresolved) {
+ if (Module *OtherMod = resolveModuleId(UC.Id, Mod, Complain)) {
+ Module::Conflict Conflict;
+ Conflict.Other = OtherMod;
+ Conflict.Message = UC.Message;
+ Mod->Conflicts.push_back(Conflict);
+ } else
+ Mod->UnresolvedConflicts.push_back(UC);
+ }
+ return !Mod->UnresolvedConflicts.empty();
}
Module *ModuleMap::inferModuleFromLocation(FullSourceLoc Loc) {
@@ -1759,7 +1753,13 @@ void ModuleMapParser::parseHeaderDecl(MMToken::TokenKind LeadingToken,
// If Clang supplies this header but the underlying system does not,
// just silently swap in our builtin version. Otherwise, we'll end
// up adding both (later).
- if (!File && BuiltinFile) {
+ //
+ // For local visibility, entirely replace the system file with our
+ // one and textually include the system one. We need to pass macros
+ // from our header to the system one if we #include_next it.
+ //
+ // FIXME: Can we do this in all cases?
+ if (BuiltinFile && (!File || Map.LangOpts.ModulesLocalVisibility)) {
File = BuiltinFile;
RelativePathName = BuiltinPathName;
BuiltinFile = nullptr;
diff --git a/clang/lib/Lex/PPLexerChange.cpp b/clang/lib/Lex/PPLexerChange.cpp
index 4af68b0b80a..ddc3fa646b9 100644
--- a/clang/lib/Lex/PPLexerChange.cpp
+++ b/clang/lib/Lex/PPLexerChange.cpp
@@ -615,9 +615,21 @@ void Preprocessor::EnterSubmodule(Module *M, SourceLocation ImportLoc) {
auto &Info = BuildingSubmoduleStack.back();
Info.Macros.swap(Macros);
// Save our visible modules set. This is guaranteed to clear the set.
- if (getLangOpts().ModulesLocalVisibility)
+ if (getLangOpts().ModulesLocalVisibility) {
Info.VisibleModules = std::move(VisibleModules);
+ // Resolve as much of the module definition as we can now, before we enter
+ // one if its headers.
+ // FIXME: Can we enable Complain here?
+ ModuleMap &ModMap = getHeaderSearchInfo().getModuleMap();
+ ModMap.resolveExports(M, /*Complain=*/false);
+ ModMap.resolveUses(M, /*Complain=*/false);
+ ModMap.resolveConflicts(M, /*Complain=*/false);
+
+ // This module is visible to itself.
+ makeModuleVisible(M, ImportLoc);
+ }
+
// Determine the set of starting macros for this submodule.
// FIXME: If we re-enter a submodule, should we restore its MacroDirectives?
auto &StartingMacros = getLangOpts().ModulesLocalVisibility
@@ -628,7 +640,7 @@ void Preprocessor::EnterSubmodule(Module *M, SourceLocation ImportLoc) {
// FIXME: Do this lazily, when each macro name is first referenced.
for (auto &Macro : StartingMacros) {
MacroState MS(Macro.second.getLatest());
- MS.setOverriddenMacros(*this, MS.getOverriddenMacros());
+ MS.setOverriddenMacros(*this, Macro.second.getOverriddenMacros());
Macros.insert(std::make_pair(Macro.first, std::move(MS)));
}
}
@@ -712,6 +724,7 @@ void Preprocessor::LeaveSubmodule() {
BuildingSubmoduleStack.pop_back();
// A nested #include makes the included submodule visible.
- if (!BuildingSubmoduleStack.empty() || !getLangOpts().ModulesLocalVisibility)
+ if (!BuildingSubmoduleStack.empty() ||
+ !getLangOpts().ModulesLocalVisibility)
makeModuleVisible(LeavingMod, ImportLoc);
}
diff --git a/clang/lib/Lex/PPMacroExpansion.cpp b/clang/lib/Lex/PPMacroExpansion.cpp
index 7121578c8fb..aa4e8b67644 100644
--- a/clang/lib/Lex/PPMacroExpansion.cpp
+++ b/clang/lib/Lex/PPMacroExpansion.cpp
@@ -238,7 +238,7 @@ void Preprocessor::dumpMacroInfo(const IdentifierInfo *II) {
llvm::errs() << " active";
else if (!VisibleModules.isVisible(MM->getOwningModule()))
llvm::errs() << " hidden";
- else
+ else if (MM->getMacroInfo())
llvm::errs() << " overridden";
if (!MM->overrides().empty()) {
diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp
index 697fda9215d..a45eaa0e333 100644
--- a/clang/lib/Parse/Parser.cpp
+++ b/clang/lib/Parse/Parser.cpp
@@ -541,8 +541,14 @@ bool Parser::ParseTopLevelDecl(DeclGroupPtrTy &Result) {
return false;
case tok::annot_module_begin:
+ Actions.ActOnModuleBegin(Tok.getLocation(), reinterpret_cast<Module *>(
+ Tok.getAnnotationValue()));
+ ConsumeToken();
+ return false;
+
case tok::annot_module_end:
- // FIXME: Update visibility based on the submodule we're in.
+ Actions.ActOnModuleEnd(Tok.getLocation(), reinterpret_cast<Module *>(
+ Tok.getAnnotationValue()));
ConsumeToken();
return false;
diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp
index 6825dfa41fa..e9619b369c1 100644
--- a/clang/lib/Sema/Sema.cpp
+++ b/clang/lib/Sema/Sema.cpp
@@ -99,6 +99,7 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
GlobalNewDeleteDeclared(false),
TUKind(TUKind),
NumSFINAEErrors(0),
+ CachedFakeTopLevelModule(nullptr),
AccessCheckingSFINAE(false), InNonInstantiationSFINAEContext(false),
NonInstantiationEntries(0), ArgumentPackSubstitutionIndex(-1),
CurrentInstantiationScope(nullptr), DisableTypoCorrection(false),
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 8be7286f66f..8c079f8647d 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -1784,11 +1784,11 @@ NamedDecl *Sema::LazilyCreateBuiltin(IdentifierInfo *II, unsigned ID,
/// should not consider because they are not permitted to conflict, e.g.,
/// because they come from hidden sub-modules and do not refer to the same
/// entity.
-static void filterNonConflictingPreviousDecls(ASTContext &context,
+static void filterNonConflictingPreviousDecls(Sema &S,
NamedDecl *decl,
LookupResult &previous){
// This is only interesting when modules are enabled.
- if (!context.getLangOpts().Modules)
+ if (!S.getLangOpts().Modules)
return;
// Empty sets are uninteresting.
@@ -1800,7 +1800,7 @@ static void filterNonConflictingPreviousDecls(ASTContext &context,
NamedDecl *old = filter.next();
// Non-hidden declarations are never ignored.
- if (!old->isHidden())
+ if (S.isVisible(old))
continue;
if (!old->isExternallyVisible())
@@ -1814,11 +1814,11 @@ static void filterNonConflictingPreviousDecls(ASTContext &context,
/// entity if their types are the same.
/// FIXME: This is notionally doing the same thing as ASTReaderDecl's
/// isSameEntity.
-static void filterNonConflictingPreviousTypedefDecls(ASTContext &Context,
+static void filterNonConflictingPreviousTypedefDecls(Sema &S,
TypedefNameDecl *Decl,
LookupResult &Previous) {
// This is only interesting when modules are enabled.
- if (!Context.getLangOpts().Modules)
+ if (!S.getLangOpts().Modules)
return;
// Empty sets are uninteresting.
@@ -1830,19 +1830,19 @@ static void filterNonConflictingPreviousTypedefDecls(ASTContext &Context,
NamedDecl *Old = Filter.next();
// Non-hidden declarations are never ignored.
- if (!Old->isHidden())
+ if (S.isVisible(Old))
continue;
// Declarations of the same entity are not ignored, even if they have
// different linkages.
if (auto *OldTD = dyn_cast<TypedefNameDecl>(Old)) {
- if (Context.hasSameType(OldTD->getUnderlyingType(),
- Decl->getUnderlyingType()))
+ if (S.Context.hasSameType(OldTD->getUnderlyingType(),
+ Decl->getUnderlyingType()))
continue;
// If both declarations give a tag declaration a typedef name for linkage
// purposes, then they declare the same entity.
- if (OldTD->getAnonDeclWithTypedefName() &&
+ if (OldTD->getAnonDeclWithTypedefName(/*AnyRedecl*/true) &&
Decl->getAnonDeclWithTypedefName())
continue;
}
@@ -1957,7 +1957,7 @@ void Sema::MergeTypedefNameDecl(TypedefNameDecl *New, LookupResult &OldDecls) {
return New->setInvalidDecl();
if (auto *OldTD = dyn_cast<TypedefNameDecl>(Old)) {
- auto *OldTag = OldTD->getAnonDeclWithTypedefName();
+ auto *OldTag = OldTD->getAnonDeclWithTypedefName(/*AnyRedecl*/true);
auto *NewTag = New->getAnonDeclWithTypedefName();
NamedDecl *Hidden = nullptr;
if (getLangOpts().CPlusPlus && OldTag && NewTag &&
@@ -5065,7 +5065,7 @@ Sema::ActOnTypedefNameDecl(Scope *S, DeclContext *DC, TypedefNameDecl *NewTD,
// in an outer scope, it isn't the same thing.
FilterLookupForScope(Previous, DC, S, /*ConsiderLinkage*/false,
/*AllowInlineNamespace*/false);
- filterNonConflictingPreviousTypedefDecls(Context, NewTD, Previous);
+ filterNonConflictingPreviousTypedefDecls(*this, NewTD, Previous);
if (!Previous.empty()) {
Redeclaration = true;
MergeTypedefNameDecl(NewTD, Previous);
@@ -6381,7 +6381,7 @@ bool Sema::CheckVariableDeclaration(VarDecl *NewVD, LookupResult &Previous) {
Previous.setShadowed();
// Filter out any non-conflicting previous declarations.
- filterNonConflictingPreviousDecls(Context, NewVD, Previous);
+ filterNonConflictingPreviousDecls(*this, NewVD, Previous);
if (!Previous.empty()) {
MergeVarDecl(NewVD, Previous);
@@ -7930,7 +7930,7 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
!Previous.isShadowed();
// Filter out any non-conflicting previous declarations.
- filterNonConflictingPreviousDecls(Context, NewFD, Previous);
+ filterNonConflictingPreviousDecls(*this, NewFD, Previous);
bool Redeclaration = false;
NamedDecl *OldDecl = nullptr;
@@ -7985,7 +7985,7 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
// Check for a previous extern "C" declaration with this name.
if (!Redeclaration &&
checkForConflictWithNonVisibleExternC(*this, NewFD, Previous)) {
- filterNonConflictingPreviousDecls(Context, NewFD, Previous);
+ filterNonConflictingPreviousDecls(*this, NewFD, Previous);
if (!Previous.empty()) {
// This is an extern "C" declaration with the same name as a previous
// declaration, and thus redeclares that entity...
@@ -14076,6 +14076,8 @@ DeclResult Sema::ActOnModuleImport(SourceLocation AtLoc,
if (!Mod)
return true;
+ VisibleModules.setVisible(Mod, ImportLoc);
+
checkModuleImportContext(*this, Mod, ImportLoc, CurContext);
// FIXME: we should support importing a submodule within a different submodule
@@ -14113,6 +14115,25 @@ void Sema::ActOnModuleInclude(SourceLocation DirectiveLoc, Module *Mod) {
// FIXME: Should we synthesize an ImportDecl here?
getModuleLoader().makeModuleVisible(Mod, Module::AllVisible, DirectiveLoc);
+ VisibleModules.setVisible(Mod, DirectiveLoc);
+}
+
+void Sema::ActOnModuleBegin(SourceLocation DirectiveLoc, Module *Mod) {
+ checkModuleImportContext(*this, Mod, DirectiveLoc, CurContext);
+
+ if (getLangOpts().ModulesLocalVisibility)
+ VisibleModulesStack.push_back(std::move(VisibleModules));
+ VisibleModules.setVisible(Mod, DirectiveLoc);
+}
+
+void Sema::ActOnModuleEnd(SourceLocation DirectiveLoc, Module *Mod) {
+ checkModuleImportContext(*this, Mod, DirectiveLoc, CurContext);
+
+ if (getLangOpts().ModulesLocalVisibility) {
+ VisibleModules = std::move(VisibleModulesStack.back());
+ VisibleModulesStack.pop_back();
+ VisibleModules.setVisible(Mod, DirectiveLoc);
+ }
}
void Sema::createImplicitModuleImportForErrorRecovery(SourceLocation Loc,
@@ -14130,6 +14151,7 @@ void Sema::createImplicitModuleImportForErrorRecovery(SourceLocation Loc,
// Make the module visible.
getModuleLoader().makeModuleVisible(Mod, Module::AllVisible, Loc);
+ VisibleModules.setVisible(Mod, Loc);
}
void Sema::ActOnPragmaRedefineExtname(IdentifierInfo* Name,
diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp
index 5e7e34a8928..a8a143fa9a9 100644
--- a/clang/lib/Sema/SemaLookup.cpp
+++ b/clang/lib/Sema/SemaLookup.cpp
@@ -24,6 +24,7 @@
#include "clang/AST/ExprCXX.h"
#include "clang/Basic/Builtins.h"
#include "clang/Basic/LangOptions.h"
+#include "clang/Lex/HeaderSearch.h"
#include "clang/Lex/ModuleLoader.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Sema/DeclSpec.h"
@@ -1171,15 +1172,59 @@ static Decl *getInstantiatedFrom(Decl *D, MemberSpecializationInfo *MSInfo) {
return MSInfo->isExplicitSpecialization() ? D : MSInfo->getInstantiatedFrom();
}
+Module *Sema::getOwningModule(Decl *Entity) {
+ // If it's imported, grab its owning module.
+ Module *M = Entity->getImportedOwningModule();
+ if (M || !isa<NamedDecl>(Entity) || !cast<NamedDecl>(Entity)->isHidden())
+ return M;
+ assert(!Entity->isFromASTFile() &&
+ "hidden entity from AST file has no owning module");
+
+ // It's local and hidden; grab or compute its owning module.
+ M = Entity->getLocalOwningModule();
+ if (M)
+ return M;
+
+ if (auto *Containing =
+ PP.getModuleContainingLocation(Entity->getLocation())) {
+ M = Containing;
+ } else if (Entity->isInvalidDecl() || Entity->getLocation().isInvalid()) {
+ // Don't bother tracking visibility for invalid declarations with broken
+ // locations.
+ cast<NamedDecl>(Entity)->setHidden(false);
+ } else {
+ // We need to assign a module to an entity that exists outside of any
+ // module, so that we can hide it from modules that we textually enter.
+ // Invent a fake module for all such entities.
+ if (!CachedFakeTopLevelModule) {
+ CachedFakeTopLevelModule =
+ PP.getHeaderSearchInfo().getModuleMap().findOrCreateModule(
+ "<top-level>", nullptr, false, false).first;
+
+ auto &SrcMgr = PP.getSourceManager();
+ SourceLocation StartLoc =
+ SrcMgr.getLocForStartOfFile(SrcMgr.getMainFileID());
+ auto &TopLevel =
+ VisibleModulesStack.empty() ? VisibleModules : VisibleModulesStack[0];
+ TopLevel.setVisible(CachedFakeTopLevelModule, StartLoc);
+ }
+
+ M = CachedFakeTopLevelModule;
+ }
+
+ if (M)
+ Entity->setLocalOwningModule(M);
+ return M;
+}
+
void Sema::makeMergedDefinitionVisible(NamedDecl *ND, SourceLocation Loc) {
- if (auto *Listener = getASTMutationListener())
- Listener->RedefinedHiddenDefinition(ND,
- PP.getModuleContainingLocation(Loc));
- ND->setHidden(false);
+ auto *M = PP.getModuleContainingLocation(Loc);
+ assert(M && "hidden definition not in any module");
+ Context.mergeDefinitionIntoModule(ND, M);
}
/// \brief Find the module in which the given declaration was defined.
-static Module *getDefiningModule(Decl *Entity) {
+static Module *getDefiningModule(Sema &S, Decl *Entity) {
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(Entity)) {
// If this function was instantiated from a template, the defining module is
// the module containing the pattern.
@@ -1201,15 +1246,16 @@ static Module *getDefiningModule(Decl *Entity) {
// from a template.
DeclContext *Context = Entity->getDeclContext();
if (Context->isFileContext())
- return Entity->getOwningModule();
- return getDefiningModule(cast<Decl>(Context));
+ return S.getOwningModule(Entity);
+ return getDefiningModule(S, cast<Decl>(Context));
}
llvm::DenseSet<Module*> &Sema::getLookupModules() {
unsigned N = ActiveTemplateInstantiations.size();
for (unsigned I = ActiveTemplateInstantiationLookupModules.size();
I != N; ++I) {
- Module *M = getDefiningModule(ActiveTemplateInstantiations[I].Entity);
+ Module *M =
+ getDefiningModule(*this, ActiveTemplateInstantiations[I].Entity);
if (M && !LookupModulesCache.insert(M).second)
M = nullptr;
ActiveTemplateInstantiationLookupModules.push_back(M);
@@ -1217,6 +1263,13 @@ llvm::DenseSet<Module*> &Sema::getLookupModules() {
return LookupModulesCache;
}
+bool Sema::hasVisibleMergedDefinition(NamedDecl *Def) {
+ for (Module *Merged : Context.getModulesWithMergedDefinition(Def))
+ if (isModuleVisible(Merged))
+ return true;
+ return false;
+}
+
/// \brief Determine whether a declaration is visible to name lookup.
///
/// This routine determines whether the declaration D is visible in the current
@@ -1227,8 +1280,24 @@ llvm::DenseSet<Module*> &Sema::getLookupModules() {
/// your module can see, including those later on in your module).
bool LookupResult::isVisibleSlow(Sema &SemaRef, NamedDecl *D) {
assert(D->isHidden() && "should not call this: not in slow case");
- Module *DeclModule = D->getOwningModule();
- assert(DeclModule && "hidden decl not from a module");
+ Module *DeclModule = SemaRef.getOwningModule(D);
+ if (!DeclModule) {
+ // getOwningModule() may have decided the declaration should not be hidden.
+ assert(!D->isHidden() && "hidden decl not from a module");
+ 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->isFromASTFile() || !D->isModulePrivate()) {
+ if (SemaRef.isModuleVisible(DeclModule))
+ return true;
+ // Also check merged definitions.
+ if (SemaRef.getLangOpts().ModulesLocalVisibility &&
+ SemaRef.hasVisibleMergedDefinition(D))
+ return true;
+ }
// If this declaration is not at namespace scope nor module-private,
// then it is visible if its lexical parent has a visible definition.
@@ -1236,7 +1305,9 @@ bool LookupResult::isVisibleSlow(Sema &SemaRef, NamedDecl *D) {
if (!D->isModulePrivate() &&
DC && !DC->isFileContext() && !isa<LinkageSpecDecl>(DC)) {
if (SemaRef.hasVisibleDefinition(cast<NamedDecl>(DC))) {
- if (SemaRef.ActiveTemplateInstantiations.empty()) {
+ if (SemaRef.ActiveTemplateInstantiations.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->setHidden(false);
@@ -1269,6 +1340,10 @@ bool LookupResult::isVisibleSlow(Sema &SemaRef, NamedDecl *D) {
return false;
}
+bool Sema::isVisibleSlow(const NamedDecl *D) {
+ return LookupResult::isVisible(*this, const_cast<NamedDecl*>(D));
+}
+
/// \brief Retrieve the visible declaration corresponding to D, if any.
///
/// This routine determines whether the declaration D is visible in the current
@@ -4524,18 +4599,18 @@ void Sema::diagnoseTypo(const TypoCorrection &Correction,
/// Find which declaration we should import to provide the definition of
/// the given declaration.
-static const NamedDecl *getDefinitionToImport(const NamedDecl *D) {
- if (const VarDecl *VD = dyn_cast<VarDecl>(D))
+static NamedDecl *getDefinitionToImport(NamedDecl *D) {
+ if (VarDecl *VD = dyn_cast<VarDecl>(D))
return VD->getDefinition();
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
- return FD->isDefined(FD) ? FD : nullptr;
- if (const TagDecl *TD = dyn_cast<TagDecl>(D))
+ return FD->isDefined(FD) ? const_cast<FunctionDecl*>(FD) : nullptr;
+ if (TagDecl *TD = dyn_cast<TagDecl>(D))
return TD->getDefinition();
- if (const ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(D))
+ if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(D))
return ID->getDefinition();
- if (const ObjCProtocolDecl *PD = dyn_cast<ObjCProtocolDecl>(D))
+ if (ObjCProtocolDecl *PD = dyn_cast<ObjCProtocolDecl>(D))
return PD->getDefinition();
- if (const TemplateDecl *TD = dyn_cast<TemplateDecl>(D))
+ if (TemplateDecl *TD = dyn_cast<TemplateDecl>(D))
return getDefinitionToImport(TD->getTemplatedDecl());
return nullptr;
}
@@ -4568,10 +4643,10 @@ void Sema::diagnoseTypo(const TypoCorrection &Correction,
// Suggest importing a module providing the definition of this entity, if
// possible.
- const NamedDecl *Def = getDefinitionToImport(Decl);
+ NamedDecl *Def = getDefinitionToImport(Decl);
if (!Def)
Def = Decl;
- Module *Owner = Def->getOwningModule();
+ Module *Owner = getOwningModule(Def);
assert(Owner && "definition of hidden declaration is not in a module");
Diag(Correction.getCorrectionRange().getBegin(),
diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp
index 8729f481d6d..0c6eac1e95a 100644
--- a/clang/lib/Sema/SemaType.cpp
+++ b/clang/lib/Sema/SemaType.cpp
@@ -5148,7 +5148,11 @@ bool Sema::hasVisibleDefinition(NamedDecl *D, NamedDecl **Suggested) {
// If this definition was instantiated from a template, map back to the
// pattern from which it was instantiated.
- if (auto *RD = dyn_cast<CXXRecordDecl>(D)) {
+ if (isa<TagDecl>(D) && cast<TagDecl>(D)->isBeingDefined()) {
+ // We're in the middle of defining it; this definition should be treated
+ // as visible.
+ return true;
+ } else if (auto *RD = dyn_cast<CXXRecordDecl>(D)) {
if (auto *Pattern = RD->getTemplateInstantiationPattern())
RD = Pattern;
D = RD->getDefinition();
@@ -5231,7 +5235,7 @@ bool Sema::RequireCompleteTypeImpl(SourceLocation Loc, QualType T,
// repeating the diagnostic.
// FIXME: Add a Fix-It that imports the corresponding module or includes
// the header.
- Module *Owner = SuggestedDef->getOwningModule();
+ Module *Owner = getOwningModule(SuggestedDef);
Diag(Loc, diag::err_module_private_definition)
<< T << Owner->getFullModuleName();
Diag(SuggestedDef->getLocation(), diag::note_previous_definition);
diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp
index c4b4aec24a0..08fd923f47d 100644
--- a/clang/lib/Serialization/ASTReader.cpp
+++ b/clang/lib/Serialization/ASTReader.cpp
@@ -7997,7 +7997,7 @@ void ASTReader::getInputFiles(ModuleFile &F,
std::string ASTReader::getOwningModuleNameForDiagnostic(const Decl *D) {
// If we know the owning module, use it.
- if (Module *M = D->getOwningModule())
+ if (Module *M = D->getImportedOwningModule())
return M->getFullModuleName();
// Otherwise, use the name of the top-level module the decl is within.
@@ -8168,6 +8168,11 @@ void ASTReader::finishPendingActions() {
MD->setLazyBody(PB->second);
}
PendingBodies.clear();
+
+ // Do some cleanup.
+ for (auto *ND : PendingMergedDefinitionsToDeduplicate)
+ getContext().deduplicateMergedDefinitonsFor(ND);
+ PendingMergedDefinitionsToDeduplicate.clear();
}
void ASTReader::diagnoseOdrViolations() {
diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp
index 4ff81d8d92b..ed684537a66 100644
--- a/clang/lib/Serialization/ASTReaderDecl.cpp
+++ b/clang/lib/Serialization/ASTReaderDecl.cpp
@@ -458,24 +458,28 @@ void ASTDeclReader::VisitDecl(Decl *D) {
D->FromASTFile = true;
D->setModulePrivate(Record[Idx++]);
D->Hidden = D->isModulePrivate();
-
+
// Determine whether this declaration is part of a (sub)module. If so, it
// may not yet be visible.
if (unsigned SubmoduleID = readSubmoduleID(Record, Idx)) {
// Store the owning submodule ID in the declaration.
D->setOwningModuleID(SubmoduleID);
-
- // Module-private declarations are never visible, so there is no work to do.
- if (!D->isModulePrivate()) {
- if (Module *Owner = Reader.getSubmodule(SubmoduleID)) {
- if (Owner->NameVisibility != Module::AllVisible) {
- // The owning module is not visible. Mark this declaration as hidden.
- D->Hidden = true;
-
- // Note that this declaration was hidden because its owning module is
- // not yet visible.
- Reader.HiddenNamesMap[Owner].push_back(D);
- }
+
+ if (D->Hidden) {
+ // Module-private declarations are never visible, so there is no work to do.
+ } else if (Reader.getContext().getLangOpts().ModulesLocalVisibility) {
+ // If local visibility is being tracked, this declaration will become
+ // hidden and visible as the owning module does. Inform Sema that this
+ // declaration might not be visible.
+ D->Hidden = true;
+ } else if (Module *Owner = Reader.getSubmodule(SubmoduleID)) {
+ if (Owner->NameVisibility != Module::AllVisible) {
+ // The owning module is not visible. Mark this declaration as hidden.
+ D->Hidden = true;
+
+ // Note that this declaration was hidden because its owning module is
+ // not yet visible.
+ Reader.HiddenNamesMap[Owner].push_back(D);
}
}
}
@@ -1399,7 +1403,12 @@ void ASTDeclReader::MergeDefinitionData(
// If MergeDD is visible or becomes visible, make the definition visible.
if (!MergeDD.Definition->isHidden())
DD.Definition->Hidden = false;
- else {
+ else if (Reader.getContext().getLangOpts().ModulesLocalVisibility) {
+ Reader.getContext().mergeDefinitionIntoModule(
+ DD.Definition, MergeDD.Definition->getImportedOwningModule(),
+ /*NotifyListeners*/ false);
+ Reader.PendingMergedDefinitionsToDeduplicate.insert(DD.Definition);
+ } else {
auto SubmoduleID = MergeDD.Definition->getOwningModuleID();
assert(SubmoduleID && "hidden definition in no module");
Reader.HiddenNamesMap[Reader.getSubmodule(SubmoduleID)].push_back(
@@ -3813,7 +3822,13 @@ void ASTDeclReader::UpdateDecl(Decl *D, ModuleFile &ModuleFile,
case UPD_DECL_EXPORTED:
unsigned SubmoduleID = readSubmoduleID(Record, Idx);
Module *Owner = SubmoduleID ? Reader.getSubmodule(SubmoduleID) : nullptr;
- if (Owner && Owner->NameVisibility != Module::AllVisible) {
+ if (Reader.getContext().getLangOpts().ModulesLocalVisibility) {
+ // FIXME: This doesn't send the right notifications if there are
+ // ASTMutationListeners other than an ASTWriter.
+ Reader.getContext().mergeDefinitionIntoModule(cast<NamedDecl>(D), Owner,
+ /*NotifyListeners*/false);
+ Reader.PendingMergedDefinitionsToDeduplicate.insert(cast<NamedDecl>(D));
+ } else if (Owner && Owner->NameVisibility != Module::AllVisible) {
// If Owner is made visible at some later point, make this declaration
// visible too.
Reader.HiddenNamesMap[Owner].push_back(D);
diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp
index 1e7fc5cdb6a..2963b32857a 100644
--- a/clang/lib/Serialization/ASTWriter.cpp
+++ b/clang/lib/Serialization/ASTWriter.cpp
@@ -5746,6 +5746,8 @@ void ASTWriter::DeclarationMarkedOpenMPThreadPrivate(const Decl *D) {
void ASTWriter::RedefinedHiddenDefinition(const NamedDecl *D, Module *M) {
assert(!WritingAST && "Already writing the AST!");
assert(D->isHidden() && "expected a hidden declaration");
- assert(D->isFromASTFile() && "hidden decl not from AST file");
+ if (!D->isFromASTFile())
+ return;
+
DeclUpdates[D].push_back(DeclUpdate(UPD_DECL_EXPORTED, M));
}
OpenPOWER on IntegriCloud