iains created this revision. Herald added a project: All. iains added reviewers: urnathan, ChuanqiXu. iains added a subscriber: clang-modules. iains published this revision for review. iains added a comment. Herald added a project: clang. Herald added a subscriber: cfe-commits.
we need to distinguish implementation and interface in code-gen. During code-gen (for initializers) we need to process module implementation units differently from interfaces. At present, this is not possible since the interface module is loaded as representing the "current module scope". We cannot treat an implementation unit as if it was a regular source, since we need to track module purview and associate definitions with the module. The solution here is to create a module type for the implementation which imports the interface per C++20: [module.unit/8] 'A module-declaration that contains neither an export-keyword nor a module-partition implicitly imports the primary module interface unit of the module as if by a module-import-declaration. Implementation modules are never serialized (-emit-module-interface for an implementation unit is diagnosed and rejected). Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D126959 Files: clang/include/clang/Basic/Module.h clang/include/clang/Lex/ModuleMap.h clang/lib/AST/Decl.cpp clang/lib/Frontend/FrontendActions.cpp clang/lib/Lex/ModuleMap.cpp clang/lib/Sema/SemaDecl.cpp clang/lib/Sema/SemaModule.cpp
Index: clang/lib/Sema/SemaModule.cpp =================================================================== --- clang/lib/Sema/SemaModule.cpp +++ clang/lib/Sema/SemaModule.cpp @@ -256,6 +256,7 @@ auto &Map = PP.getHeaderSearchInfo().getModuleMap(); Module *Mod; + ImportDecl *Import = nullptr; switch (MDK) { case ModuleDeclKind::Interface: case ModuleDeclKind::PartitionInterface: { @@ -288,6 +289,8 @@ // keyword nor a module-partition implicitly imports the primary // module interface unit of the module as if by a module-import- // declaration. + + // First find the interface we need to import. Mod = getModuleLoader().loadModule(ModuleLoc, {ModuleNameLoc}, Module::AllVisible, /*IsInclusionDirective=*/false); @@ -296,6 +299,13 @@ // Create an empty module interface unit for error recovery. Mod = Map.createModuleForInterfaceUnit(ModuleLoc, ModuleName, GlobalModuleFragment); + } else { + // Make the decl. + Import = ImportDecl::Create(Context, CurContext, ModuleLoc, Mod, + Path[0].second); + // now create the implementation module + Mod = Map.createModuleForImplementationUnit(ModuleLoc, ModuleName, + GlobalModuleFragment); } } break; @@ -335,8 +345,16 @@ // statements, so imports are allowed. ImportState = ModuleImportState::ImportAllowed; + // We already potentially made an implicit import (in the case of a module + // implementation unit importing its interface). Make this module visible + // and return the import decl to be added to the current TU. + if (Import) + VisibleModules.setVisible(Import->getImportedModule(), ModuleLoc); + // FIXME: Create a ModuleDecl. - return nullptr; + // If we made an implicit import of the module interface, then return the + // imported module decl. + return Import ? ConvertDeclToDeclGroup(Import) : nullptr; } Sema::DeclGroupPtrTy @@ -360,19 +378,17 @@ Diag(ModuleScopes.back().BeginLoc, diag::note_previous_definition); return nullptr; - case Module::ModuleInterfaceUnit: - break; - } - - if (!ModuleScopes.back().ModuleInterface) { + case Module::ModuleImplementationUnit: Diag(PrivateLoc, diag::err_private_module_fragment_not_module_interface); Diag(ModuleScopes.back().BeginLoc, diag::note_not_module_interface_add_export) << FixItHint::CreateInsertion(ModuleScopes.back().BeginLoc, "export "); return nullptr; + + case Module::ModuleInterfaceUnit: + break; } - // FIXME: Check this isn't a module interface partition. // FIXME: Check that this translation unit does not import any partitions; // such imports would violate [basic.link]/2's "shall be the only module unit" // restriction. Index: clang/lib/Sema/SemaDecl.cpp =================================================================== --- clang/lib/Sema/SemaDecl.cpp +++ clang/lib/Sema/SemaDecl.cpp @@ -1641,6 +1641,13 @@ if (NewM == OldM) return false; + // A module implementation unit has visibility of the decls in its implicitly + // imported interface. + if (getLangOpts().CPlusPlusModules && NewM && OldM && + NewM->Kind == Module::ModuleImplementationUnit && + OldM->Kind == Module::ModuleInterfaceUnit) + return NewM->Name == OldM->Name; + bool NewIsModuleInterface = NewM && NewM->isModulePurview(); bool OldIsModuleInterface = OldM && OldM->isModulePurview(); if (NewIsModuleInterface || OldIsModuleInterface) { Index: clang/lib/Lex/ModuleMap.cpp =================================================================== --- clang/lib/Lex/ModuleMap.cpp +++ clang/lib/Lex/ModuleMap.cpp @@ -881,6 +881,34 @@ return Result; } +Module *ModuleMap::createModuleForImplementationUnit(SourceLocation Loc, + StringRef Name, + Module *GlobalModule) { + assert(LangOpts.CurrentModule == Name && "module name mismatch"); + // The interface for this implementation must exist and be loaded. + assert(Modules[Name] && Modules[Name]->Kind == Module::ModuleInterfaceUnit && + "creating implementation module without an interface"); + + auto *Result = new Module(Name, Loc, nullptr, /*IsFramework*/ false, + /*IsExplicit*/ false, NumCreatedModules++); + Result->Kind = Module::ModuleImplementationUnit; + SourceModule = Result; + + // Reparent the current global module fragment as a submodule of this module. + for (auto &Submodule : PendingSubmodules) { + Submodule->setParent(Result); + Submodule.release(); // now owned by parent + } + PendingSubmodules.clear(); + + // Mark the main source file as being within the newly-created module so that + // declarations and macros are properly visibility-restricted to it. + auto *MainFile = SourceMgr.getFileEntryForID(SourceMgr.getMainFileID()); + assert(MainFile && "no input file for module implementation"); + + return Result; +} + Module *ModuleMap::createHeaderModule(StringRef Name, ArrayRef<Module::Header> Headers) { assert(LangOpts.CurrentModule == Name && "module name mismatch"); Index: clang/lib/Frontend/FrontendActions.cpp =================================================================== --- clang/lib/Frontend/FrontendActions.cpp +++ clang/lib/Frontend/FrontendActions.cpp @@ -831,6 +831,8 @@ return "Module Map Module"; case Module::ModuleInterfaceUnit: return "Interface Unit"; + case Module::ModuleImplementationUnit: + return "Implementation Unit (should never be serialized)"; case Module::ModulePartitionInterface: return "Partition Interface"; case Module::ModulePartitionImplementation: Index: clang/lib/AST/Decl.cpp =================================================================== --- clang/lib/AST/Decl.cpp +++ clang/lib/AST/Decl.cpp @@ -1565,6 +1565,7 @@ return nullptr; case Module::ModuleInterfaceUnit: + case Module::ModuleImplementationUnit: case Module::ModulePartitionInterface: case Module::ModulePartitionImplementation: return M; Index: clang/include/clang/Lex/ModuleMap.h =================================================================== --- clang/include/clang/Lex/ModuleMap.h +++ clang/include/clang/Lex/ModuleMap.h @@ -561,6 +561,14 @@ Module *createModuleForInterfaceUnit(SourceLocation Loc, StringRef Name, Module *GlobalModule); + /// Create a new module for a C++ module implementation unit. + /// The interface module for this implementation (implicitly imported) must + /// exist and be loaded and present in the modules map. + /// + /// \returns The newly-created module. + Module *createModuleForImplementationUnit(SourceLocation Loc, StringRef Name, + Module *GlobalModule); + /// Create a header module from the specified list of headers. Module *createHeaderModule(StringRef Name, ArrayRef<Module::Header> Headers); Index: clang/include/clang/Basic/Module.h =================================================================== --- clang/include/clang/Basic/Module.h +++ clang/include/clang/Basic/Module.h @@ -109,6 +109,9 @@ /// This is a C++20 module interface unit. ModuleInterfaceUnit, + /// This is a C++20 module implementation unit. + ModuleImplementationUnit, + /// This is a C++ 20 header unit. ModuleHeaderUnit, @@ -159,9 +162,16 @@ /// Does this Module scope describe part of the purview of a named C++ module? bool isModulePurview() const { - return Kind == ModuleInterfaceUnit || Kind == ModulePartitionInterface || - Kind == ModulePartitionImplementation || - Kind == PrivateModuleFragment; + switch (Kind) { + case ModuleInterfaceUnit: + case ModuleImplementationUnit: + case ModulePartitionInterface: + case ModulePartitionImplementation: + case PrivateModuleFragment: + return true; + default: + return false; + } } /// Does this Module scope describe a fragment of the global module within
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits