Skip to content

Commit 2d2bb9c

Browse files
committed
[clang][cas] Extend fix for private modules to module builds
In 6034ccd we fixed an issue where if a public module is imported via PCH we cannot import the private module in a TU because the modulemap is not parsed. This is also an issue when building a module that imports the private module and the TU used a PCH, because even though we don't import the PCH itself, we still use the prebuilt/explicit module found via the PCH instead of building an implicit scanner module. This commit generalizes the original fix to handle all prebuilt/explicit modules. rdar://107446573 (cherry picked from commit 159fe25)
1 parent aa434c9 commit 2d2bb9c

File tree

2 files changed

+104
-45
lines changed

2 files changed

+104
-45
lines changed

clang/lib/Tooling/DependencyScanning/IncludeTreeActionController.cpp

Lines changed: 47 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -141,30 +141,33 @@ class IncludeTreeBuilder {
141141
Optional<llvm::Error> ErrorToReport;
142142
};
143143

144-
/// A utility for adding \c PPCallbacks to a compiler instance at the
145-
/// appropriate time.
146-
struct PPCallbacksDependencyCollector : public DependencyCollector {
147-
using MakeCB =
144+
/// A utility for adding \c PPCallbacks and/or \cASTReaderListener to a compiler
145+
/// instance at the appropriate time.
146+
struct AttachOnlyDependencyCollector : public DependencyCollector {
147+
using MakePPCB =
148148
llvm::unique_function<std::unique_ptr<PPCallbacks>(Preprocessor &)>;
149-
MakeCB Create;
150-
PPCallbacksDependencyCollector(MakeCB Create) : Create(std::move(Create)) {}
149+
using MakeASTReaderL =
150+
llvm::unique_function<std::unique_ptr<ASTReaderListener>(ASTReader &R)>;
151+
MakePPCB CreatePPCB;
152+
MakeASTReaderL CreateASTReaderL;
153+
AttachOnlyDependencyCollector(MakePPCB CreatePPCB, MakeASTReaderL CreateL)
154+
: CreatePPCB(std::move(CreatePPCB)),
155+
CreateASTReaderL(std::move(CreateL)) {}
156+
151157
void attachToPreprocessor(Preprocessor &PP) final {
152-
std::unique_ptr<PPCallbacks> CB = Create(PP);
153-
assert(CB);
154-
PP.addPPCallbacks(std::move(CB));
158+
if (CreatePPCB) {
159+
std::unique_ptr<PPCallbacks> CB = CreatePPCB(PP);
160+
assert(CB);
161+
PP.addPPCallbacks(std::move(CB));
162+
}
155163
}
156-
};
157-
/// A utility for adding \c ASTReaderListener to a compiler instance at the
158-
/// appropriate time.
159-
struct ASTReaderListenerDependencyCollector : public DependencyCollector {
160-
using MakeL =
161-
llvm::unique_function<std::unique_ptr<ASTReaderListener>(ASTReader &R)>;
162-
MakeL Create;
163-
ASTReaderListenerDependencyCollector(MakeL Create) : Create(std::move(Create)) {}
164+
164165
void attachToASTReader(ASTReader &R) final {
165-
std::unique_ptr<ASTReaderListener> L = Create(R);
166-
assert(L);
167-
R.addListener(std::move(L));
166+
if (CreateASTReaderL) {
167+
std::unique_ptr<ASTReaderListener> L = CreateASTReaderL(R);
168+
assert(L);
169+
R.addListener(std::move(L));
170+
}
168171
}
169172
};
170173

@@ -243,27 +246,29 @@ struct IncludeTreePPCallbacks : public PPCallbacks {
243246
/// MODULE_DIRECTORY record, and ignores the result.
244247
class LookupPCHModulesListener : public ASTReaderListener {
245248
public:
246-
LookupPCHModulesListener(Preprocessor &PP) : PP(PP) {}
249+
LookupPCHModulesListener(ASTReader &R) : Reader(R) {}
247250

248251
private:
249-
void ReadModuleName(StringRef ModuleName) final {
250-
if (PCHFinished)
251-
return;
252-
// Match MODULE_DIRECTORY: allow full search and ignore failure to find
253-
// the module.
254-
(void)PP.getHeaderSearchInfo().lookupModule(
255-
ModuleName, SourceLocation(), /*AllowSearch=*/true,
256-
/*AllowExtraModuleMapSearch=*/true);
257-
}
258252
void visitModuleFile(StringRef Filename,
259253
serialization::ModuleKind Kind) final {
260-
if (Kind == serialization::MK_PCH)
261-
PCHFinished = true;
254+
// Any prebuilt or explicit modules seen during scanning are "full" modules
255+
// rather than implicitly built scanner modules.
256+
if (Kind == serialization::MK_PrebuiltModule ||
257+
Kind == serialization::MK_ExplicitModule) {
258+
serialization::ModuleManager &Manager = Reader.getModuleManager();
259+
serialization::ModuleFile *MF = Manager.lookupByFileName(Filename);
260+
assert(MF && "module file missing in visitModuleFile");
261+
// Match MODULE_DIRECTORY: allow full search and ignore failure to find
262+
// the module.
263+
HeaderSearch &HS = Reader.getPreprocessor().getHeaderSearchInfo();
264+
(void)HS.lookupModule(MF->ModuleName, SourceLocation(),
265+
/*AllowSearch=*/true,
266+
/*AllowExtraModuleMapSearch=*/true);
267+
}
262268
}
263269

264270
private:
265-
Preprocessor &PP;
266-
bool PCHFinished = false;
271+
ASTReader &Reader;
267272
};
268273
} // namespace
269274

@@ -316,21 +321,15 @@ Error IncludeTreeActionController::initialize(
316321

317322
// Attach callbacks for the IncludeTree of the TU. The preprocessor
318323
// does not exist yet, so we need to indirect this via DependencyCollector.
319-
auto DC = std::make_shared<PPCallbacksDependencyCollector>(
324+
auto DC = std::make_shared<AttachOnlyDependencyCollector>(
320325
[&Builder = current()](Preprocessor &PP) {
321326
return std::make_unique<IncludeTreePPCallbacks>(Builder, PP);
327+
},
328+
[](ASTReader &R) {
329+
return std::make_unique<LookupPCHModulesListener>(R);
322330
});
323331
ScanInstance.addDependencyCollector(std::move(DC));
324332

325-
// Attach callback for modules loaded via PCH.
326-
if (!ScanInstance.getPreprocessorOpts().ImplicitPCHInclude.empty()) {
327-
auto DC = std::make_shared<ASTReaderListenerDependencyCollector>(
328-
[&](ASTReader &R) {
329-
return std::make_unique<LookupPCHModulesListener>(R.getPreprocessor());
330-
});
331-
ScanInstance.addDependencyCollector(std::move(DC));
332-
}
333-
334333
// Enable caching in the resulting commands.
335334
ScanInstance.getFrontendOpts().CacheCompileJob = true;
336335
CASOpts = ScanInstance.getCASOpts();
@@ -366,9 +365,12 @@ Error IncludeTreeActionController::initializeModuleBuild(
366365

367366
// Attach callbacks for the IncludeTree of the module. The preprocessor
368367
// does not exist yet, so we need to indirect this via DependencyCollector.
369-
auto DC = std::make_shared<PPCallbacksDependencyCollector>(
368+
auto DC = std::make_shared<AttachOnlyDependencyCollector>(
370369
[&Builder = current()](Preprocessor &PP) {
371370
return std::make_unique<IncludeTreePPCallbacks>(Builder, PP);
371+
},
372+
[](ASTReader &R) {
373+
return std::make_unique<LookupPCHModulesListener>(R);
372374
});
373375
ModuleScanInstance.addDependencyCollector(std::move(DC));
374376

clang/test/ClangScanDeps/modules-include-tree-pch-with-private.c

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,10 @@
1414
// RUN: > %t/deps_pch.json
1515

1616
// RUN: %deps-to-rsp %t/deps_pch.json --module-name Mod > %t/Mod.rsp
17+
// RUN: %deps-to-rsp %t/deps_pch.json --module-name Indirect1 > %t/Indirect1.rsp
1718
// RUN: %deps-to-rsp %t/deps_pch.json --tu-index 0 > %t/pch.rsp
1819
// RUN: %clang @%t/Mod.rsp
20+
// RUN: %clang @%t/Indirect1.rsp
1921
// RUN: %clang @%t/pch.rsp
2022

2123
// RUN: clang-scan-deps -compilation-database %t/cdb.json \
@@ -24,10 +26,39 @@
2426
// RUN: > %t/deps.json
2527

2628
// RUN: %deps-to-rsp %t/deps.json --module-name Mod_Private > %t/Mod_Private.rsp
29+
// RUN: %deps-to-rsp %t/deps.json --module-name Indirect2 > %t/Indirect2.rsp
2730
// RUN: %deps-to-rsp %t/deps.json --tu-index 0 > %t/tu.rsp
2831
// RUN: %clang @%t/Mod_Private.rsp
32+
// RUN: %clang @%t/Indirect2.rsp
2933
// RUN: %clang @%t/tu.rsp
3034

35+
// Extract include-tree casids
36+
// RUN: cat %t/Indirect2.rsp | sed -E 's|.*"-fcas-include-tree" "(llvmcas://[[:xdigit:]]+)".*|\1|' > %t/Indirect.casid
37+
// RUN: cat %t/tu.rsp | sed -E 's|.*"-fcas-include-tree" "(llvmcas://[[:xdigit:]]+)".*|\1|' > %t/tu.casid
38+
39+
// RUN: echo "MODULE Indirect2" > %t/result.txt
40+
// RUN: clang-cas-test -cas %t/cas -print-include-tree @%t/Indirect.casid >> %t/result.txt
41+
// RUN: echo "TRANSLATION UNIT" >> %t/result.txt
42+
// RUN: clang-cas-test -cas %t/cas -print-include-tree @%t/tu.casid >> %t/result.txt
43+
44+
// Explicitly check that Mod_Private is imported as a module and not a header.
45+
// RUN: FileCheck %s -DPREFIX=%/t -input-file %t/result.txt
46+
47+
// CHECK-LABEL: MODULE Indirect2
48+
// CHECK: <module-includes> llvmcas://
49+
// CHECK: 1:1 <built-in> llvmcas://
50+
// CHECK: 2:1 [[PREFIX]]/indirect2.h llvmcas://
51+
// CHECK: Submodule: Indirect2
52+
// CHECK: 2:1 (Module) Indirect1
53+
// CHECK: 3:1 (Module) Mod_Private
54+
55+
// CHECK-LABEL: TRANSLATION UNIT
56+
// CHECK: (PCH) llvmcas://
57+
// CHECK: [[PREFIX]]/tu.m llvmcas://
58+
// CHECK: 1:1 <built-in> llvmcas://
59+
// CHECK: 2:1 (Module) Mod_Private
60+
// CHECK: 3:1 (Module) Indirect2
61+
3162
//--- cdb.json.template
3263
[{
3364
"file": "DIR/tu.m",
@@ -54,12 +85,38 @@ void pub(void);
5485
//--- Mod.framework/PrivateHeaders/Priv.h
5586
void priv(void);
5687

88+
//--- module.modulemap
89+
module Indirect1 {
90+
header "indirect1.h"
91+
export *
92+
}
93+
module Indirect2 {
94+
header "indirect2.h"
95+
export *
96+
}
97+
98+
//--- indirect1.h
99+
#import <Mod/Mod.h>
100+
101+
//--- indirect2.h
102+
#import "indirect1.h"
103+
#import <Mod/Priv.h>
104+
105+
static inline void indirect(void) {
106+
pub();
107+
priv();
108+
}
109+
57110
//--- prefix.h
58111
#import <Mod/Mod.h>
112+
#import "indirect1.h"
59113

60114
//--- tu.m
61115
#import <Mod/Priv.h>
116+
#import "indirect2.h"
117+
62118
void tu(void) {
63119
pub();
64120
priv();
121+
indirect();
65122
}

0 commit comments

Comments
 (0)