diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h index b08eb525602b6..c2e4847d1d1e8 100644 --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -447,9 +447,8 @@ class ASTContext : public RefCountedBase { }; llvm::DenseMap ModuleInitializers; - /// For module code-gen cases, this is the top-level (C++20) Named module - /// we are building. - Module *TopLevelCXXNamedModule = nullptr; + /// This is the top-level (C++20) Named module we are building. + Module *CurrentCXXNamedModule = nullptr; static constexpr unsigned ConstantArrayTypesLog2InitSize = 8; static constexpr unsigned GeneralTypesLog2InitSize = 9; @@ -1052,10 +1051,10 @@ class ASTContext : public RefCountedBase { ArrayRef getModuleInitializers(Module *M); /// Set the (C++20) module we are building. - void setNamedModuleForCodeGen(Module *M) { TopLevelCXXNamedModule = M; } + void setCurrentNamedModule(Module *M); /// Get module under construction, nullptr if this is not a C++20 module. - Module *getNamedModuleForCodeGen() const { return TopLevelCXXNamedModule; } + Module *getCurrentNamedModule() const { return CurrentCXXNamedModule; } TranslationUnitDecl *getTranslationUnitDecl() const { return TUDecl->getMostRecentDecl(); diff --git a/clang/include/clang/AST/DeclBase.h b/clang/include/clang/AST/DeclBase.h index be76d1648b9ac..571f1f10387bf 100644 --- a/clang/include/clang/AST/DeclBase.h +++ b/clang/include/clang/AST/DeclBase.h @@ -644,6 +644,9 @@ class alignas(8) Decl { return getModuleOwnershipKind() > ModuleOwnershipKind::VisibleWhenImported; } + /// Whether this declaration comes from another module unit. + bool isInCurrentModuleUnit() 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 5296d7000b5cc..4d68462e43e3e 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -2358,9 +2358,6 @@ 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 de65c3cc47b9b..3441c069b4b83 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -1153,6 +1153,13 @@ 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()); diff --git a/clang/lib/AST/DeclBase.cpp b/clang/lib/AST/DeclBase.cpp index f49945f434193..fe458b67dcab0 100644 --- a/clang/lib/AST/DeclBase.cpp +++ b/clang/lib/AST/DeclBase.cpp @@ -30,6 +30,7 @@ #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" @@ -1022,6 +1023,26 @@ bool Decl::isInExportDeclContext() const { return DC && isa(DC); } +bool Decl::isInCurrentModuleUnit() const { + auto *M = getOwningModule(); + + if (!M) + return true; + + 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 true; + + if (M->isGlobalModule()) + return true; + + 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 9d7284cd0e37d..04e42153519ae 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().getNamedModuleForCodeGen() && - !getContext().getNamedModuleForCodeGen()->isModuleImplementation()) { + if (CXX20ModuleInits && getContext().getCurrentNamedModule() && + !getContext().getCurrentNamedModule()->isModuleImplementation()) { SmallString<256> InitFnName; llvm::raw_svector_ostream Out(InitFnName); cast(getCXXABI().getMangleContext()) - .mangleModuleInitializer(getContext().getNamedModuleForCodeGen(), Out); + .mangleModuleInitializer(getContext().getCurrentNamedModule(), 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 7534304b1878f..d3cde11a7e962 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().getNamedModuleForCodeGen(); + Module *Primary = getContext().getCurrentNamedModule(); if (CXX20ModuleInits && Primary && !Primary->isHeaderLikeModule()) EmitModuleInitializers(Primary); EmitDeferred(); diff --git a/clang/lib/Frontend/ASTUnit.cpp b/clang/lib/Frontend/ASTUnit.cpp index bda49fb68e460..b1e7db1f6b39e 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->setNamedModuleForCodeGen(M); + AST->Ctx->setCurrentNamedModule(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 202e5f49ac4a1..b59ee727d267b 100644 --- a/clang/lib/Sema/SemaLookup.cpp +++ b/clang/lib/Sema/SemaLookup.cpp @@ -1905,14 +1905,11 @@ bool LookupResult::isReachableSlow(Sema &SemaRef, NamedDecl *D) { Module *DeclModule = SemaRef.getOwningModule(D); assert(DeclModule && "hidden decl has no owning module"); - // Entities in module map modules are reachable only if they're visible. - if (DeclModule->isModuleMapModule()) + // Entities in header like modules are reachable only if they're visible. + if (DeclModule->isHeaderLikeModule()) return false; - // 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)) + if (D->isInCurrentModuleUnit()) return true; // [module.reach]/p3: @@ -3892,7 +3889,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 (!isModuleUnitOfCurrentTU(FM) && + if (!D->isInCurrentModuleUnit() && 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 53e453b117e17..58157950b3da3 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().setNamedModuleForCodeGen(Mod); + getASTContext().setCurrentNamedModule(Mod); // We already potentially made an implicit import (in the case of a module // implementation unit importing its interface). Make this module visible @@ -1021,16 +1021,3 @@ 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 135bf8053a964..419adff028c28 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -6543,23 +6543,20 @@ void Sema::AddOverloadCandidate( } // Functions with internal linkage are only viable in the same module unit. - 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; - } + if (getLangOpts().CPlusPlusModules && !Function->isInCurrentModuleUnit()) { + /// 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 c6ba58724e774..bd0aa8edb11fb 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -2851,8 +2851,7 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams, NewDefaultLoc = NewTypeParm->getDefaultArgumentLoc(); SawDefaultArgument = true; - if (!OldTypeParm->getOwningModule() || - isModuleUnitOfCurrentTU(OldTypeParm->getOwningModule())) + if (OldTypeParm->isInCurrentModuleUnit()) RedundantDefaultArg = true; else if (!getASTContext().isSameDefaultTemplateArgument(OldTypeParm, NewTypeParm)) { @@ -2904,8 +2903,7 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams, OldDefaultLoc = OldNonTypeParm->getDefaultArgumentLoc(); NewDefaultLoc = NewNonTypeParm->getDefaultArgumentLoc(); SawDefaultArgument = true; - if (!OldNonTypeParm->getOwningModule() || - isModuleUnitOfCurrentTU(OldNonTypeParm->getOwningModule())) + if (OldNonTypeParm->isInCurrentModuleUnit()) RedundantDefaultArg = true; else if (!getASTContext().isSameDefaultTemplateArgument( OldNonTypeParm, NewNonTypeParm)) { @@ -2956,8 +2954,7 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams, OldDefaultLoc = OldTemplateParm->getDefaultArgument().getLocation(); NewDefaultLoc = NewTemplateParm->getDefaultArgument().getLocation(); SawDefaultArgument = true; - if (!OldTemplateParm->getOwningModule() || - isModuleUnitOfCurrentTU(OldTemplateParm->getOwningModule())) + if (OldTemplateParm->isInCurrentModuleUnit()) RedundantDefaultArg = true; else if (!getASTContext().isSameDefaultTemplateArgument( OldTemplateParm, NewTemplateParm)) {