Skip to content

Commit 611dd6f

Browse files
committed
Merge commit 'ea1bfbf3f639' from llvm.org/main into next
2 parents be9371f + ea1bfbf commit 611dd6f

File tree

5 files changed

+216
-41
lines changed

5 files changed

+216
-41
lines changed

clang/include/clang/Tooling/DependencyScanning/ModuleDepCollector.h

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -184,12 +184,25 @@ struct ModuleDeps {
184184
/// on, not including transitive dependencies.
185185
std::vector<PrebuiltModuleDep> PrebuiltModuleDeps;
186186

187-
/// A list of module identifiers this module directly depends on, not
188-
/// including transitive dependencies.
187+
/// This struct contains information about a single dependency.
188+
struct DepInfo {
189+
/// Identifies the dependency.
190+
ModuleID ID;
191+
192+
/// Indicates if the module that has this dependency exports it or not.
193+
bool Exported = false;
194+
195+
bool operator<(const DepInfo &Other) const {
196+
return std::tie(ID, Exported) < std::tie(Other.ID, Other.Exported);
197+
}
198+
};
199+
200+
/// A list of DepsInfo containing information about modules this module
201+
/// directly depends on, not including transitive dependencies.
189202
///
190203
/// This may include modules with a different context hash when it can be
191204
/// determined that the differences are benign for this compilation.
192-
std::vector<ModuleID> ClangModuleDeps;
205+
std::vector<ModuleDeps::DepInfo> ClangModuleDeps;
193206

194207
/// The CASID for the module input dependency tree, if any.
195208
std::optional<std::string> CASFileSystemRootID;
@@ -285,7 +298,8 @@ class ModuleDepCollectorPP final : public PPCallbacks {
285298
llvm::DenseSet<const Module *> &AddedModules);
286299

287300
/// Add discovered module dependency for the given module.
288-
void addOneModuleDep(const Module *M, const ModuleID ID, ModuleDeps &MD);
301+
void addOneModuleDep(const Module *M, bool Exported, const ModuleID ID,
302+
ModuleDeps &MD);
289303
};
290304

291305
/// Collects modular and non-modular dependencies of the main file by attaching
@@ -367,16 +381,16 @@ class ModuleDepCollector final : public DependencyCollector {
367381

368382
/// Collect module map files for given modules.
369383
llvm::DenseSet<const FileEntry *>
370-
collectModuleMapFiles(ArrayRef<ModuleID> ClangModuleDeps) const;
384+
collectModuleMapFiles(ArrayRef<ModuleDeps::DepInfo> ClangModuleDeps) const;
371385

372386
/// Add module map files to the invocation, if needed.
373387
void addModuleMapFiles(CompilerInvocation &CI,
374-
ArrayRef<ModuleID> ClangModuleDeps) const;
388+
ArrayRef<ModuleDeps::DepInfo> ClangModuleDeps) const;
375389
/// Add module files (pcm) to the invocation, if needed.
376390
void addModuleFiles(CompilerInvocation &CI,
377-
ArrayRef<ModuleID> ClangModuleDeps) const;
391+
ArrayRef<ModuleDeps::DepInfo> ClangModuleDeps) const;
378392
void addModuleFiles(CowCompilerInvocation &CI,
379-
ArrayRef<ModuleID> ClangModuleDeps) const;
393+
ArrayRef<ModuleDeps::DepInfo> ClangModuleDeps) const;
380394

381395
/// Add paths that require looking up outputs to the given dependencies.
382396
void addOutputPaths(CowCompilerInvocation &CI, ModuleDeps &Deps);

clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp

Lines changed: 38 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -404,10 +404,10 @@ ModuleDepCollector::getInvocationAdjustedForModuleBuildWithoutOutputs(
404404
}
405405

406406
llvm::DenseSet<const FileEntry *> ModuleDepCollector::collectModuleMapFiles(
407-
ArrayRef<ModuleID> ClangModuleDeps) const {
407+
ArrayRef<ModuleDeps::DepInfo> ClangModuleDeps) const {
408408
llvm::DenseSet<const FileEntry *> ModuleMapFiles;
409-
for (const ModuleID &MID : ClangModuleDeps) {
410-
ModuleDeps *MD = ModuleDepsByID.lookup(MID);
409+
for (const auto &Info : ClangModuleDeps) {
410+
ModuleDeps *MD = ModuleDepsByID.lookup(Info.ID);
411411
assert(MD && "Inconsistent dependency info");
412412
// TODO: Track ClangModuleMapFile as `FileEntryRef`.
413413
auto FE = ScanInstance.getFileManager().getOptionalFileRef(
@@ -419,21 +419,23 @@ llvm::DenseSet<const FileEntry *> ModuleDepCollector::collectModuleMapFiles(
419419
}
420420

421421
void ModuleDepCollector::addModuleMapFiles(
422-
CompilerInvocation &CI, ArrayRef<ModuleID> ClangModuleDeps) const {
422+
CompilerInvocation &CI,
423+
ArrayRef<ModuleDeps::DepInfo> ClangModuleDeps) const {
423424
if (Service.shouldEagerLoadModules())
424425
return; // Only pcm is needed for eager load.
425426

426-
for (const ModuleID &MID : ClangModuleDeps) {
427-
ModuleDeps *MD = ModuleDepsByID.lookup(MID);
427+
for (const auto &Info : ClangModuleDeps) {
428+
ModuleDeps *MD = ModuleDepsByID.lookup(Info.ID);
428429
assert(MD && "Inconsistent dependency info");
429430
CI.getFrontendOpts().ModuleMapFiles.push_back(MD->ClangModuleMapFile);
430431
}
431432
}
432433

433434
void ModuleDepCollector::addModuleFiles(
434-
CompilerInvocation &CI, ArrayRef<ModuleID> ClangModuleDeps) const {
435-
for (const ModuleID &MID : ClangModuleDeps) {
436-
ModuleDeps *MD = ModuleDepsByID.lookup(MID);
435+
CompilerInvocation &CI,
436+
ArrayRef<ModuleDeps::DepInfo> ClangModuleDeps) const {
437+
for (const auto &Info : ClangModuleDeps) {
438+
ModuleDeps *MD = ModuleDepsByID.lookup(Info.ID);
437439
std::string PCMPath =
438440
Controller.lookupModuleOutput(*MD, ModuleOutputKind::ModuleFile);
439441

@@ -445,14 +447,15 @@ void ModuleDepCollector::addModuleFiles(
445447
CI.getFrontendOpts().ModuleFiles.push_back(std::move(PCMPath));
446448
else
447449
CI.getHeaderSearchOpts().PrebuiltModuleFiles.insert(
448-
{MID.ModuleName, std::move(PCMPath)});
450+
{Info.ID.ModuleName, std::move(PCMPath)});
449451
}
450452
}
451453

452454
void ModuleDepCollector::addModuleFiles(
453-
CowCompilerInvocation &CI, ArrayRef<ModuleID> ClangModuleDeps) const {
454-
for (const ModuleID &MID : ClangModuleDeps) {
455-
ModuleDeps *MD = ModuleDepsByID.lookup(MID);
455+
CowCompilerInvocation &CI,
456+
ArrayRef<ModuleDeps::DepInfo> ClangModuleDeps) const {
457+
for (const auto &Info : ClangModuleDeps) {
458+
ModuleDeps *MD = ModuleDepsByID.lookup(Info.ID);
456459
std::string PCMPath =
457460
Controller.lookupModuleOutput(*MD, ModuleOutputKind::ModuleFile);
458461

@@ -464,7 +467,7 @@ void ModuleDepCollector::addModuleFiles(
464467
CI.getMutFrontendOpts().ModuleFiles.push_back(std::move(PCMPath));
465468
else
466469
CI.getMutHeaderSearchOpts().PrebuiltModuleFiles.insert(
467-
{MID.ModuleName, std::move(PCMPath)});
470+
{Info.ID.ModuleName, std::move(PCMPath)});
468471
}
469472
}
470473

@@ -494,10 +497,10 @@ void ModuleDepCollector::applyDiscoveredDependencies(CompilerInvocation &CI) {
494497
CI.getFrontendOpts().ModuleMapFiles.emplace_back(
495498
CurrentModuleMap->getNameAsRequested());
496499

497-
SmallVector<ModuleID> DirectDeps;
500+
SmallVector<ModuleDeps::DepInfo> DirectDeps;
498501
for (const auto &KV : ModularDeps)
499502
if (DirectModularDeps.contains(KV.first))
500-
DirectDeps.push_back(KV.second->ID);
503+
DirectDeps.push_back({KV.second->ID, /* Exported = */ false});
501504

502505
// TODO: Report module maps the same way it's done for modular dependencies.
503506
addModuleMapFiles(CI, DirectDeps);
@@ -646,9 +649,9 @@ static std::string getModuleContextHash(const ModuleDeps &MD,
646649
// example, case-insensitive paths to modulemap files. Usually such a case
647650
// would indicate a missed optimization to canonicalize, but it may be
648651
// difficult to canonicalize all cases when there is a VFS.
649-
for (const auto &ID : MD.ClangModuleDeps) {
650-
HashBuilder.add(ID.ModuleName);
651-
HashBuilder.add(ID.ContextHash);
652+
for (const auto &Info : MD.ClangModuleDeps) {
653+
HashBuilder.add(Info.ID.ModuleName);
654+
HashBuilder.add(Info.ID.ContextHash);
652655
}
653656

654657
HashBuilder.add(EagerLoadModules);
@@ -1021,22 +1024,30 @@ void ModuleDepCollectorPP::addAllSubmoduleDeps(
10211024
});
10221025
}
10231026

1024-
void ModuleDepCollectorPP::addOneModuleDep(const Module *M, const ModuleID ID,
1025-
ModuleDeps &MD) {
1026-
MD.ClangModuleDeps.push_back(ID);
1027+
void ModuleDepCollectorPP::addOneModuleDep(const Module *M, bool Exported,
1028+
const ModuleID ID, ModuleDeps &MD) {
1029+
MD.ClangModuleDeps.push_back({ID, Exported});
1030+
10271031
if (MD.IsInStableDirectories)
10281032
MD.IsInStableDirectories = MDC.ModularDeps[M]->IsInStableDirectories;
10291033
}
10301034

10311035
void ModuleDepCollectorPP::addModuleDep(
10321036
const Module *M, ModuleDeps &MD,
10331037
llvm::DenseSet<const Module *> &AddedModules) {
1038+
SmallVector<Module *> ExportedModulesVector;
1039+
M->getExportedModules(ExportedModulesVector);
1040+
llvm::DenseSet<const Module *> ExportedModulesSet(
1041+
ExportedModulesVector.begin(), ExportedModulesVector.end());
10341042
for (const Module *Import : M->Imports) {
1035-
if (Import->getTopLevelModule() != M->getTopLevelModule() &&
1043+
const Module *ImportedTopLevelModule = Import->getTopLevelModule();
1044+
if (ImportedTopLevelModule != M->getTopLevelModule() &&
10361045
!MDC.isPrebuiltModule(Import)) {
1037-
if (auto ImportID = handleTopLevelModule(Import->getTopLevelModule()))
1038-
if (AddedModules.insert(Import->getTopLevelModule()).second)
1039-
addOneModuleDep(Import->getTopLevelModule(), *ImportID, MD);
1046+
if (auto ImportID = handleTopLevelModule(ImportedTopLevelModule))
1047+
if (AddedModules.insert(ImportedTopLevelModule).second) {
1048+
bool Exported = ExportedModulesSet.contains(ImportedTopLevelModule);
1049+
addOneModuleDep(ImportedTopLevelModule, Exported, *ImportID, MD);
1050+
}
10401051
}
10411052
}
10421053
}
@@ -1060,7 +1071,7 @@ void ModuleDepCollectorPP::addAffectingClangModule(
10601071
!MDC.isPrebuiltModule(Affecting)) {
10611072
if (auto ImportID = handleTopLevelModule(Affecting))
10621073
if (AddedModules.insert(Affecting).second)
1063-
addOneModuleDep(Affecting, *ImportID, MD);
1074+
addOneModuleDep(Affecting, /* Exported = */ false, *ImportID, MD);
10641075
}
10651076
}
10661077
}

clang/test/ClangScanDeps/export.c

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
// Test correctly reporting what a module exports during dependency scanning.
2+
// Module A depends on modules B, C and D, but only exports B and C.
3+
// Module E depends on modules B, C and D, and exports all of them.
4+
5+
// RUN: rm -rf %t
6+
// RUN: split-file %s %t
7+
// RUN: sed -e "s|DIR|%/t|g" %t/cdb.json.template > %t/cdb.json
8+
// RUN: clang-scan-deps -compilation-database \
9+
// RUN: %t/cdb.json -format experimental-full > %t/deps.db
10+
// RUN: cat %t/deps.db | sed 's:\\\\\?:/:g' | FileCheck %s
11+
12+
//--- cdb.json.template
13+
[
14+
{
15+
"directory": "DIR",
16+
"command": "clang -c DIR/test.c -I DIR/AH -I DIR/BH -I DIR/CH -I DIR/DH -I DIR/EH -fmodules -fmodules-cache-path=DIR/cache",
17+
"file": "DIR/test.c"
18+
},
19+
]
20+
21+
//--- AH/A.h
22+
#include "B.h"
23+
#include "C.h"
24+
#include "D.h"
25+
26+
int funcA();
27+
28+
//--- AH/module.modulemap
29+
module A {
30+
header "A.h"
31+
32+
export B
33+
export C
34+
}
35+
36+
//--- BH/B.h
37+
//--- BH/module.modulemap
38+
module B {
39+
header "B.h"
40+
}
41+
42+
//--- CH/C.h
43+
//--- CH/module.modulemap
44+
module C {
45+
header "C.h"
46+
}
47+
48+
//--- DH/D.h
49+
//--- DH/module.modulemap
50+
module D {
51+
header "D.h"
52+
}
53+
54+
//--- EH/E.h
55+
#include "B.h"
56+
#include "C.h"
57+
#include "D.h"
58+
59+
//--- EH/module.modulemap
60+
module E {
61+
header "E.h"
62+
export *
63+
}
64+
65+
//--- test.c
66+
#include "A.h"
67+
#include "E.h"
68+
69+
int test1() {
70+
return funcA();
71+
}
72+
73+
// CHECK: {
74+
// CHECK-NEXT: "modules": [
75+
// CHECK-NEXT: {
76+
// CHECK-NEXT: "clang-module-deps": [
77+
// CHECK-NEXT: {
78+
// CHECK-NEXT: "context-hash": "[[HASH_MOD_B:.*]]",
79+
// CHECK-NEXT: "module-name": "B",
80+
// CHECK-NEXT: "exported": "true"
81+
// CHECK-NEXT: },
82+
// CHECK-NEXT: {
83+
// CHECK-NEXT: "context-hash": "[[HASH_MOD_C:.*]]",
84+
// CHECK-NEXT: "module-name": "C",
85+
// CHECK-NEXT: "exported": "true"
86+
// CHECK-NEXT: },
87+
// CHECK-NEXT: {
88+
// CHECK-NEXT: "context-hash": "[[HASH_MOD_D:.*]]",
89+
// CHECK-NEXT: "module-name": "D"
90+
// CHECK-NEXT: }
91+
// CHECK-NEXT: ],
92+
// CHECK-NEXT: "clang-modulemap-file":{{.*}},
93+
// CHECK-NEXT: "command-line": [
94+
// CHECK: ],
95+
// CHECK: "name": "A"
96+
// CHECK-NEXT: }
97+
// CHECK: {
98+
// CHECK: "name": "B"
99+
// CHECK: }
100+
// CHECK: {
101+
// CHECK: "name": "C"
102+
// CHECK: }
103+
// CHECK: {
104+
// CHECK: "name": "D"
105+
// CHECK: }
106+
// CHECK: {
107+
// CHECK-NEXT: "clang-module-deps": [
108+
// CHECK-NEXT: {
109+
// CHECK-NEXT: "context-hash": "[[HASH_MOD_B]]",
110+
// CHECK-NEXT: "module-name": "B",
111+
// CHECK-NEXT: "exported": "true"
112+
// CHECK-NEXT: },
113+
// CHECK-NEXT: {
114+
// CHECK-NEXT: "context-hash": "[[HASH_MOD_C]]",
115+
// CHECK-NEXT: "module-name": "C",
116+
// CHECK-NEXT: "exported": "true"
117+
// CHECK-NEXT: },
118+
// CHECK-NEXT: {
119+
// CHECK-NEXT: "context-hash": "[[HASH_MOD_D]]",
120+
// CHECK-NEXT: "module-name": "D",
121+
// CHECK-NEXT: "exported": "true"
122+
// CHECK-NEXT: }
123+
// CHECK-NEXT: ],
124+
// CHECK-NEXT: "clang-modulemap-file":{{.*}},
125+
// CHECK-NEXT: "command-line": [
126+
// CHECK: ],
127+
// CHECK: "name": "E"
128+
// CHECK-NEXT: }
129+
// CHECK: ]
130+
// CHECK: }
131+
132+
133+

clang/test/ClangScanDeps/optimize-vfs-pch.m

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,8 @@
5454
// CHECK-NEXT: "clang-module-deps": [
5555
// CHECK-NEXT: {
5656
// CHECK-NEXT: "context-hash": "{{.*}}",
57-
// CHECK-NEXT: "module-name": "E"
57+
// CHECK-NEXT: "module-name": "E",
58+
// CHECK-NEXT: "exported": "true"
5859
// CHECK-NEXT: }
5960
// CHECK-NEXT: ],
6061
// CHECK-NEXT: "clang-modulemap-file": "[[PREFIX]]/modules/D/module.modulemap",

clang/tools/clang-scan-deps/ClangScanDeps.cpp

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -605,16 +605,32 @@ static auto toJSONStrings(llvm::json::OStream &JOS, Container &&Strings) {
605605
};
606606
}
607607

608+
static auto toJSONModuleID(llvm::json::OStream &JOS, StringRef ContextHash,
609+
StringRef ModuleName, bool Exported) {
610+
return JOS.object([&] {
611+
JOS.attribute("context-hash", StringRef(ContextHash));
612+
JOS.attribute("module-name", StringRef(ModuleName));
613+
if (Exported)
614+
JOS.attribute("exported", StringRef("true"));
615+
});
616+
}
617+
608618
// Technically, we don't need to sort the dependency list to get determinism.
609619
// Leaving these be will simply preserve the import order.
610620
static auto toJSONSorted(llvm::json::OStream &JOS, std::vector<ModuleID> V) {
611621
llvm::sort(V);
612622
return [&JOS, V = std::move(V)] {
613-
for (const ModuleID &MID : V)
614-
JOS.object([&] {
615-
JOS.attribute("context-hash", StringRef(MID.ContextHash));
616-
JOS.attribute("module-name", StringRef(MID.ModuleName));
617-
});
623+
for (const auto &MID : V)
624+
toJSONModuleID(JOS, MID.ContextHash, MID.ModuleName, false);
625+
};
626+
}
627+
628+
static auto toJSONSorted(llvm::json::OStream &JOS,
629+
std::vector<ModuleDeps::DepInfo> V) {
630+
llvm::sort(V);
631+
return [&JOS, V = std::move(V)] {
632+
for (const ModuleDeps::DepInfo &MID : V)
633+
toJSONModuleID(JOS, MID.ID.ContextHash, MID.ID.ModuleName, MID.Exported);
618634
};
619635
}
620636

0 commit comments

Comments
 (0)