diff options
Diffstat (limited to 'clang')
21 files changed, 344 insertions, 41 deletions
diff --git a/clang/include/clang/Basic/DiagnosticFrontendKinds.td b/clang/include/clang/Basic/DiagnosticFrontendKinds.td index d58552b345f..90303f0500f 100644 --- a/clang/include/clang/Basic/DiagnosticFrontendKinds.td +++ b/clang/include/clang/Basic/DiagnosticFrontendKinds.td @@ -153,7 +153,7 @@ def warn_incompatible_analyzer_plugin_api : Warning< InGroup<DiagGroup<"analyzer-incompatible-plugin"> >; def note_incompatible_analyzer_plugin_api : Note< "current API version is '%0', but plugin was compiled with version '%1'">; - + def err_module_map_not_found : Error<"module map file '%0' not found">, DefaultFatal; def err_missing_module_name : Error< @@ -187,6 +187,10 @@ def remark_module_build_done : Remark<"finished building module '%0'">, def err_conflicting_module_names : Error< "conflicting module names specified: '-fmodule-name=%0' and " "'-fmodule-implementation-of %1'">; +def err_module_already_loaded : Error< + "module '%0' has already been loaded; cannot load module file '%1'">; +def err_module_file_not_module : Error< + "AST file '%0' was not built as a module">, DefaultFatal; def err_missing_vfs_overlay_file : Error< "virtual filesystem overlay file '%0' not found">, DefaultFatal; diff --git a/clang/include/clang/Basic/DiagnosticSerializationKinds.td b/clang/include/clang/Basic/DiagnosticSerializationKinds.td index 1c81fc60906..5de2c6acba8 100644 --- a/clang/include/clang/Basic/DiagnosticSerializationKinds.td +++ b/clang/include/clang/Basic/DiagnosticSerializationKinds.td @@ -52,7 +52,9 @@ def err_pch_with_compiler_errors : Error< "PCH file contains compiler errors">; def err_imported_module_not_found : Error< - "module '%0' imported by AST file '%1' not found">, DefaultFatal; + "module '%0' in AST file '%1' (imported by AST file '%2') " + "is not defined in any loaded module map file; " + "maybe you need to load '%3'?">, DefaultFatal; def err_imported_module_modmap_changed : Error< "module '%0' imported by AST file '%1' found in a different module map file" " (%2) than when the importing AST file was built (%3)">, DefaultFatal; diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index 0d1a4e90ee6..f0b384b979b 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -641,7 +641,7 @@ def fbuild_session_file : Joined<["-"], "fbuild-session-file=">, def fmodules_validate_once_per_build_session : Flag<["-"], "fmodules-validate-once-per-build-session">, Group<i_Group>, Flags<[CC1Option]>, HelpText<"Don't verify input files for the modules if the module has been " - "successfully validate or loaded during this build session">; + "successfully validated or loaded during this build session">; def fmodules_validate_system_headers : Flag<["-"], "fmodules-validate-system-headers">, Group<i_Group>, Flags<[CC1Option]>, HelpText<"Validate the system headers that a module depends on when loading the module">; @@ -657,6 +657,9 @@ def fmodule_name : JoinedOrSeparate<["-"], "fmodule-name=">, Group<f_Group>, def fmodule_map_file : Joined<["-"], "fmodule-map-file=">, Group<f_Group>, Flags<[DriverOption,CC1Option]>, MetaVarName<"<file>">, HelpText<"Load this module map file">; +def fmodule_file : Joined<["-"], "fmodule-file=">, + Group<f_Group>, Flags<[DriverOption,CC1Option]>, + HelpText<"Load this precompiled module file">, MetaVarName<"<file>">; def fmodules_ignore_macro : Joined<["-"], "fmodules-ignore-macro=">, Group<f_Group>, Flags<[CC1Option]>, HelpText<"Ignore the definition of the given macro when building and loading modules">; def fmodules_decluse : Flag <["-"], "fmodules-decluse">, Group<f_Group>, diff --git a/clang/include/clang/Frontend/CompilerInstance.h b/clang/include/clang/Frontend/CompilerInstance.h index 40e3069e66b..6f15331e8fd 100644 --- a/clang/include/clang/Frontend/CompilerInstance.h +++ b/clang/include/clang/Frontend/CompilerInstance.h @@ -691,6 +691,8 @@ public: // Create module manager. void createModuleManager(); + ModuleLoadResult loadModuleFile(StringRef FileName, SourceLocation Loc); + ModuleLoadResult loadModule(SourceLocation ImportLoc, ModuleIdPath Path, Module::NameVisibilityKind Visibility, bool IsInclusionDirective) override; diff --git a/clang/include/clang/Frontend/FrontendOptions.h b/clang/include/clang/Frontend/FrontendOptions.h index 04b7c1b2c23..aa1e25380a1 100644 --- a/clang/include/clang/Frontend/FrontendOptions.h +++ b/clang/include/clang/Frontend/FrontendOptions.h @@ -230,6 +230,10 @@ public: /// The list of plugins to load. std::vector<std::string> Plugins; + /// \brief The list of additional prebuilt module files to load before + /// processing the input. + std::vector<std::string> ModuleFiles; + /// \brief The list of AST files to merge. std::vector<std::string> ASTMergeFiles; diff --git a/clang/include/clang/Serialization/ASTReader.h b/clang/include/clang/Serialization/ASTReader.h index 1b3d46a6e47..730a257bca8 100644 --- a/clang/include/clang/Serialization/ASTReader.h +++ b/clang/include/clang/Serialization/ASTReader.h @@ -206,6 +206,9 @@ public: std::unique_ptr<ASTReaderListener> Second) : First(std::move(First)), Second(std::move(Second)) {} + std::unique_ptr<ASTReaderListener> takeFirst() { return std::move(First); } + std::unique_ptr<ASTReaderListener> takeSecond() { return std::move(Second); } + bool ReadFullVersionInformation(StringRef FullVersion) override; void ReadModuleName(StringRef ModuleName) override; void ReadModuleMapFile(StringRef ModuleMapPath) override; @@ -1389,12 +1392,17 @@ public: void makeNamesVisible(const HiddenNames &Names, Module *Owner, bool FromFinalization); + /// \brief Take the AST callbacks listener. + std::unique_ptr<ASTReaderListener> takeListener() { + return std::move(Listener); + } + /// \brief Set the AST callbacks listener. void setListener(std::unique_ptr<ASTReaderListener> Listener) { this->Listener = std::move(Listener); } - /// \brief Add an AST callbak listener. + /// \brief Add an AST callback listener. /// /// Takes ownership of \p L. void addListener(std::unique_ptr<ASTReaderListener> L) { @@ -1404,6 +1412,30 @@ public: Listener = std::move(L); } + /// RAII object to temporarily add an AST callback listener. + class ListenerScope { + ASTReader &Reader; + bool Chained; + + public: + ListenerScope(ASTReader &Reader, std::unique_ptr<ASTReaderListener> L) + : Reader(Reader), Chained(false) { + auto Old = Reader.takeListener(); + if (Old) { + Chained = true; + L = llvm::make_unique<ChainedASTReaderListener>(std::move(L), + std::move(Old)); + } + Reader.setListener(std::move(L)); + } + ~ListenerScope() { + auto New = Reader.takeListener(); + if (Chained) + Reader.setListener(static_cast<ChainedASTReaderListener *>(New.get()) + ->takeSecond()); + } + }; + /// \brief Set the AST deserialization listener. void setDeserializationListener(ASTDeserializationListener *Listener, bool TakeOwnership = false); diff --git a/clang/include/clang/Serialization/Module.h b/clang/include/clang/Serialization/Module.h index 49520390559..a889e8b6540 100644 --- a/clang/include/clang/Serialization/Module.h +++ b/clang/include/clang/Serialization/Module.h @@ -42,10 +42,11 @@ namespace reader { /// \brief Specifies the kind of module that has been loaded. enum ModuleKind { - MK_Module, ///< File is a module proper. - MK_PCH, ///< File is a PCH file treated as such. - MK_Preamble, ///< File is a PCH file treated as the preamble. - MK_MainFile ///< File is a PCH file treated as the actual main file. + MK_ImplicitModule, ///< File is an implicitly-loaded module. + MK_ExplicitModule, ///< File is an explicitly-loaded module. + MK_PCH, ///< File is a PCH file treated as such. + MK_Preamble, ///< File is a PCH file treated as the preamble. + MK_MainFile ///< File is a PCH file treated as the actual main file. }; /// \brief Information about the contents of a DeclContext. diff --git a/clang/lib/Driver/Tools.cpp b/clang/lib/Driver/Tools.cpp index 822d55b7cbf..d8f3edd8957 100644 --- a/clang/lib/Driver/Tools.cpp +++ b/clang/lib/Driver/Tools.cpp @@ -3833,7 +3833,11 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // definitions. Args.AddAllArgs(CmdArgs, options::OPT_fmodule_map_file); - // -fmodule-cache-path specifies where our module files should be written. + // -fmodule-file can be used to specify files containing precompiled modules. + Args.AddAllArgs(CmdArgs, options::OPT_fmodule_file); + + // -fmodule-cache-path specifies where our implicitly-built module files + // should be written. SmallString<128> ModuleCachePath; if (Arg *A = Args.getLastArg(options::OPT_fmodules_cache_path)) ModuleCachePath = A->getValue(); diff --git a/clang/lib/Frontend/ASTUnit.cpp b/clang/lib/Frontend/ASTUnit.cpp index 8742a54c01c..19fafa3370a 100644 --- a/clang/lib/Frontend/ASTUnit.cpp +++ b/clang/lib/Frontend/ASTUnit.cpp @@ -2776,7 +2776,8 @@ struct PCHLocatorInfo { static bool PCHLocator(serialization::ModuleFile &M, void *UserData) { PCHLocatorInfo &Info = *static_cast<PCHLocatorInfo*>(UserData); switch (M.Kind) { - case serialization::MK_Module: + case serialization::MK_ImplicitModule: + case serialization::MK_ExplicitModule: return true; // skip dependencies. case serialization::MK_PCH: Info.Mod = &M; diff --git a/clang/lib/Frontend/CompilerInstance.cpp b/clang/lib/Frontend/CompilerInstance.cpp index e1803d0f311..ba0743abd26 100644 --- a/clang/lib/Frontend/CompilerInstance.cpp +++ b/clang/lib/Frontend/CompilerInstance.cpp @@ -1040,7 +1040,7 @@ static bool compileAndLoadModule(CompilerInstance &ImportingInstance, // Try to read the module file, now that we've compiled it. ASTReader::ASTReadResult ReadResult = ImportingInstance.getModuleManager()->ReadAST( - ModuleFileName, serialization::MK_Module, ImportLoc, + ModuleFileName, serialization::MK_ImplicitModule, ImportLoc, ModuleLoadCapabilities); if (ReadResult == ASTReader::OutOfDate && @@ -1268,6 +1268,53 @@ void CompilerInstance::createModuleManager() { } ModuleLoadResult +CompilerInstance::loadModuleFile(StringRef FileName, SourceLocation Loc) { + if (!ModuleManager) + createModuleManager(); + if (!ModuleManager) + return ModuleLoadResult(); + + // Load the module if this is the first time we've been told about this file. + auto *MF = ModuleManager->getModuleManager().lookup(FileName); + if (!MF) { + struct ReadModuleNameListener : ASTReaderListener { + std::function<void(StringRef)> OnRead; + ReadModuleNameListener(std::function<void(StringRef)> F) : OnRead(F) {} + void ReadModuleName(StringRef ModuleName) override { OnRead(ModuleName); } + }; + + // Register listener to track the modules that are loaded by explicitly + // loading a module file. We suppress any attempts to implicitly load + // module files for any such module. + ASTReader::ListenerScope OnReadModuleName( + *ModuleManager, + llvm::make_unique<ReadModuleNameListener>([&](StringRef ModuleName) { + auto &PP = getPreprocessor(); + auto *NameII = PP.getIdentifierInfo(ModuleName); + auto *Module = PP.getHeaderSearchInfo().lookupModule(ModuleName, false); + if (!KnownModules.insert(std::make_pair(NameII, Module)).second) + getDiagnostics().Report(Loc, diag::err_module_already_loaded) + << ModuleName << FileName; + })); + + if (ModuleManager->ReadAST(FileName, serialization::MK_ExplicitModule, Loc, + ASTReader::ARR_None) != ASTReader::Success) + return ModuleLoadResult(); + + MF = ModuleManager->getModuleManager().lookup(FileName); + assert(MF && "unexpectedly failed to load module file"); + } + + if (MF->ModuleName.empty()) { + getDiagnostics().Report(Loc, diag::err_module_file_not_module) + << FileName; + return ModuleLoadResult(); + } + auto *Module = PP->getHeaderSearchInfo().lookupModule(MF->ModuleName, false); + return ModuleLoadResult(Module, false); +} + +ModuleLoadResult CompilerInstance::loadModule(SourceLocation ImportLoc, ModuleIdPath Path, Module::NameVisibilityKind Visibility, @@ -1330,8 +1377,9 @@ CompilerInstance::loadModule(SourceLocation ImportLoc, // Try to load the module file. unsigned ARRFlags = ASTReader::ARR_OutOfDate | ASTReader::ARR_Missing; - switch (ModuleManager->ReadAST(ModuleFileName, serialization::MK_Module, - ImportLoc, ARRFlags)) { + switch (ModuleManager->ReadAST(ModuleFileName, + serialization::MK_ImplicitModule, ImportLoc, + ARRFlags)) { case ASTReader::Success: break; diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index 373842d2381..2c4118c2792 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -838,7 +838,8 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, Opts.ASTDumpLookups = Args.hasArg(OPT_ast_dump_lookups); Opts.UseGlobalModuleIndex = !Args.hasArg(OPT_fno_modules_global_index); Opts.GenerateGlobalModuleIndex = Opts.UseGlobalModuleIndex; - + Opts.ModuleFiles = Args.getAllArgValues(OPT_fmodule_file); + Opts.CodeCompleteOpts.IncludeMacros = Args.hasArg(OPT_code_completion_macros); Opts.CodeCompleteOpts.IncludeCodePatterns diff --git a/clang/lib/Frontend/FrontendAction.cpp b/clang/lib/Frontend/FrontendAction.cpp index 8760f5094d4..1c9384218ad 100644 --- a/clang/lib/Frontend/FrontendAction.cpp +++ b/clang/lib/Frontend/FrontendAction.cpp @@ -321,7 +321,7 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, // FIXME: should not overwrite ASTMutationListener when parsing model files? if (!isModelParsingAction()) CI.getASTContext().setASTMutationListener(Consumer->GetASTMutationListener()); - + if (!CI.getPreprocessorOpts().ChainedIncludes.empty()) { // Convert headers to PCH and chain them. IntrusiveRefCntPtr<ExternalSemaSource> source, FinalReader; @@ -383,6 +383,17 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, "doesn't support modules"); } + // If we were asked to load any module files, do so now. Don't make any names + // from those modules visible. + for (const auto &ModuleFile : CI.getFrontendOpts().ModuleFiles) { + // FIXME: Use a better source location here. Perhaps inject something + // into the predefines buffer to represent these module files. + if (!CI.loadModuleFile(ModuleFile, + CI.getSourceManager().getLocForStartOfFile( + CI.getSourceManager().getMainFileID()))) + goto failure; + } + // If there is a layout overrides file, attach an external AST source that // provides the layouts from that file. if (!CI.getFrontendOpts().OverrideRecordLayoutsFile.empty() && diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp index 3a6e6551dbf..f3181546320 100644 --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -389,14 +389,14 @@ bool PCHValidator::ReadDiagnosticOptions( // If the original import came from a file explicitly generated by the user, // don't check the diagnostic mappings. // FIXME: currently this is approximated by checking whether this is not a - // module import. + // module import of an implicitly-loaded module file. // Note: ModuleMgr.rbegin() may not be the current module, but it must be in // the transitive closure of its imports, since unrelated modules cannot be // imported until after this module finishes validation. ModuleFile *TopImport = *ModuleMgr.rbegin(); while (!TopImport->ImportedBy.empty()) TopImport = TopImport->ImportedBy[0]; - if (TopImport->Kind != MK_Module) + if (TopImport->Kind != MK_ImplicitModule) return false; StringRef ModuleName = TopImport->ModuleName; @@ -781,7 +781,7 @@ IdentifierInfo *ASTIdentifierLookupTrait::ReadData(const internal_key_type& k, } } - if (F.Kind == MK_Module) { + if (F.Kind == MK_ImplicitModule || F.Kind == MK_ExplicitModule) { // Macro definitions are stored from newest to oldest, so reverse them // before registering them. llvm::SmallVector<unsigned, 8> MacroSizes; @@ -1238,7 +1238,8 @@ bool ASTReader::ReadSLocEntry(int ID) { SrcMgr::CharacteristicKind FileCharacter = (SrcMgr::CharacteristicKind)Record[2]; SourceLocation IncludeLoc = ReadSourceLocation(*F, Record[1]); - if (IncludeLoc.isInvalid() && F->Kind == MK_Module) { + if (IncludeLoc.isInvalid() && + (F->Kind == MK_ImplicitModule || F->Kind == MK_ExplicitModule)) { IncludeLoc = getImportLocation(F); } unsigned Code = SLocEntryCursor.ReadCode(); @@ -1284,7 +1285,7 @@ std::pair<SourceLocation, StringRef> ASTReader::getModuleImportLoc(int ID) { // Find which module file this entry lands in. ModuleFile *M = GlobalSLocEntryMap.find(-ID)->second; - if (M->Kind != MK_Module) + if (M->Kind != MK_ImplicitModule && M->Kind != MK_ExplicitModule) return std::make_pair(SourceLocation(), ""); // FIXME: Can we map this down to a particular submodule? That would be @@ -1773,7 +1774,8 @@ void ASTReader::resolvePendingMacro(IdentifierInfo *II, const PendingMacroInfo &PMInfo) { assert(II); - if (PMInfo.M->Kind != MK_Module) { + if (PMInfo.M->Kind != MK_ImplicitModule && + PMInfo.M->Kind != MK_ExplicitModule) { installPCHMacroDirectives(II, *PMInfo.M, PMInfo.PCHMacroData.MacroDirectivesOffset); return; @@ -1797,7 +1799,7 @@ void ASTReader::resolvePendingMacro(IdentifierInfo *II, void ASTReader::installPCHMacroDirectives(IdentifierInfo *II, ModuleFile &M, uint64_t Offset) { - assert(M.Kind != MK_Module); + assert(M.Kind != MK_ImplicitModule && M.Kind != MK_ExplicitModule); BitstreamCursor &Cursor = M.MacroCursor; SavedStreamPosition SavedPosition(Cursor); @@ -2279,7 +2281,8 @@ ASTReader::ReadControlBlock(ModuleFile &F, unsigned N = NumUserInputs; if (ValidateSystemInputs || - (HSOpts.ModulesValidateOncePerBuildSession && F.Kind == MK_Module)) + (HSOpts.ModulesValidateOncePerBuildSession && + F.Kind == MK_ImplicitModule)) N = NumInputs; for (unsigned I = 0; I < N; ++I) { @@ -3191,7 +3194,7 @@ ASTReader::ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities) { break; case IMPORTED_MODULES: { - if (F.Kind != MK_Module) { + if (F.Kind != MK_ImplicitModule && F.Kind != MK_ExplicitModule) { // If we aren't loading a module (which has its own exports), make // all of the imported modules visible. // FIXME: Deal with macros-only imports. @@ -3289,29 +3292,40 @@ ASTReader::ReadModuleMapFileBlock(RecordData &Record, ModuleFile &F, unsigned Idx = 0; F.ModuleMapPath = ReadString(Record, Idx); + if (F.Kind == MK_ExplicitModule) { + // For an explicitly-loaded module, we don't care whether the original + // module map file exists or matches. + return Success; + } + // Try to resolve ModuleName in the current header search context and // verify that it is found in the same module map file as we saved. If the // top-level AST file is a main file, skip this check because there is no // usable header search context. assert(!F.ModuleName.empty() && - "MODULE_NAME should come before MOUDLE_MAP_FILE"); - if (F.Kind == MK_Module && (*ModuleMgr.begin())->Kind != MK_MainFile) { + "MODULE_NAME should come before MODULE_MAP_FILE"); + if (F.Kind == MK_ImplicitModule && + (*ModuleMgr.begin())->Kind != MK_MainFile) { + // An implicitly-loaded module file should have its module listed in some + // module map file that we've already loaded. Module *M = PP.getHeaderSearchInfo().lookupModule(F.ModuleName); - if (!M) { + auto &Map = PP.getHeaderSearchInfo().getModuleMap(); + const FileEntry *ModMap = M ? Map.getModuleMapFileForUniquing(M) : nullptr; + if (!ModMap) { assert(ImportedBy && "top-level import should be verified"); if ((ClientLoadCapabilities & ARR_Missing) == 0) - Diag(diag::err_imported_module_not_found) - << F.ModuleName << ImportedBy->FileName; + Diag(diag::err_imported_module_not_found) << F.ModuleName << F.FileName + << ImportedBy->FileName + << F.ModuleMapPath; return Missing; } + assert(M->Name == F.ModuleName && "found module with different name"); + // Check the primary module map file. - auto &Map = PP.getHeaderSearchInfo().getModuleMap(); const FileEntry *StoredModMap = FileMgr.getFile(F.ModuleMapPath); - const FileEntry *ModMap = Map.getModuleMapFileForUniquing(M); if (StoredModMap == nullptr || StoredModMap != ModMap) { assert(ModMap && "found module is missing module map file"); - assert(M->Name == F.ModuleName && "found module with different name"); assert(ImportedBy && "top-level import should be verified"); if ((ClientLoadCapabilities & ARR_OutOfDate) == 0) Diag(diag::err_imported_module_modmap_changed) @@ -3696,7 +3710,7 @@ ASTReader::ASTReadResult ASTReader::ReadAST(const std::string &FileName, // in the filesystem). for (unsigned I = 0, N = Loaded.size(); I != N; ++I) { ImportedModule &M = Loaded[I]; - if (M.Mod->Kind == MK_Module) { + if (M.Mod->Kind == MK_ImplicitModule) { updateModuleTimestamp(*M.Mod); } } @@ -3729,7 +3743,7 @@ ASTReader::ReadASTCore(StringRef FileName, break; case ModuleManager::Missing: - // The module file was missing; if the client handle handle, that, return + // The module file was missing; if the client can handle that, return // it. if (ClientLoadCapabilities & ARR_Missing) return Missing; @@ -8196,14 +8210,16 @@ void ASTReader::finishPendingActions() { for (unsigned IDIdx = 0, NumIDs = GlobalIDs.size(); IDIdx != NumIDs; ++IDIdx) { const PendingMacroInfo &Info = GlobalIDs[IDIdx]; - if (Info.M->Kind != MK_Module) + if (Info.M->Kind != MK_ImplicitModule && + Info.M->Kind != MK_ExplicitModule) resolvePendingMacro(II, Info); } // Handle module imports. for (unsigned IDIdx = 0, NumIDs = GlobalIDs.size(); IDIdx != NumIDs; ++IDIdx) { const PendingMacroInfo &Info = GlobalIDs[IDIdx]; - if (Info.M->Kind == MK_Module) + if (Info.M->Kind == MK_ImplicitModule || + Info.M->Kind == MK_ExplicitModule) resolvePendingMacro(II, Info); } } diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp index a3b773f6fc5..b5a447d197d 100644 --- a/clang/lib/Serialization/ASTReaderDecl.cpp +++ b/clang/lib/Serialization/ASTReaderDecl.cpp @@ -1194,7 +1194,7 @@ void ASTDeclReader::VisitNamespaceDecl(NamespaceDecl *D) { // any other module's anonymous namespaces, so don't attach the anonymous // namespace at all. NamespaceDecl *Anon = ReadDeclAs<NamespaceDecl>(Record, Idx); - if (F.Kind != MK_Module) + if (F.Kind != MK_ImplicitModule && F.Kind != MK_ExplicitModule) D->setAnonymousNamespace(Anon); } else { // Link this namespace back to the first declaration, which has already @@ -3536,7 +3536,8 @@ void ASTDeclReader::UpdateDecl(Decl *D, ModuleFile &ModuleFile, // Each module has its own anonymous namespace, which is disjoint from // any other module's anonymous namespaces, so don't attach the anonymous // namespace at all. - if (ModuleFile.Kind != MK_Module) { + if (ModuleFile.Kind != MK_ImplicitModule && + ModuleFile.Kind != MK_ExplicitModule) { if (TranslationUnitDecl *TU = dyn_cast<TranslationUnitDecl>(D)) TU->setAnonymousNamespace(Anon); else diff --git a/clang/lib/Serialization/ModuleManager.cpp b/clang/lib/Serialization/ModuleManager.cpp index 18fe035456d..20249e0a7bd 100644 --- a/clang/lib/Serialization/ModuleManager.cpp +++ b/clang/lib/Serialization/ModuleManager.cpp @@ -89,7 +89,7 @@ ModuleManager::addModule(StringRef FileName, ModuleKind Type, ModuleEntry = New; New->InputFilesValidationTimestamp = 0; - if (New->Kind == MK_Module) { + if (New->Kind == MK_ImplicitModule) { std::string TimestampFilename = New->getTimestampFilename(); vfs::Status Status; // A cached stat value would be fine as well. diff --git a/clang/test/Modules/Inputs/explicit-build/a.h b/clang/test/Modules/Inputs/explicit-build/a.h new file mode 100644 index 00000000000..5e3602f58ff --- /dev/null +++ b/clang/test/Modules/Inputs/explicit-build/a.h @@ -0,0 +1,5 @@ +#if !__building_module(a) +#error "should only get here when building module a" +#endif + +const int a = 1; diff --git a/clang/test/Modules/Inputs/explicit-build/b.h b/clang/test/Modules/Inputs/explicit-build/b.h new file mode 100644 index 00000000000..449b3859ab4 --- /dev/null +++ b/clang/test/Modules/Inputs/explicit-build/b.h @@ -0,0 +1,7 @@ +#include "a.h" + +#if !__building_module(b) +#error "should only get here when building module b" +#endif + +const int b = 2; diff --git a/clang/test/Modules/Inputs/explicit-build/c.h b/clang/test/Modules/Inputs/explicit-build/c.h new file mode 100644 index 00000000000..2c66a23e892 --- /dev/null +++ b/clang/test/Modules/Inputs/explicit-build/c.h @@ -0,0 +1,7 @@ +#include "b.h" + +#if !__building_module(c) +#error "should only get here when building module c" +#endif + +const int c = 3; diff --git a/clang/test/Modules/Inputs/explicit-build/module.modulemap b/clang/test/Modules/Inputs/explicit-build/module.modulemap new file mode 100644 index 00000000000..bd6ea830c2d --- /dev/null +++ b/clang/test/Modules/Inputs/explicit-build/module.modulemap @@ -0,0 +1,3 @@ +module a { header "a.h" } +module b { header "b.h" export * } +module c { header "c.h" export * } diff --git a/clang/test/Modules/explicit-build.cpp b/clang/test/Modules/explicit-build.cpp new file mode 100644 index 00000000000..0911837ed8f --- /dev/null +++ b/clang/test/Modules/explicit-build.cpp @@ -0,0 +1,151 @@ +// RUN: rm -rf %t + +// ------------------------------- +// Build chained modules A, B, and C +// RUN: %clang_cc1 -x c++ -fmodules -fmodules-cache-path=%t -Rmodule-build -fno-modules-error-recovery \ +// RUN: -fmodule-name=a -emit-module %S/Inputs/explicit-build/module.modulemap -o %t/a.pcm \ +// RUN: 2>&1 | FileCheck --check-prefix=CHECK-NO-IMPLICIT-BUILD %s --allow-empty +// +// RUN: %clang_cc1 -x c++ -fmodules -fmodules-cache-path=%t -Rmodule-build -fno-modules-error-recovery \ +// RUN: -fmodule-file=%t/a.pcm \ +// RUN: -fmodule-name=b -emit-module %S/Inputs/explicit-build/module.modulemap -o %t/b.pcm \ +// RUN: 2>&1 | FileCheck --check-prefix=CHECK-NO-IMPLICIT-BUILD %s --allow-empty +// +// RUN: %clang_cc1 -x c++ -fmodules -fmodules-cache-path=%t -Rmodule-build -fno-modules-error-recovery \ +// RUN: -fmodule-file=%t/b.pcm \ +// RUN: -fmodule-name=c -emit-module %S/Inputs/explicit-build/module.modulemap -o %t/c.pcm \ +// RUN: 2>&1 | FileCheck --check-prefix=CHECK-NO-IMPLICIT-BUILD %s --allow-empty +// +// CHECK-NO-IMPLICIT-BUILD-NOT: building module + +// ------------------------------- +// Build B with an implicit build of A +// RUN: %clang_cc1 -x c++ -fmodules -fmodules-cache-path=%t -Rmodule-build -fno-modules-error-recovery \ +// RUN: -fmodule-name=b -emit-module %S/Inputs/explicit-build/module.modulemap -o %t/b-not-a.pcm \ +// RUN: 2>&1 | FileCheck --check-prefix=CHECK-B-NO-A %s +// +// CHECK-B-NO-A: While building module 'b': +// CHECK-B-NO-A: building module 'a' as + +// ------------------------------- +// Check that we can use the explicitly-built A, B, and C modules. +// RUN: %clang_cc1 -x c++ -fmodules -fmodules-cache-path=%t -Rmodule-build -fno-modules-error-recovery \ +// RUN: -fmodule-file=%t/a.pcm \ +// RUN: -verify %s -DHAVE_A +// +// RUN: %clang_cc1 -x c++ -fmodules -fmodules-cache-path=%t -Rmodule-build -fno-modules-error-recovery \ +// RUN: -fmodule-file=%t/a.pcm \ +// RUN: -fmodule-map-file=%S/Inputs/explicit-build/module.modulemap \ +// RUN: -verify %s -DHAVE_A +// +// RUN: %clang_cc1 -x c++ -fmodules -fmodules-cache-path=%t -Rmodule-build -fno-modules-error-recovery \ +// RUN: -fmodule-file=%t/b.pcm \ +// RUN: -verify %s -DHAVE_A -DHAVE_B +// +// RUN: %clang_cc1 -x c++ -fmodules -fmodules-cache-path=%t -Rmodule-build -fno-modules-error-recovery \ +// RUN: -fmodule-file=%t/a.pcm \ +// RUN: -fmodule-file=%t/b.pcm \ +// RUN: -verify %s -DHAVE_A -DHAVE_B +// +// RUN: %clang_cc1 -x c++ -fmodules -fmodules-cache-path=%t -Rmodule-build -fno-modules-error-recovery \ +// RUN: -fmodule-file=%t/a.pcm \ +// RUN: -fmodule-file=%t/b.pcm \ +// RUN: -fmodule-file=%t/c.pcm \ +// RUN: -verify %s -DHAVE_A -DHAVE_B -DHAVE_C +// +// RUN: %clang_cc1 -x c++ -fmodules -fmodules-cache-path=%t -Rmodule-build -fno-modules-error-recovery \ +// RUN: -I%S/Inputs/explicit-build \ +// RUN: -fmodule-file=%t/a.pcm \ +// RUN: -fmodule-file=%t/b.pcm \ +// RUN: -fmodule-file=%t/c.pcm \ +// RUN: -verify %s -INCLUDE_ALL -DHAVE_A -DHAVE_B -DHAVE_C + +#ifdef INCLUDE_ALL + #include "a.h" + #include "b.h" + #include "c.h" + static_assert(a == 1, ""); + static_assert(b == 2, ""); + static_assert(c == 3, ""); +#else + const int use_a = a; + #ifndef HAVE_A + // expected-error@-2 {{undeclared identifier}} + #else + // expected-error@-4 {{must be imported from module 'a'}} + // expected-note@Inputs/explicit-build/a.h:* {{here}} + #endif + + const int use_b = b; + #ifndef HAVE_B + // expected-error@-2 {{undeclared identifier}} + #else + // expected-error@-4 {{must be imported from module 'b'}} + // expected-note@Inputs/explicit-build/b.h:* {{here}} + #endif + + const int use_c = c; + #ifndef HAVE_C + // expected-error@-2 {{undeclared identifier}} + #else + // expected-error@-4 {{must be imported from module 'c'}} + // expected-note@Inputs/explicit-build/c.h:* {{here}} + #endif +#endif + +// ------------------------------- +// Check that we can use a mixture of implicit and explicit modules. +// RUN: not %clang_cc1 -x c++ -fmodules -fmodules-cache-path=%t -Rmodule-build -fno-modules-error-recovery \ +// RUN: -fmodule-file=%t/b-not-a.pcm \ +// RUN: -fmodule-map-file=%S/Inputs/explicit-build/module.modulemap \ +// RUN: %s 2>&1 | FileCheck --check-prefix=CHECK-A-AND-B-NO-A %s + +// ------------------------------- +// Check that mixing an implicit and explicit form of the 'a' module is rejected. +// RUN: not %clang_cc1 -x c++ -fmodules -fmodules-cache-path=%t -Rmodule-build -fno-modules-error-recovery \ +// RUN: -fmodule-file=%t/a.pcm \ +// RUN: -fmodule-file=%t/b-not-a.pcm \ +// RUN: %s 2>&1 | FileCheck --check-prefix=CHECK-A-AND-B-NO-A %s +// +// RUN: not %clang_cc1 -x c++ -fmodules -fmodules-cache-path=%t -Rmodule-build -fno-modules-error-recovery \ +// RUN: -fmodule-file=%t/a.pcm \ +// RUN: -fmodule-file=%t/b-not-a.pcm \ +// RUN: -fmodule-map-file=%S/Inputs/explicit-build/module.modulemap \ +// RUN: %s 2>&1 | FileCheck --check-prefix=CHECK-A-AND-B-NO-A %s +// +// FIXME: We should load module map files specified on the command line and +// module map files in include paths on demand to allow this, and possibly +// also the previous case. +// CHECK-A-AND-B-NO-A: fatal error: module 'a' {{.*}} is not defined in any loaded module map + +// ------------------------------- +// Try to use two different flavors of the 'a' module. +// RUN: %clang_cc1 -x c++ -fmodules -fmodules-cache-path=%t -Rmodule-build -fno-modules-error-recovery \ +// RUN: -fmodule-name=a -emit-module %S/Inputs/explicit-build/module.modulemap -o %t/a-alt.pcm \ +// RUN: 2>&1 | FileCheck --check-prefix=CHECK-NO-IMPLICIT-BUILD %s --allow-empty +// +// RUN: not %clang_cc1 -x c++ -fmodules -fmodules-cache-path=%t -Rmodule-build -fno-modules-error-recovery \ +// RUN: -fmodule-file=%t/a.pcm \ +// RUN: -fmodule-file=%t/a-alt.pcm \ +// RUN: -fmodule-map-file=%S/Inputs/explicit-build/module.modulemap \ +// RUN: %s 2>&1 | FileCheck --check-prefix=CHECK-MULTIPLE-AS %s +// +// RUN: not %clang_cc1 -x c++ -fmodules -fmodules-cache-path=%t -Rmodule-build -fno-modules-error-recovery \ +// RUN: -fmodule-file=%t/a-alt.pcm \ +// RUN: -fmodule-file=%t/a.pcm \ +// RUN: -fmodule-map-file=%S/Inputs/explicit-build/module.modulemap \ +// RUN: %s 2>&1 | FileCheck --check-prefix=CHECK-MULTIPLE-AS %s +// +// CHECK-MULTIPLE-AS: error: module 'a' has already been loaded; cannot load module file '{{.*a(-alt)?}}.pcm' + +// ------------------------------- +// Try to import a PCH with -fmodule-file= +// RUN: %clang_cc1 -x c++ -fmodules -fmodules-cache-path=%t -Rmodule-build -fno-modules-error-recovery \ +// RUN: -fmodule-name=a -emit-pch %S/Inputs/explicit-build/a.h -o %t/a.pch \ +// RUN: 2>&1 | FileCheck --check-prefix=CHECK-NO-IMPLICIT-BUILD %s --allow-empty +// +// RUN: not %clang_cc1 -x c++ -fmodules -fmodules-cache-path=%t -Rmodule-build -fno-modules-error-recovery \ +// RUN: -fmodule-file=%t/a.pch \ +// RUN: %s 2>&1 | FileCheck --check-prefix=CHECK-A-AS-PCH %s +// +// CHECK-A-AS-PCH: fatal error: AST file '{{.*}}a.pch' was not built as a module diff --git a/clang/test/Modules/resolution-change.m b/clang/test/Modules/resolution-change.m index 011782eec2b..b725a64acb4 100644 --- a/clang/test/Modules/resolution-change.m +++ b/clang/test/Modules/resolution-change.m @@ -11,11 +11,11 @@ // Use the PCH with no way to resolve DependsOnA // RUN: not %clang_cc1 -fmodules -fmodules-cache-path=%t -include-pch %t-A.pch %s -fsyntax-only 2>&1 | FileCheck -check-prefix=CHECK-NODOA %s -// CHECK-NODOA: module 'DependsOnA' imported by AST file '{{.*A.pch}}' not found +// CHECK-NODOA: module 'DependsOnA' in AST file '{{.*DependsOnA.*pcm}}' (imported by AST file '{{.*A.pch}}') is not defined in any loaded module map // Use the PCH with no way to resolve A // RUN: not %clang_cc1 -fmodules -fmodules-cache-path=%t -I %S/Inputs/modules-with-same-name/DependsOnA -include-pch %t-A.pch %s -fsyntax-only 2>&1 | FileCheck -check-prefix=CHECK-NOA %s -// CHECK-NOA: module 'A' imported by AST file '{{.*DependsOnA.*pcm}}' not found +// CHECK-NOA: module 'A' in AST file '{{.*A.*pcm}}' (imported by AST file '{{.*DependsOnA.*pcm}}') is not defined in any loaded module map // Use the PCH and have it resolve the the other A // RUN: not %clang_cc1 -fmodules -fmodules-cache-path=%t -I %S/Inputs/modules-with-same-name/DependsOnA -I %S/Inputs/modules-with-same-name/path2/A -include-pch %t-A.pch %s -fsyntax-only 2>&1 | FileCheck -check-prefix=CHECK-WRONGA %s |