Skip to content

Commit 5602ec9

Browse files
committed
[clang][modules] Cache loads of modules imported by PCH
During explicit modular build, PCM files are typically specified via the `-fmodule-file=<path>` command-line option. Early during the compilation, Clang uses the `ASTReader` to read their contents and caches the result so that the module isn't loaded implicitly later on. A listener is attached to the `ASTReader` to collect names of the modules read from the PCM files. However, if the PCM has already been loaded previously via PCH: 1. the `ASTReader` doesn't do anything for the second time, 2. the listener is not invoked at all, 3. the module load result is not cached, 4. the compilation fails when attempting to load the module implicitly later on. This patch solves this problem by attaching the listener to the `ASTReader` for PCH reading as well. Reviewed By: dexonsmith Differential Revision: https://reviews.llvm.org/D111560
1 parent febdba9 commit 5602ec9

File tree

7 files changed

+32
-13
lines changed

7 files changed

+32
-13
lines changed

clang/lib/Frontend/CompilerInstance.cpp

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -565,29 +565,26 @@ namespace {
565565
// We mark these as known and redirect any attempt to load that module to
566566
// the files we were handed.
567567
struct ReadModuleNames : ASTReaderListener {
568-
CompilerInstance &CI;
568+
Preprocessor &PP;
569569
llvm::SmallVector<IdentifierInfo*, 8> LoadedModules;
570570

571-
ReadModuleNames(CompilerInstance &CI) : CI(CI) {}
571+
ReadModuleNames(Preprocessor &PP) : PP(PP) {}
572572

573573
void ReadModuleName(StringRef ModuleName) override {
574-
LoadedModules.push_back(
575-
CI.getPreprocessor().getIdentifierInfo(ModuleName));
574+
LoadedModules.push_back(PP.getIdentifierInfo(ModuleName));
576575
}
577576

578577
void registerAll() {
579-
ModuleMap &MM = CI.getPreprocessor().getHeaderSearchInfo().getModuleMap();
578+
ModuleMap &MM = PP.getHeaderSearchInfo().getModuleMap();
580579
for (auto *II : LoadedModules)
581580
MM.cacheModuleLoad(*II, MM.findModule(II->getName()));
582581
LoadedModules.clear();
583582
}
584583

585584
void markAllUnavailable() {
586585
for (auto *II : LoadedModules) {
587-
if (Module *M = CI.getPreprocessor()
588-
.getHeaderSearchInfo()
589-
.getModuleMap()
590-
.findModule(II->getName())) {
586+
if (Module *M = PP.getHeaderSearchInfo().getModuleMap().findModule(
587+
II->getName())) {
591588
M->HasIncompatibleModuleFile = true;
592589

593590
// Mark module as available if the only reason it was unavailable
@@ -652,6 +649,11 @@ IntrusiveRefCntPtr<ASTReader> CompilerInstance::createPCHExternalASTSource(
652649
for (auto &Listener : DependencyCollectors)
653650
Listener->attachToASTReader(*Reader);
654651

652+
auto Listener = std::make_unique<ReadModuleNames>(PP);
653+
auto &ListenerRef = *Listener;
654+
ASTReader::ListenerScope ReadModuleNamesListener(*Reader,
655+
std::move(Listener));
656+
655657
switch (Reader->ReadAST(Path,
656658
Preamble ? serialization::MK_Preamble
657659
: serialization::MK_PCH,
@@ -661,6 +663,7 @@ IntrusiveRefCntPtr<ASTReader> CompilerInstance::createPCHExternalASTSource(
661663
// Set the predefines buffer as suggested by the PCH reader. Typically, the
662664
// predefines buffer will be empty.
663665
PP.setPredefines(Reader->getSuggestedPredefines());
666+
ListenerRef.registerAll();
664667
return Reader;
665668

666669
case ASTReader::Failure:
@@ -676,6 +679,7 @@ IntrusiveRefCntPtr<ASTReader> CompilerInstance::createPCHExternalASTSource(
676679
break;
677680
}
678681

682+
ListenerRef.markAllUnavailable();
679683
Context.setExternalSource(nullptr);
680684
return nullptr;
681685
}
@@ -1706,7 +1710,7 @@ bool CompilerInstance::loadModuleFile(StringRef FileName) {
17061710
SourceLocation())
17071711
<= DiagnosticsEngine::Warning;
17081712

1709-
auto Listener = std::make_unique<ReadModuleNames>(*this);
1713+
auto Listener = std::make_unique<ReadModuleNames>(*PP);
17101714
auto &ListenerRef = *Listener;
17111715
ASTReader::ListenerScope ReadModuleNamesListener(*TheASTReader,
17121716
std::move(Listener));

clang/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ FullDependencies::getAdditionalArgsWithoutModulePaths() const {
3838
};
3939

4040
for (const PrebuiltModuleDep &PMD : PrebuiltModuleDeps) {
41-
Args.push_back("-fmodule-file=" + PMD.ModuleName + "=" + PMD.PCMFile);
41+
Args.push_back("-fmodule-file=" + PMD.PCMFile);
4242
Args.push_back("-fmodule-map-file=" + PMD.ModuleMapFile);
4343
}
4444

clang/test/ClangScanDeps/modules-pch.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -229,8 +229,7 @@
229229
// CHECK-TU-WITH-COMMON-NEXT: "command-line": [
230230
// CHECK-TU-WITH-COMMON-NEXT: "-fno-implicit-modules",
231231
// CHECK-TU-WITH-COMMON-NEXT: "-fno-implicit-module-maps",
232-
// FIXME: Figure out why we need `=ModCommon2` here for Clang to pick up the PCM.
233-
// CHECK-TU-WITH-COMMON-NEXT: "-fmodule-file=ModCommon2=[[PREFIX]]/build/{{.*}}/ModCommon2-{{.*}}.pcm",
232+
// CHECK-TU-WITH-COMMON-NEXT: "-fmodule-file=[[PREFIX]]/build/{{.*}}/ModCommon2-{{.*}}.pcm",
234233
// CHECK-TU-WITH-COMMON-NEXT: "-fmodule-map-file=[[PREFIX]]/module.modulemap"
235234
// CHECK-TU-WITH-COMMON-NEXT: "-fmodule-file=[[PREFIX]]/build/[[HASH_MOD_TU_WITH_COMMON]]/ModTUWithCommon-{{.*}}.pcm",
236235
// CHECK-TU-WITH-COMMON-NEXT: "-fmodule-map-file=[[PREFIX]]/module.modulemap"

clang/test/Modules/Inputs/pch-shared-module/mod.h

Whitespace-only changes.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
module mod { header "mod.h" }
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
#include "mod.h"
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// rm -rf %t && mkdir %t
2+
3+
// RUN: %clang_cc1 -fmodules -emit-module -fmodule-name=mod %S/Inputs/pch-shared-module/module.modulemap -o %t/mod.pcm
4+
5+
// RUN: %clang_cc1 -fmodules -emit-pch %S/Inputs/pch-shared-module/pch.h -o %t/pch.h.gch \
6+
// RUN: -fmodule-file=%t/mod.pcm -fmodule-map-file=%S/Inputs/pch-shared-module/module.modulemap
7+
8+
// Check that `mod.pcm` is loaded correctly, even though it's imported by the PCH as well.
9+
// RUN: %clang_cc1 -fmodules -fsyntax-only %s -include-pch %t/pch.h.gch -I %S/Inputs/pch-shared-module \
10+
// RUN: -fmodule-file=%t/mod.pcm -fmodule-map-file=%S/Inputs/pch-shared-module/module.modulemap -verify
11+
12+
#include "mod.h"
13+
14+
// expected-no-diagnostics

0 commit comments

Comments
 (0)