diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h index c2e4847d1d1e8..b08eb525602b6 100644 --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -447,8 +447,9 @@ class ASTContext : public RefCountedBase { }; llvm::DenseMap ModuleInitializers; - /// This is the top-level (C++20) Named module we are building. - Module *CurrentCXXNamedModule = nullptr; + /// For module code-gen cases, this is the top-level (C++20) Named module + /// we are building. + Module *TopLevelCXXNamedModule = nullptr; static constexpr unsigned ConstantArrayTypesLog2InitSize = 8; static constexpr unsigned GeneralTypesLog2InitSize = 9; @@ -1051,10 +1052,10 @@ class ASTContext : public RefCountedBase { ArrayRef getModuleInitializers(Module *M); /// Set the (C++20) module we are building. - void setCurrentNamedModule(Module *M); + void setNamedModuleForCodeGen(Module *M) { TopLevelCXXNamedModule = M; } /// Get module under construction, nullptr if this is not a C++20 module. - Module *getCurrentNamedModule() const { return CurrentCXXNamedModule; } + Module *getNamedModuleForCodeGen() const { return TopLevelCXXNamedModule; } TranslationUnitDecl *getTranslationUnitDecl() const { return TUDecl->getMostRecentDecl(); diff --git a/clang/include/clang/AST/DeclBase.h b/clang/include/clang/AST/DeclBase.h index f7d5b3a83141a..e0dc6dab7b334 100644 --- a/clang/include/clang/AST/DeclBase.h +++ b/clang/include/clang/AST/DeclBase.h @@ -644,9 +644,6 @@ class alignas(8) Decl { return getModuleOwnershipKind() > ModuleOwnershipKind::VisibleWhenImported; } - /// Whether this declaration comes from another module unit. - bool isInAnotherModuleUnit() const; - /// FIXME: Implement discarding declarations actually in global module /// fragment. See [module.global.frag]p3,4 for details. bool isDiscardedInGlobalModuleFragment() const { return false; } diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 4d68462e43e3e..5296d7000b5cc 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -2358,6 +2358,9 @@ class Sema final { return Entity->getOwningModule(); } + // Determine whether the module M belongs to the current TU. + bool isModuleUnitOfCurrentTU(const Module *M) const; + /// Make a merged definition of an existing hidden definition \p ND /// visible at the specified location. void makeMergedDefinitionVisible(NamedDecl *ND); diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index e1a230f7588c6..7fdbf4d32efe8 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -1153,13 +1153,6 @@ ArrayRef ASTContext::getModuleInitializers(Module *M) { return Inits->Initializers; } -void ASTContext::setCurrentNamedModule(Module *M) { - assert(M->isModulePurview()); - assert(!CurrentCXXNamedModule && - "We should set named module for ASTContext for only once"); - CurrentCXXNamedModule = M; -} - ExternCContextDecl *ASTContext::getExternCContextDecl() const { if (!ExternCContext) ExternCContext = ExternCContextDecl::Create(*this, getTranslationUnitDecl()); @@ -11929,7 +11922,7 @@ bool ASTContext::DeclMustBeEmitted(const Decl *D) { // Variables in other module units shouldn't be forced to be emitted. auto *VM = VD->getOwningModule(); if (VM && VM->getTopLevelModule()->isModulePurview() && - VM->getTopLevelModule() != getCurrentNamedModule()) + VM->getTopLevelModule() != getNamedModuleForCodeGen()) return false; // Variables that can be needed in other TUs are required. diff --git a/clang/lib/AST/DeclBase.cpp b/clang/lib/AST/DeclBase.cpp index 834beef49a444..f49945f434193 100644 --- a/clang/lib/AST/DeclBase.cpp +++ b/clang/lib/AST/DeclBase.cpp @@ -30,7 +30,6 @@ #include "clang/Basic/IdentifierTable.h" #include "clang/Basic/LLVM.h" #include "clang/Basic/LangOptions.h" -#include "clang/Basic/Module.h" #include "clang/Basic/ObjCRuntime.h" #include "clang/Basic/PartialDiagnostic.h" #include "clang/Basic/SourceLocation.h" @@ -1023,28 +1022,6 @@ bool Decl::isInExportDeclContext() const { return DC && isa(DC); } -bool Decl::isInAnotherModuleUnit() const { - auto *M = getOwningModule(); - - if (!M) - return false; - - M = M->getTopLevelModule(); - // FIXME: It is problematic if the header module lives in another module - // unit. Consider to fix this by techniques like - // ExternalASTSource::hasExternalDefinitions. - if (M->isHeaderLikeModule()) - return false; - - // A global module without parent implies that we're parsing the global - // module. So it can't be in another module unit. - if (M->isGlobalModule()) - return false; - - assert(M->isModulePurview() && "New module kind?"); - return M != getASTContext().getCurrentNamedModule(); -} - static Decl::Kind getKind(const Decl *D) { return D->getKind(); } static Decl::Kind getKind(const DeclContext *DC) { return DC->getDeclKind(); } diff --git a/clang/lib/CodeGen/CGDeclCXX.cpp b/clang/lib/CodeGen/CGDeclCXX.cpp index 04e42153519ae..9d7284cd0e37d 100644 --- a/clang/lib/CodeGen/CGDeclCXX.cpp +++ b/clang/lib/CodeGen/CGDeclCXX.cpp @@ -883,12 +883,12 @@ CodeGenModule::EmitCXXGlobalInitFunc() { // with priority emitted above. Module implementation units behave the same // way as a non-modular TU with imports. llvm::Function *Fn; - if (CXX20ModuleInits && getContext().getCurrentNamedModule() && - !getContext().getCurrentNamedModule()->isModuleImplementation()) { + if (CXX20ModuleInits && getContext().getNamedModuleForCodeGen() && + !getContext().getNamedModuleForCodeGen()->isModuleImplementation()) { SmallString<256> InitFnName; llvm::raw_svector_ostream Out(InitFnName); cast(getCXXABI().getMangleContext()) - .mangleModuleInitializer(getContext().getCurrentNamedModule(), Out); + .mangleModuleInitializer(getContext().getNamedModuleForCodeGen(), Out); Fn = CreateGlobalInitOrCleanUpFunction( FTy, llvm::Twine(InitFnName), FI, SourceLocation(), false, llvm::GlobalVariable::ExternalLinkage); diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index d3cde11a7e962..7534304b1878f 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -529,7 +529,7 @@ static void setVisibilityFromDLLStorageClass(const clang::LangOptions &LO, } void CodeGenModule::Release() { - Module *Primary = getContext().getCurrentNamedModule(); + Module *Primary = getContext().getNamedModuleForCodeGen(); if (CXX20ModuleInits && Primary && !Primary->isHeaderLikeModule()) EmitModuleInitializers(Primary); EmitDeferred(); diff --git a/clang/lib/Frontend/ASTUnit.cpp b/clang/lib/Frontend/ASTUnit.cpp index b1e7db1f6b39e..bda49fb68e460 100644 --- a/clang/lib/Frontend/ASTUnit.cpp +++ b/clang/lib/Frontend/ASTUnit.cpp @@ -879,7 +879,7 @@ std::unique_ptr ASTUnit::LoadFromASTFile( Module *M = HeaderInfo.lookupModule(AST->getLangOpts().CurrentModule); if (M && AST->getLangOpts().isCompilingModule() && M->isModulePurview()) - AST->Ctx->setCurrentNamedModule(M); + AST->Ctx->setNamedModuleForCodeGen(M); // Create an AST consumer, even though it isn't used. if (ToLoad >= LoadASTOnly) diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp index 5a2a3616d1136..e3a47334e2a2f 100644 --- a/clang/lib/Sema/SemaLookup.cpp +++ b/clang/lib/Sema/SemaLookup.cpp @@ -1905,11 +1905,14 @@ bool LookupResult::isReachableSlow(Sema &SemaRef, NamedDecl *D) { Module *DeclModule = SemaRef.getOwningModule(D); assert(DeclModule && "hidden decl has no owning module"); - // Entities in header like modules are reachable only if they're visible. - if (DeclModule->isHeaderLikeModule()) + // Entities in module map modules are reachable only if they're visible. + if (DeclModule->isModuleMapModule()) return false; - if (!D->isInAnotherModuleUnit()) + // If D comes from a module and SemaRef doesn't own a module, it implies D + // comes from another TU. In case SemaRef owns a module, we could judge if D + // comes from another TU by comparing the module unit. + if (SemaRef.isModuleUnitOfCurrentTU(DeclModule)) return true; // [module.reach]/p3: @@ -3890,7 +3893,7 @@ void Sema::ArgumentDependentLookup(DeclarationName Name, SourceLocation Loc, "bad export context"); // .. are attached to a named module M, do not appear in the // translation unit containing the point of the lookup.. - if (D->isInAnotherModuleUnit() && + if (!isModuleUnitOfCurrentTU(FM) && llvm::any_of(AssociatedClasses, [&](auto *E) { // ... and have the same innermost enclosing non-inline // namespace scope as a declaration of an associated entity diff --git a/clang/lib/Sema/SemaModule.cpp b/clang/lib/Sema/SemaModule.cpp index 58157950b3da3..53e453b117e17 100644 --- a/clang/lib/Sema/SemaModule.cpp +++ b/clang/lib/Sema/SemaModule.cpp @@ -389,7 +389,7 @@ Sema::ActOnModuleDecl(SourceLocation StartLoc, SourceLocation ModuleLoc, // statements, so imports are allowed. ImportState = ModuleImportState::ImportAllowed; - getASTContext().setCurrentNamedModule(Mod); + getASTContext().setNamedModuleForCodeGen(Mod); // We already potentially made an implicit import (in the case of a module // implementation unit importing its interface). Make this module visible @@ -1021,3 +1021,16 @@ void Sema::PopImplicitGlobalModuleFragment() { "left the wrong module scope, which is not global module fragment"); ModuleScopes.pop_back(); } + +bool Sema::isModuleUnitOfCurrentTU(const Module *M) const { + assert(M); + + Module *CurrentModuleUnit = getCurrentModule(); + + // If we are not in a module currently, M must not be the module unit of + // current TU. + if (!CurrentModuleUnit) + return false; + + return M->isSubModuleOf(CurrentModuleUnit->getTopLevelModule()); +} diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index 7f3e78c89f57a..135bf8053a964 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -6543,20 +6543,23 @@ void Sema::AddOverloadCandidate( } // Functions with internal linkage are only viable in the same module unit. - if (getLangOpts().CPlusPlusModules && Function->isInAnotherModuleUnit()) { - /// FIXME: Currently, the semantics of linkage in clang is slightly - /// different from the semantics in C++ spec. In C++ spec, only names - /// have linkage. So that all entities of the same should share one - /// linkage. But in clang, different entities of the same could have - /// different linkage. - NamedDecl *ND = Function; - if (auto *SpecInfo = Function->getTemplateSpecializationInfo()) - ND = SpecInfo->getTemplate(); - - if (ND->getFormalLinkage() == Linkage::InternalLinkage) { - Candidate.Viable = false; - Candidate.FailureKind = ovl_fail_module_mismatched; - return; + if (auto *MF = Function->getOwningModule()) { + if (getLangOpts().CPlusPlusModules && !MF->isModuleMapModule() && + !isModuleUnitOfCurrentTU(MF)) { + /// FIXME: Currently, the semantics of linkage in clang is slightly + /// different from the semantics in C++ spec. In C++ spec, only names + /// have linkage. So that all entities of the same should share one + /// linkage. But in clang, different entities of the same could have + /// different linkage. + NamedDecl *ND = Function; + if (auto *SpecInfo = Function->getTemplateSpecializationInfo()) + ND = SpecInfo->getTemplate(); + + if (ND->getFormalLinkage() == Linkage::InternalLinkage) { + Candidate.Viable = false; + Candidate.FailureKind = ovl_fail_module_mismatched; + return; + } } } diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index b3a180e909b3f..c6ba58724e774 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -2851,7 +2851,8 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams, NewDefaultLoc = NewTypeParm->getDefaultArgumentLoc(); SawDefaultArgument = true; - if (!OldTypeParm->isInAnotherModuleUnit()) + if (!OldTypeParm->getOwningModule() || + isModuleUnitOfCurrentTU(OldTypeParm->getOwningModule())) RedundantDefaultArg = true; else if (!getASTContext().isSameDefaultTemplateArgument(OldTypeParm, NewTypeParm)) { @@ -2903,7 +2904,8 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams, OldDefaultLoc = OldNonTypeParm->getDefaultArgumentLoc(); NewDefaultLoc = NewNonTypeParm->getDefaultArgumentLoc(); SawDefaultArgument = true; - if (!OldNonTypeParm->isInAnotherModuleUnit()) + if (!OldNonTypeParm->getOwningModule() || + isModuleUnitOfCurrentTU(OldNonTypeParm->getOwningModule())) RedundantDefaultArg = true; else if (!getASTContext().isSameDefaultTemplateArgument( OldNonTypeParm, NewNonTypeParm)) { @@ -2954,7 +2956,8 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams, OldDefaultLoc = OldTemplateParm->getDefaultArgument().getLocation(); NewDefaultLoc = NewTemplateParm->getDefaultArgument().getLocation(); SawDefaultArgument = true; - if (!OldTemplateParm->isInAnotherModuleUnit()) + if (!OldTemplateParm->getOwningModule() || + isModuleUnitOfCurrentTU(OldTemplateParm->getOwningModule())) RedundantDefaultArg = true; else if (!getASTContext().isSameDefaultTemplateArgument( OldTemplateParm, NewTemplateParm)) {