Skip to content

Commit 159fe25

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
1 parent 96d5596 commit 159fe25

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
@@ -142,30 +142,33 @@ class IncludeTreeBuilder {
142142
std::optional<llvm::Error> ErrorToReport;
143143
};
144144

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

@@ -244,27 +247,29 @@ struct IncludeTreePPCallbacks : public PPCallbacks {
244247
/// MODULE_DIRECTORY record, and ignores the result.
245248
class LookupPCHModulesListener : public ASTReaderListener {
246249
public:
247-
LookupPCHModulesListener(Preprocessor &PP) : PP(PP) {}
250+
LookupPCHModulesListener(ASTReader &R) : Reader(R) {}
248251

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

265271
private:
266-
Preprocessor &PP;
267-
bool PCHFinished = false;
272+
ASTReader &Reader;
268273
};
269274
} // namespace
270275

@@ -317,21 +322,15 @@ Error IncludeTreeActionController::initialize(
317322

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

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

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

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)