Skip to content

Commit e16becb

Browse files
committed
[clang][modules] Allow including module maps to be non-affecting
1 parent 80f510b commit e16becb

File tree

7 files changed

+97
-50
lines changed

7 files changed

+97
-50
lines changed

clang/include/clang/Serialization/ASTBitCodes.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ namespace serialization {
4141
/// Version 4 of AST files also requires that the version control branch and
4242
/// revision match exactly, since there is no backward compatibility of
4343
/// AST files at this time.
44-
const unsigned VERSION_MAJOR = 30;
44+
const unsigned VERSION_MAJOR = 31;
4545

4646
/// AST file minor version number supported by this version of
4747
/// Clang.
@@ -51,7 +51,7 @@ const unsigned VERSION_MAJOR = 30;
5151
/// for the previous version could still support reading the new
5252
/// version by ignoring new kinds of subblocks), this number
5353
/// should be increased.
54-
const unsigned VERSION_MINOR = 1;
54+
const unsigned VERSION_MINOR = 0;
5555

5656
/// An ID number that refers to an identifier in an AST file.
5757
///

clang/include/clang/Serialization/ASTWriter.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,10 @@ class StoredDeclsList;
7676
class SwitchCase;
7777
class Token;
7878

79+
namespace SrcMgr {
80+
class FileInfo;
81+
} // namespace SrcMgr
82+
7983
/// Writes an AST file containing the contents of a translation unit.
8084
///
8185
/// The ASTWriter class produces a bitstream containing the serialized
@@ -491,6 +495,11 @@ class ASTWriter : public ASTDeserializationListener,
491495
/// during \c SourceManager serialization.
492496
void computeNonAffectingInputFiles();
493497

498+
/// Some affecting files can be included from files that are not considered
499+
/// affecting. This function erases such source locations.
500+
SourceLocation getAffectingIncludeLoc(const SourceManager &SourceMgr,
501+
const SrcMgr::FileInfo &File);
502+
494503
/// Returns an adjusted \c FileID, accounting for any non-affecting input
495504
/// files.
496505
FileID getAdjustedFileID(FileID FID) const;

clang/include/clang/Serialization/ModuleFile.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ struct InputFileInfo {
6969
bool Overridden;
7070
bool Transient;
7171
bool TopLevel;
72+
bool TopLevelAmongAffecting;
7273
bool ModuleMap;
7374
};
7475

clang/lib/Serialization/ASTReader.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2444,9 +2444,10 @@ InputFileInfo ASTReader::getInputFileInfo(ModuleFile &F, unsigned ID) {
24442444
R.Overridden = static_cast<bool>(Record[3]);
24452445
R.Transient = static_cast<bool>(Record[4]);
24462446
R.TopLevel = static_cast<bool>(Record[5]);
2447-
R.ModuleMap = static_cast<bool>(Record[6]);
2447+
R.TopLevelAmongAffecting = static_cast<bool>(Record[6]);
2448+
R.ModuleMap = static_cast<bool>(Record[7]);
24482449
std::tie(R.FilenameAsRequested, R.Filename) = [&]() {
2449-
uint16_t AsRequestedLength = Record[7];
2450+
uint16_t AsRequestedLength = Record[8];
24502451

24512452
std::string NameAsRequested = Blob.substr(0, AsRequestedLength).str();
24522453
std::string Name = Blob.substr(AsRequestedLength).str();

clang/lib/Serialization/ASTWriter.cpp

Lines changed: 76 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -173,57 +173,53 @@ GetAffectingModuleMaps(const Preprocessor &PP, Module *RootModule) {
173173

174174
const HeaderSearch &HS = PP.getHeaderSearchInfo();
175175
const ModuleMap &MM = HS.getModuleMap();
176-
const SourceManager &SourceMgr = PP.getSourceManager();
177176

178177
std::set<const FileEntry *> ModuleMaps;
179-
auto CollectIncludingModuleMaps = [&](FileID FID, FileEntryRef F) {
180-
if (!ModuleMaps.insert(F).second)
178+
std::set<const Module *> ProcessedModules;
179+
auto CollectModuleMapsForHierarchy = [&](const Module *M) {
180+
M = M->getTopLevelModule();
181+
182+
if (!ProcessedModules.insert(M).second)
181183
return;
182-
SourceLocation Loc = SourceMgr.getIncludeLoc(FID);
183-
// The include location of inferred module maps can point into the header
184-
// file that triggered the inferring. Cut off the walk if that's the case.
185-
while (Loc.isValid() && isModuleMap(SourceMgr.getFileCharacteristic(Loc))) {
186-
FID = SourceMgr.getFileID(Loc);
187-
F = *SourceMgr.getFileEntryRefForID(FID);
188-
if (!ModuleMaps.insert(F).second)
189-
break;
190-
Loc = SourceMgr.getIncludeLoc(FID);
191-
}
192-
};
193184

194-
std::set<const Module *> ProcessedModules;
195-
auto CollectIncludingMapsFromAncestors = [&](const Module *M) {
196-
for (const Module *Mod = M; Mod; Mod = Mod->Parent) {
197-
if (!ProcessedModules.insert(Mod).second)
198-
break;
185+
std::queue<const Module *> Q;
186+
Q.push(M);
187+
while (!Q.empty()) {
188+
const Module *Mod = Q.front();
189+
Q.pop();
190+
199191
// The containing module map is affecting, because it's being pointed
200192
// into by Module::DefinitionLoc.
201-
if (FileID FID = MM.getContainingModuleMapFileID(Mod); FID.isValid())
202-
CollectIncludingModuleMaps(FID, *SourceMgr.getFileEntryRefForID(FID));
193+
if (auto FE = MM.getContainingModuleMapFile(Mod); FE)
194+
ModuleMaps.insert(*FE);
203195
// For inferred modules, the module map that allowed inferring is not in
204196
// the include chain of the virtual containing module map file. It did
205197
// affect the compilation, though.
206-
if (FileID FID = MM.getModuleMapFileIDForUniquing(Mod); FID.isValid())
207-
CollectIncludingModuleMaps(FID, *SourceMgr.getFileEntryRefForID(FID));
198+
if (auto FE = MM.getModuleMapFileForUniquing(Mod); FE)
199+
ModuleMaps.insert(*FE);
200+
201+
for (auto *SubM : Mod->submodules())
202+
Q.push(SubM);
208203
}
209204
};
210205

211206
// Handle all the affecting modules referenced from the root module.
212207

208+
CollectModuleMapsForHierarchy(RootModule);
209+
213210
std::queue<const Module *> Q;
214211
Q.push(RootModule);
215212
while (!Q.empty()) {
216-
const Module *CurrentModule = Q.front();
213+
const Module *RootSubmodule = Q.front();
217214
Q.pop();
218215

219-
CollectIncludingMapsFromAncestors(CurrentModule);
220-
for (const Module *ImportedModule : CurrentModule->Imports)
221-
CollectIncludingMapsFromAncestors(ImportedModule);
222-
for (const Module *UndeclaredModule : CurrentModule->UndeclaredUses)
223-
CollectIncludingMapsFromAncestors(UndeclaredModule);
216+
for (const Module *ImportedModule : RootSubmodule->Imports)
217+
CollectModuleMapsForHierarchy(ImportedModule);
218+
for (const Module *UndeclaredModule : RootSubmodule->UndeclaredUses)
219+
CollectModuleMapsForHierarchy(UndeclaredModule);
224220

225-
for (auto *M : CurrentModule->submodules())
226-
Q.push(M);
221+
for (auto *SubM : RootSubmodule->submodules())
222+
Q.push(SubM);
227223
}
228224

229225
// Handle textually-included headers that belong to other modules.
@@ -249,9 +245,39 @@ GetAffectingModuleMaps(const Preprocessor &PP, Module *RootModule) {
249245

250246
for (const auto &KH : HS.findResolvedModulesForHeader(*File))
251247
if (const Module *M = KH.getModule())
252-
CollectIncludingMapsFromAncestors(M);
248+
CollectModuleMapsForHierarchy(M);
253249
}
254250

251+
// Note: This algorithm doesn't handle all edge-cases. Let's say something
252+
// from \c ModulesToProcess imports X. The algorithm doesn't pick up
253+
// Y.modulemap as affecting in the following cases:
254+
255+
//--- X.modulemap
256+
// module X { header "X.h" }
257+
// extern module Y "Y.modulemap
258+
//--- Y.modulemap
259+
// module Y { header "Y.h" }
260+
//
261+
// Since SourceManager doesn't keep list of files included from X.modulemap,
262+
// we would need to walk up the include chain from all leaf files to figure
263+
// out if they are reachable from X.modulemap and if so mark all module map
264+
// files in the chain as affecting.
265+
266+
//--- Y.modulemap
267+
// module Y { header "Y.h" }
268+
// extern module X "X.modulemap"
269+
//--- X.modulemap
270+
// module X { header "X.h" }
271+
// module Y.Sub { header "Y_Sub.h" }
272+
//
273+
// Only considering X.modulemap affecting means that parsing it without having
274+
// access to Y.modulemap fails. There is no way to find out this dependence
275+
// since ModuleMap does not keep a mapping from a module map file to the
276+
// modules it defines. We could always consider the including module map as
277+
// affecting, but that is problematic on MacOS, where X might be something
278+
// like Darwin whose parent module map includes lots of other module maps that
279+
// describe unrelated top-level modules.
280+
255281
return ModuleMaps;
256282
}
257283

@@ -1631,6 +1657,7 @@ struct InputFileEntry {
16311657
bool IsTransient;
16321658
bool BufferOverridden;
16331659
bool IsTopLevel;
1660+
bool IsTopLevelAmongAffecting;
16341661
bool IsModuleMap;
16351662
uint32_t ContentHash[2];
16361663

@@ -1639,6 +1666,18 @@ struct InputFileEntry {
16391666

16401667
} // namespace
16411668

1669+
SourceLocation ASTWriter::getAffectingIncludeLoc(const SourceManager &SourceMgr,
1670+
const SrcMgr::FileInfo &File) {
1671+
SourceLocation IncludeLoc = File.getIncludeLoc();
1672+
if (IncludeLoc.isValid()) {
1673+
FileID IncludeFID = SourceMgr.getFileID(IncludeLoc);
1674+
assert(IncludeFID.isValid() && "IncludeLoc in invalid file");
1675+
if (!IsSLocAffecting[IncludeFID.ID])
1676+
IncludeLoc = SourceLocation();
1677+
}
1678+
return IncludeLoc;
1679+
}
1680+
16421681
void ASTWriter::WriteInputFiles(SourceManager &SourceMgr,
16431682
HeaderSearchOptions &HSOpts) {
16441683
using namespace llvm;
@@ -1654,6 +1693,7 @@ void ASTWriter::WriteInputFiles(SourceManager &SourceMgr,
16541693
IFAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Overridden
16551694
IFAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Transient
16561695
IFAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Top-level
1696+
IFAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Top-level affect
16571697
IFAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Module map
16581698
IFAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 16)); // Name as req. len
16591699
IFAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Name as req. + name
@@ -1693,6 +1733,8 @@ void ASTWriter::WriteInputFiles(SourceManager &SourceMgr,
16931733
Entry.IsTransient = Cache->IsTransient;
16941734
Entry.BufferOverridden = Cache->BufferOverridden;
16951735
Entry.IsTopLevel = File.getIncludeLoc().isInvalid();
1736+
Entry.IsTopLevelAmongAffecting =
1737+
getAffectingIncludeLoc(SourceMgr, File).isInvalid();
16961738
Entry.IsModuleMap = isModuleMap(File.getFileCharacteristic());
16971739

16981740
auto ContentHash = hash_code(-1);
@@ -1758,6 +1800,7 @@ void ASTWriter::WriteInputFiles(SourceManager &SourceMgr,
17581800
Entry.BufferOverridden,
17591801
Entry.IsTransient,
17601802
Entry.IsTopLevel,
1803+
Entry.IsTopLevelAmongAffecting,
17611804
Entry.IsModuleMap,
17621805
NameAsRequested.size()};
17631806

@@ -2219,7 +2262,7 @@ void ASTWriter::WriteSourceManagerBlock(SourceManager &SourceMgr,
22192262
SLocEntryOffsets.push_back(Offset);
22202263
// Starting offset of this entry within this module, so skip the dummy.
22212264
Record.push_back(getAdjustedOffset(SLoc->getOffset()) - 2);
2222-
AddSourceLocation(File.getIncludeLoc(), Record);
2265+
AddSourceLocation(getAffectingIncludeLoc(SourceMgr, File), Record);
22232266
Record.push_back(File.getFileCharacteristic()); // FIXME: stable encoding
22242267
Record.push_back(File.hasLineDirectives());
22252268

clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -616,7 +616,7 @@ ModuleDepCollectorPP::handleTopLevelModule(const Module *M) {
616616
MDC.ScanInstance.getASTReader()->visitInputFileInfos(
617617
*MF, /*IncludeSystem=*/true,
618618
[&](const serialization::InputFileInfo &IFI, bool IsSystem) {
619-
if (!(IFI.TopLevel && IFI.ModuleMap))
619+
if (!(IFI.TopLevelAmongAffecting && IFI.ModuleMap))
620620
return;
621621
if (StringRef(IFI.FilenameAsRequested)
622622
.ends_with("__inferred_module.map"))

clang/test/ClangScanDeps/modules-extern-unrelated.m

Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -22,15 +22,8 @@
2222
//--- second/second.h
2323
#include "first_other.h"
2424

25-
//--- cdb.json.template
26-
[{
27-
"directory": "DIR",
28-
"file": "DIR/tu.m",
29-
"command": "clang -fmodules -fmodules-cache-path=DIR/cache -I DIR/zeroth -I DIR/first -I DIR/second -c DIR/tu.m -o DIR/tu.o"
30-
}]
31-
32-
// RUN: sed -e "s|DIR|%/t|g" -e "s|INPUTS|%/S/Inputs|g" %t/cdb.json.template > %t/cdb.json
33-
// RUN: clang-scan-deps -compilation-database %t/cdb.json -format experimental-full > %t/result.json
25+
// RUN: clang-scan-deps -format experimental-full -o %t/result.json \
26+
// RUN: -- %clang -fmodules -fmodules-cache-path=%t/cache -I %t/zeroth -I %t/first -I %t/second -c %t/tu.m -o %t/tu.o
3427
// RUN: cat %t/result.json | sed 's:\\\\\?:/:g' | FileCheck %s -DPREFIX=%/t
3528

3629
// CHECK: {
@@ -67,11 +60,11 @@
6760
// CHECK-NEXT: ],
6861
// CHECK-NEXT: "clang-modulemap-file": "[[PREFIX]]/second/second.modulemap",
6962
// CHECK-NEXT: "command-line": [
63+
// CHECK-NOT: "-fmodule-map-file=[[PREFIX]]/second/module.modulemap"
7064
// CHECK: ],
7165
// CHECK-NEXT: "context-hash": "{{.*}}",
7266
// CHECK-NEXT: "file-deps": [
7367
// CHECK-NEXT: "[[PREFIX]]/first/module.modulemap",
74-
// CHECK-NEXT: "[[PREFIX]]/second/module.modulemap",
7568
// CHECK-NEXT: "[[PREFIX]]/second/second.h",
7669
// CHECK-NEXT: "[[PREFIX]]/second/second.modulemap"
7770
// CHECK-NEXT: ],
@@ -90,11 +83,11 @@
9083
// CHECK-NEXT: ],
9184
// CHECK-NEXT: "clang-modulemap-file": "[[PREFIX]]/zeroth/module.modulemap",
9285
// CHECK-NEXT: "command-line": [
86+
// CHECK-NOT: "-fmodule-map-file=[[PREFIX]]/second/module.modulemap"
9387
// CHECK: ],
9488
// CHECK-NEXT: "context-hash": "{{.*}}",
9589
// CHECK-NEXT: "file-deps": [
9690
// CHECK-NEXT: "[[PREFIX]]/first/module.modulemap",
97-
// CHECK-NEXT: "[[PREFIX]]/second/module.modulemap",
9891
// CHECK-NEXT: "[[PREFIX]]/second/second.modulemap",
9992
// CHECK-NEXT: "[[PREFIX]]/zeroth/module.modulemap",
10093
// CHECK-NEXT: "[[PREFIX]]/zeroth/zeroth.h"
@@ -115,7 +108,7 @@
115108
// CHECK-NEXT: ],
116109
// CHECK-NEXT: "command-line": [
117110
// CHECK: ],
118-
// CHECK-NEXT: "executable": "clang",
111+
// CHECK-NEXT: "executable": "{{.*}}",
119112
// CHECK-NEXT: "file-deps": [
120113
// CHECK-NEXT: "[[PREFIX]]/tu.m"
121114
// CHECK-NEXT: ],

0 commit comments

Comments
 (0)