Skip to content

Commit 1e25ff8

Browse files
committed
[clang][deps] Fix traversal of precompiled dependencies
The code for traversing precompiled dependencies is somewhat complicated and contains a dangling iterator bug. This patch simplifies the code and fixes the bug. Reviewed By: dexonsmith Differential Revision: https://reviews.llvm.org/D121533
1 parent d73daa9 commit 1e25ff8

File tree

2 files changed

+156
-30
lines changed

2 files changed

+156
-30
lines changed

clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp

Lines changed: 17 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -46,21 +46,25 @@ class DependencyConsumerForwarder : public DependencyFileGenerator {
4646
DependencyConsumer &C;
4747
};
4848

49+
using PrebuiltModuleFilesT = decltype(HeaderSearchOptions::PrebuiltModuleFiles);
50+
4951
/// A listener that collects the imported modules and optionally the input
5052
/// files.
5153
class PrebuiltModuleListener : public ASTReaderListener {
5254
public:
53-
PrebuiltModuleListener(llvm::StringMap<std::string> &PrebuiltModuleFiles,
54-
llvm::StringSet<> &InputFiles, bool VisitInputFiles)
55+
PrebuiltModuleListener(PrebuiltModuleFilesT &PrebuiltModuleFiles,
56+
llvm::StringSet<> &InputFiles, bool VisitInputFiles,
57+
llvm::SmallVector<std::string> &NewModuleFiles)
5558
: PrebuiltModuleFiles(PrebuiltModuleFiles), InputFiles(InputFiles),
56-
VisitInputFiles(VisitInputFiles) {}
59+
VisitInputFiles(VisitInputFiles), NewModuleFiles(NewModuleFiles) {}
5760

5861
bool needsImportVisitation() const override { return true; }
5962
bool needsInputFileVisitation() override { return VisitInputFiles; }
6063
bool needsSystemInputFileVisitation() override { return VisitInputFiles; }
6164

6265
void visitImport(StringRef ModuleName, StringRef Filename) override {
63-
PrebuiltModuleFiles.insert({ModuleName, Filename.str()});
66+
if (PrebuiltModuleFiles.insert({ModuleName.str(), Filename.str()}).second)
67+
NewModuleFiles.push_back(Filename.str());
6468
}
6569

6670
bool visitInputFile(StringRef Filename, bool isSystem, bool isOverridden,
@@ -70,47 +74,30 @@ class PrebuiltModuleListener : public ASTReaderListener {
7074
}
7175

7276
private:
73-
llvm::StringMap<std::string> &PrebuiltModuleFiles;
77+
PrebuiltModuleFilesT &PrebuiltModuleFiles;
7478
llvm::StringSet<> &InputFiles;
7579
bool VisitInputFiles;
80+
llvm::SmallVector<std::string> &NewModuleFiles;
7681
};
7782

78-
using PrebuiltModuleFilesT = decltype(HeaderSearchOptions::PrebuiltModuleFiles);
79-
8083
/// Visit the given prebuilt module and collect all of the modules it
8184
/// transitively imports and contributing input files.
8285
static void visitPrebuiltModule(StringRef PrebuiltModuleFilename,
8386
CompilerInstance &CI,
8487
PrebuiltModuleFilesT &ModuleFiles,
8588
llvm::StringSet<> &InputFiles,
8689
bool VisitInputFiles) {
87-
// Maps the names of modules that weren't yet visited to their PCM path.
88-
llvm::StringMap<std::string> ModuleFilesWorklist;
89-
// Contains PCM paths of all visited modules.
90-
llvm::StringSet<> VisitedModuleFiles;
91-
92-
PrebuiltModuleListener Listener(ModuleFilesWorklist, InputFiles,
93-
VisitInputFiles);
90+
// List of module files to be processed.
91+
llvm::SmallVector<std::string> Worklist{PrebuiltModuleFilename.str()};
92+
PrebuiltModuleListener Listener(ModuleFiles, InputFiles, VisitInputFiles,
93+
Worklist);
9494

95-
auto GatherModuleFileInfo = [&](StringRef ASTFile) {
95+
while (!Worklist.empty())
9696
ASTReader::readASTFileControlBlock(
97-
ASTFile, CI.getFileManager(), CI.getPCHContainerReader(),
97+
Worklist.pop_back_val(), CI.getFileManager(),
98+
CI.getPCHContainerReader(),
9899
/*FindModuleFileExtensions=*/false, Listener,
99100
/*ValidateDiagnosticOptions=*/false);
100-
};
101-
102-
GatherModuleFileInfo(PrebuiltModuleFilename);
103-
while (!ModuleFilesWorklist.empty()) {
104-
auto WorklistItemIt = ModuleFilesWorklist.begin();
105-
106-
if (!VisitedModuleFiles.contains(WorklistItemIt->getValue())) {
107-
VisitedModuleFiles.insert(WorklistItemIt->getValue());
108-
GatherModuleFileInfo(WorklistItemIt->getValue());
109-
ModuleFiles[WorklistItemIt->getKey().str()] = WorklistItemIt->getValue();
110-
}
111-
112-
ModuleFilesWorklist.erase(WorklistItemIt);
113-
}
114101
}
115102

116103
/// Transform arbitrary file name into an object-like file name.
Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
// Unsupported on AIX because we don't support the requisite "__clangast"
2+
// section in XCOFF yet.
3+
// UNSUPPORTED: aix
4+
5+
// This test checks that the dependency scanner can handle larger amount of
6+
// explicitly built modules retrieved from the PCH.
7+
// (Previously, there was a bug dangling iterator bug that manifested only with
8+
// 16 and more retrieved modules.)
9+
10+
// RUN: rm -rf %t
11+
// RUN: split-file %s %t
12+
13+
//--- mod_00.h
14+
//--- mod_01.h
15+
//--- mod_02.h
16+
//--- mod_03.h
17+
//--- mod_04.h
18+
//--- mod_05.h
19+
//--- mod_06.h
20+
//--- mod_07.h
21+
//--- mod_08.h
22+
//--- mod_09.h
23+
//--- mod_10.h
24+
//--- mod_11.h
25+
//--- mod_12.h
26+
//--- mod_13.h
27+
//--- mod_14.h
28+
//--- mod_15.h
29+
//--- mod_16.h
30+
//--- mod.h
31+
#include "mod_00.h"
32+
#include "mod_01.h"
33+
#include "mod_02.h"
34+
#include "mod_03.h"
35+
#include "mod_04.h"
36+
#include "mod_05.h"
37+
#include "mod_06.h"
38+
#include "mod_07.h"
39+
#include "mod_08.h"
40+
#include "mod_09.h"
41+
#include "mod_10.h"
42+
#include "mod_11.h"
43+
#include "mod_12.h"
44+
#include "mod_13.h"
45+
#include "mod_14.h"
46+
#include "mod_15.h"
47+
#include "mod_16.h"
48+
//--- module.modulemap
49+
module mod_00 { header "mod_00.h" }
50+
module mod_01 { header "mod_01.h" }
51+
module mod_02 { header "mod_02.h" }
52+
module mod_03 { header "mod_03.h" }
53+
module mod_04 { header "mod_04.h" }
54+
module mod_05 { header "mod_05.h" }
55+
module mod_06 { header "mod_06.h" }
56+
module mod_07 { header "mod_07.h" }
57+
module mod_08 { header "mod_08.h" }
58+
module mod_09 { header "mod_09.h" }
59+
module mod_10 { header "mod_10.h" }
60+
module mod_11 { header "mod_11.h" }
61+
module mod_12 { header "mod_12.h" }
62+
module mod_13 { header "mod_13.h" }
63+
module mod_14 { header "mod_14.h" }
64+
module mod_15 { header "mod_15.h" }
65+
module mod_16 { header "mod_16.h" }
66+
module mod { header "mod.h" }
67+
68+
//--- pch.h
69+
#include "mod.h"
70+
71+
//--- tu.c
72+
73+
//--- cdb_pch.json.template
74+
[{
75+
"file": "DIR/pch.h",
76+
"directory": "DIR",
77+
"command": "clang -x c-header DIR/pch.h -fmodules -gmodules -fimplicit-module-maps -fmodules-cache-path=DIR/cache -o DIR/pch.h.gch"
78+
}]
79+
80+
//--- cdb_tu.json.template
81+
[{
82+
"file": "DIR/tu.c",
83+
"directory": "DIR",
84+
"command": "clang -fsyntax-only DIR/tu.c -fmodules -gmodules -fimplicit-module-maps -fmodules-cache-path=DIR/cache -include DIR/pch.h -o DIR/tu.o"
85+
}]
86+
87+
// Scan dependencies of the PCH:
88+
//
89+
// RUN: sed "s|DIR|%/t|g" %t/cdb_pch.json.template > %t/cdb_pch.json
90+
// RUN: clang-scan-deps -compilation-database %t/cdb_pch.json -format experimental-full \
91+
// RUN: -generate-modules-path-args -module-files-dir %t/build > %t/result_pch.json
92+
93+
// Explicitly build the PCH:
94+
//
95+
// RUN: %python %S/../../utils/module-deps-to-rsp.py %t/result_pch.json --module-name=mod_00 > %t/mod_00.cc1.rsp
96+
// RUN: %python %S/../../utils/module-deps-to-rsp.py %t/result_pch.json --module-name=mod_01 > %t/mod_01.cc1.rsp
97+
// RUN: %python %S/../../utils/module-deps-to-rsp.py %t/result_pch.json --module-name=mod_02 > %t/mod_02.cc1.rsp
98+
// RUN: %python %S/../../utils/module-deps-to-rsp.py %t/result_pch.json --module-name=mod_03 > %t/mod_03.cc1.rsp
99+
// RUN: %python %S/../../utils/module-deps-to-rsp.py %t/result_pch.json --module-name=mod_04 > %t/mod_04.cc1.rsp
100+
// RUN: %python %S/../../utils/module-deps-to-rsp.py %t/result_pch.json --module-name=mod_05 > %t/mod_05.cc1.rsp
101+
// RUN: %python %S/../../utils/module-deps-to-rsp.py %t/result_pch.json --module-name=mod_06 > %t/mod_06.cc1.rsp
102+
// RUN: %python %S/../../utils/module-deps-to-rsp.py %t/result_pch.json --module-name=mod_07 > %t/mod_07.cc1.rsp
103+
// RUN: %python %S/../../utils/module-deps-to-rsp.py %t/result_pch.json --module-name=mod_08 > %t/mod_08.cc1.rsp
104+
// RUN: %python %S/../../utils/module-deps-to-rsp.py %t/result_pch.json --module-name=mod_09 > %t/mod_09.cc1.rsp
105+
// RUN: %python %S/../../utils/module-deps-to-rsp.py %t/result_pch.json --module-name=mod_10 > %t/mod_10.cc1.rsp
106+
// RUN: %python %S/../../utils/module-deps-to-rsp.py %t/result_pch.json --module-name=mod_11 > %t/mod_11.cc1.rsp
107+
// RUN: %python %S/../../utils/module-deps-to-rsp.py %t/result_pch.json --module-name=mod_12 > %t/mod_12.cc1.rsp
108+
// RUN: %python %S/../../utils/module-deps-to-rsp.py %t/result_pch.json --module-name=mod_13 > %t/mod_13.cc1.rsp
109+
// RUN: %python %S/../../utils/module-deps-to-rsp.py %t/result_pch.json --module-name=mod_14 > %t/mod_14.cc1.rsp
110+
// RUN: %python %S/../../utils/module-deps-to-rsp.py %t/result_pch.json --module-name=mod_15 > %t/mod_15.cc1.rsp
111+
// RUN: %python %S/../../utils/module-deps-to-rsp.py %t/result_pch.json --module-name=mod_16 > %t/mod_16.cc1.rsp
112+
// RUN: %python %S/../../utils/module-deps-to-rsp.py %t/result_pch.json --module-name=mod > %t/mod.cc1.rsp
113+
// RUN: %python %S/../../utils/module-deps-to-rsp.py %t/result_pch.json --tu-index=0 > %t/pch.rsp
114+
//
115+
// RUN: %clang @%t/mod_00.cc1.rsp
116+
// RUN: %clang @%t/mod_01.cc1.rsp
117+
// RUN: %clang @%t/mod_02.cc1.rsp
118+
// RUN: %clang @%t/mod_03.cc1.rsp
119+
// RUN: %clang @%t/mod_04.cc1.rsp
120+
// RUN: %clang @%t/mod_05.cc1.rsp
121+
// RUN: %clang @%t/mod_06.cc1.rsp
122+
// RUN: %clang @%t/mod_07.cc1.rsp
123+
// RUN: %clang @%t/mod_08.cc1.rsp
124+
// RUN: %clang @%t/mod_09.cc1.rsp
125+
// RUN: %clang @%t/mod_10.cc1.rsp
126+
// RUN: %clang @%t/mod_11.cc1.rsp
127+
// RUN: %clang @%t/mod_12.cc1.rsp
128+
// RUN: %clang @%t/mod_13.cc1.rsp
129+
// RUN: %clang @%t/mod_14.cc1.rsp
130+
// RUN: %clang @%t/mod_15.cc1.rsp
131+
// RUN: %clang @%t/mod_16.cc1.rsp
132+
// RUN: %clang @%t/mod.cc1.rsp
133+
// RUN: %clang @%t/pch.rsp
134+
135+
// Scan dependencies of the TU, checking it doesn't crash:
136+
//
137+
// RUN: sed "s|DIR|%/t|g" %t/cdb_tu.json.template > %t/cdb_tu.json
138+
// RUN: clang-scan-deps -compilation-database %t/cdb_tu.json -format experimental-full \
139+
// RUN: -generate-modules-path-args -module-files-dir %t/build

0 commit comments

Comments
 (0)