diff --git a/clang/lib/Frontend/CompilerInstance.cpp b/clang/lib/Frontend/CompilerInstance.cpp --- a/clang/lib/Frontend/CompilerInstance.cpp +++ b/clang/lib/Frontend/CompilerInstance.cpp @@ -441,6 +441,52 @@ InitOpts.RemappedFilesKeepOriginalName); } +namespace { +// Helper to recursively read the module names for all modules we're adding. +// We mark these as known and redirect any attempt to load that module to +// the files we were handed. +struct ReadModuleNames : ASTReaderListener { + Preprocessor &PP; + llvm::SmallVector LoadedModules; + + ReadModuleNames(Preprocessor &PP) : PP(PP) {} + + void ReadModuleName(StringRef ModuleName) override { + LoadedModules.push_back(PP.getIdentifierInfo(ModuleName)); + } + + void registerAll() { + ModuleMap &MM = PP.getHeaderSearchInfo().getModuleMap(); + for (auto *II : LoadedModules) + MM.cacheModuleLoad(*II, MM.findModule(II->getName())); + LoadedModules.clear(); + } + + void markAllUnavailable() { + for (auto *II : LoadedModules) { + if (Module *M = PP.getHeaderSearchInfo().getModuleMap().findModule( + II->getName())) { + M->HasIncompatibleModuleFile = true; + + // Mark module as available if the only reason it was unavailable + // was missing headers. + SmallVector Stack; + Stack.push_back(M); + while (!Stack.empty()) { + Module *Current = Stack.pop_back_val(); + if (Current->IsUnimportable) + continue; + Current->IsAvailable = true; + Stack.insert(Stack.end(), Current->submodule_begin(), + Current->submodule_end()); + } + } + } + LoadedModules.clear(); + } +}; +} // namespace + // Preprocessor void CompilerInstance::createPreprocessor(TranslationUnitKind TUKind) { @@ -603,6 +649,11 @@ for (auto &Listener : DependencyCollectors) Listener->attachToASTReader(*Reader); + auto Listener = std::make_unique(PP); + auto &ListenerRef = *Listener; + ASTReader::ListenerScope ReadModuleNamesListener(*Reader, + std::move(Listener)); + switch (Reader->ReadAST(Path, Preamble ? serialization::MK_Preamble : serialization::MK_PCH, @@ -612,6 +663,7 @@ // Set the predefines buffer as suggested by the PCH reader. Typically, the // predefines buffer will be empty. PP.setPredefines(Reader->getSuggestedPredefines()); + ListenerRef.registerAll(); return Reader; case ASTReader::Failure: @@ -627,6 +679,7 @@ break; } + ListenerRef.markAllUnavailable(); Context.setExternalSource(nullptr); return nullptr; } @@ -1634,52 +1687,6 @@ *FrontendTimerGroup); llvm::TimeRegion TimeLoading(FrontendTimerGroup ? &Timer : nullptr); - // Helper to recursively read the module names for all modules we're adding. - // We mark these as known and redirect any attempt to load that module to - // the files we were handed. - struct ReadModuleNames : ASTReaderListener { - CompilerInstance &CI; - llvm::SmallVector LoadedModules; - - ReadModuleNames(CompilerInstance &CI) : CI(CI) {} - - void ReadModuleName(StringRef ModuleName) override { - LoadedModules.push_back( - CI.getPreprocessor().getIdentifierInfo(ModuleName)); - } - - void registerAll() { - ModuleMap &MM = CI.getPreprocessor().getHeaderSearchInfo().getModuleMap(); - for (auto *II : LoadedModules) - MM.cacheModuleLoad(*II, MM.findModule(II->getName())); - LoadedModules.clear(); - } - - void markAllUnavailable() { - for (auto *II : LoadedModules) { - if (Module *M = CI.getPreprocessor() - .getHeaderSearchInfo() - .getModuleMap() - .findModule(II->getName())) { - M->HasIncompatibleModuleFile = true; - - // Mark module as available if the only reason it was unavailable - // was missing headers. - SmallVector Stack; - Stack.push_back(M); - while (!Stack.empty()) { - Module *Current = Stack.pop_back_val(); - if (Current->IsUnimportable) continue; - Current->IsAvailable = true; - Stack.insert(Stack.end(), - Current->submodule_begin(), Current->submodule_end()); - } - } - } - LoadedModules.clear(); - } - }; - // If we don't already have an ASTReader, create one now. if (!TheASTReader) createASTReader(); @@ -1691,7 +1698,7 @@ SourceLocation()) <= DiagnosticsEngine::Warning; - auto Listener = std::make_unique(*this); + auto Listener = std::make_unique(*PP); auto &ListenerRef = *Listener; ASTReader::ListenerScope ReadModuleNamesListener(*TheASTReader, std::move(Listener)); diff --git a/clang/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp b/clang/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp --- a/clang/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp +++ b/clang/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp @@ -38,7 +38,7 @@ }; for (const PrebuiltModuleDep &PMD : PrebuiltModuleDeps) { - Args.push_back("-fmodule-file=" + PMD.ModuleName + "=" + PMD.PCMFile); + Args.push_back("-fmodule-file=" + PMD.PCMFile); Args.push_back("-fmodule-map-file=" + PMD.ModuleMapFile); } diff --git a/clang/test/ClangScanDeps/modules-pch.c b/clang/test/ClangScanDeps/modules-pch.c --- a/clang/test/ClangScanDeps/modules-pch.c +++ b/clang/test/ClangScanDeps/modules-pch.c @@ -229,8 +229,7 @@ // CHECK-TU-WITH-COMMON-NEXT: "command-line": [ // CHECK-TU-WITH-COMMON-NEXT: "-fno-implicit-modules", // CHECK-TU-WITH-COMMON-NEXT: "-fno-implicit-module-maps", -// FIXME: Figure out why we need `=ModCommon2` here for Clang to pick up the PCM. -// CHECK-TU-WITH-COMMON-NEXT: "-fmodule-file=ModCommon2=[[PREFIX]]/build/{{.*}}/ModCommon2-{{.*}}.pcm", +// CHECK-TU-WITH-COMMON-NEXT: "-fmodule-file=[[PREFIX]]/build/{{.*}}/ModCommon2-{{.*}}.pcm", // CHECK-TU-WITH-COMMON-NEXT: "-fmodule-map-file=[[PREFIX]]/module.modulemap" // CHECK-TU-WITH-COMMON-NEXT: "-fmodule-file=[[PREFIX]]/build/[[HASH_MOD_TU_WITH_COMMON]]/ModTUWithCommon-{{.*}}.pcm", // CHECK-TU-WITH-COMMON-NEXT: "-fmodule-map-file=[[PREFIX]]/module.modulemap" diff --git a/clang/test/Modules/Inputs/pch-shared-module/mod.h b/clang/test/Modules/Inputs/pch-shared-module/mod.h new file mode 100644 diff --git a/clang/test/Modules/Inputs/pch-shared-module/module.modulemap b/clang/test/Modules/Inputs/pch-shared-module/module.modulemap new file mode 100644 --- /dev/null +++ b/clang/test/Modules/Inputs/pch-shared-module/module.modulemap @@ -0,0 +1 @@ +module mod { header "mod.h" } diff --git a/clang/test/Modules/Inputs/pch-shared-module/pch.h b/clang/test/Modules/Inputs/pch-shared-module/pch.h new file mode 100644 --- /dev/null +++ b/clang/test/Modules/Inputs/pch-shared-module/pch.h @@ -0,0 +1 @@ +#include "mod.h" diff --git a/clang/test/Modules/pch-shared-module.c b/clang/test/Modules/pch-shared-module.c new file mode 100644 --- /dev/null +++ b/clang/test/Modules/pch-shared-module.c @@ -0,0 +1,14 @@ +// rm -rf %t && mkdir %t + +// RUN: %clang_cc1 -fmodules -emit-module -fmodule-name=mod %S/Inputs/pch-shared-module/module.modulemap -o %t/mod.pcm + +// RUN: %clang_cc1 -fmodules -emit-pch %S/Inputs/pch-shared-module/pch.h -o %t/pch.h.gch \ +// RUN: -fmodule-file=%t/mod.pcm -fmodule-map-file=%S/Inputs/pch-shared-module/module.modulemap + +// Check that `mod.pcm` is loaded correctly, even though it's imported by the PCH as well. +// RUN: %clang_cc1 -fmodules -fsyntax-only %s -include-pch %t/pch.h.gch -I %S/Inputs/pch-shared-module \ +// RUN: -fmodule-file=%t/mod.pcm -fmodule-map-file=%S/Inputs/pch-shared-module/module.modulemap -verify + +#include "mod.h" + +// expected-no-diagnostics