@@ -173,54 +173,50 @@ GetAffectingModuleMaps(const Preprocessor &PP, Module *RootModule) {
173
173
174
174
const HeaderSearch &HS = PP.getHeaderSearchInfo ();
175
175
const ModuleMap &MM = HS.getModuleMap ();
176
- const SourceManager &SourceMgr = PP.getSourceManager ();
177
176
178
177
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 )
181
183
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
- };
193
184
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
+
199
191
// The containing module map is affecting, because it's being pointed
200
192
// into by Module::DefinitionLoc.
201
- if (FileID FID = MM.getContainingModuleMapFileID (Mod); FID.isValid ())
202
- CollectIncludingModuleMaps (FID, *SourceMgr.getFileEntryRefForID (FID));
203
- // For inferred modules, the module map that allowed inferring is not in
204
- // the include chain of the virtual containing module map file. It did
205
- // affect the compilation, though.
206
- if (FileID FID = MM.getModuleMapFileIDForUniquing (Mod); FID.isValid ())
207
- CollectIncludingModuleMaps (FID, *SourceMgr.getFileEntryRefForID (FID));
193
+ if (auto FE = MM.getContainingModuleMapFile (Mod))
194
+ ModuleMaps.insert (*FE);
195
+ // For inferred modules, the module map that allowed inferring is not
196
+ // related to the virtual containing module map file. It did affect the
197
+ // compilation, though.
198
+ if (auto FE = MM.getModuleMapFileForUniquing (Mod))
199
+ ModuleMaps.insert (*FE);
200
+
201
+ for (auto *SubM : Mod->submodules ())
202
+ Q.push (SubM);
208
203
}
209
204
};
210
205
211
206
// Handle all the affecting modules referenced from the root module.
212
207
208
+ CollectModuleMapsForHierarchy (RootModule);
209
+
213
210
std::queue<const Module *> Q;
214
211
Q.push (RootModule);
215
212
while (!Q.empty ()) {
216
213
const Module *CurrentModule = Q.front ();
217
214
Q.pop ();
218
215
219
- CollectIncludingMapsFromAncestors (CurrentModule);
220
216
for (const Module *ImportedModule : CurrentModule->Imports )
221
- CollectIncludingMapsFromAncestors (ImportedModule);
217
+ CollectModuleMapsForHierarchy (ImportedModule);
222
218
for (const Module *UndeclaredModule : CurrentModule->UndeclaredUses )
223
- CollectIncludingMapsFromAncestors (UndeclaredModule);
219
+ CollectModuleMapsForHierarchy (UndeclaredModule);
224
220
225
221
for (auto *M : CurrentModule->submodules ())
226
222
Q.push (M);
@@ -249,9 +245,27 @@ GetAffectingModuleMaps(const Preprocessor &PP, Module *RootModule) {
249
245
250
246
for (const auto &KH : HS.findResolvedModulesForHeader (*File))
251
247
if (const Module *M = KH.getModule ())
252
- CollectIncludingMapsFromAncestors (M);
248
+ CollectModuleMapsForHierarchy (M);
253
249
}
254
250
251
+ // FIXME: This algorithm is not correct for module map hierarchies where
252
+ // module map file defining a (sub)module of a top-level module X includes
253
+ // a module map file that defines a (sub)module of another top-level module Y.
254
+ // Whenever X is affecting and Y is not, "replaying" this PCM file will fail
255
+ // when parsing module map files for X due to not knowing about the `extern`
256
+ // module map for Y.
257
+ //
258
+ // We don't have a good way to fix it here. We could mark all children of
259
+ // affecting module map files as being affecting as well, but that's
260
+ // expensive. SourceManager does not model the edge from parent to child
261
+ // SLocEntries, so instead, we would need to iterate over leaf module map
262
+ // files, walk up their include hierarchy and check whether we arrive at an
263
+ // affecting module map.
264
+ //
265
+ // Instead of complicating and slowing down this function, we should probably
266
+ // just ban module map hierarchies where module map defining a (sub)module X
267
+ // includes a module map defining a module that's not a submodule of X.
268
+
255
269
return ModuleMaps;
256
270
}
257
271
@@ -1631,6 +1645,7 @@ struct InputFileEntry {
1631
1645
bool IsTransient;
1632
1646
bool BufferOverridden;
1633
1647
bool IsTopLevel;
1648
+ bool IsTopLevelAmongAffecting;
1634
1649
bool IsModuleMap;
1635
1650
uint32_t ContentHash[2 ];
1636
1651
@@ -1639,6 +1654,18 @@ struct InputFileEntry {
1639
1654
1640
1655
} // namespace
1641
1656
1657
+ SourceLocation ASTWriter::getAffectingIncludeLoc (const SourceManager &SourceMgr,
1658
+ const SrcMgr::FileInfo &File) {
1659
+ SourceLocation IncludeLoc = File.getIncludeLoc ();
1660
+ if (IncludeLoc.isValid ()) {
1661
+ FileID IncludeFID = SourceMgr.getFileID (IncludeLoc);
1662
+ assert (IncludeFID.isValid () && " IncludeLoc in invalid file" );
1663
+ if (!IsSLocAffecting[IncludeFID.ID ])
1664
+ IncludeLoc = SourceLocation ();
1665
+ }
1666
+ return IncludeLoc;
1667
+ }
1668
+
1642
1669
void ASTWriter::WriteInputFiles (SourceManager &SourceMgr,
1643
1670
HeaderSearchOptions &HSOpts) {
1644
1671
using namespace llvm ;
@@ -1654,6 +1681,7 @@ void ASTWriter::WriteInputFiles(SourceManager &SourceMgr,
1654
1681
IFAbbrev->Add (BitCodeAbbrevOp (BitCodeAbbrevOp::Fixed, 1 )); // Overridden
1655
1682
IFAbbrev->Add (BitCodeAbbrevOp (BitCodeAbbrevOp::Fixed, 1 )); // Transient
1656
1683
IFAbbrev->Add (BitCodeAbbrevOp (BitCodeAbbrevOp::Fixed, 1 )); // Top-level
1684
+ IFAbbrev->Add (BitCodeAbbrevOp (BitCodeAbbrevOp::Fixed, 1 )); // Top-level affect
1657
1685
IFAbbrev->Add (BitCodeAbbrevOp (BitCodeAbbrevOp::Fixed, 1 )); // Module map
1658
1686
IFAbbrev->Add (BitCodeAbbrevOp (BitCodeAbbrevOp::VBR, 16 )); // Name as req. len
1659
1687
IFAbbrev->Add (BitCodeAbbrevOp (BitCodeAbbrevOp::Blob)); // Name as req. + name
@@ -1693,6 +1721,8 @@ void ASTWriter::WriteInputFiles(SourceManager &SourceMgr,
1693
1721
Entry.IsTransient = Cache->IsTransient ;
1694
1722
Entry.BufferOverridden = Cache->BufferOverridden ;
1695
1723
Entry.IsTopLevel = File.getIncludeLoc ().isInvalid ();
1724
+ Entry.IsTopLevelAmongAffecting =
1725
+ getAffectingIncludeLoc (SourceMgr, File).isInvalid ();
1696
1726
Entry.IsModuleMap = isModuleMap (File.getFileCharacteristic ());
1697
1727
1698
1728
auto ContentHash = hash_code (-1 );
@@ -1758,6 +1788,7 @@ void ASTWriter::WriteInputFiles(SourceManager &SourceMgr,
1758
1788
Entry.BufferOverridden ,
1759
1789
Entry.IsTransient ,
1760
1790
Entry.IsTopLevel ,
1791
+ Entry.IsTopLevelAmongAffecting ,
1761
1792
Entry.IsModuleMap ,
1762
1793
NameAsRequested.size ()};
1763
1794
@@ -2219,7 +2250,7 @@ void ASTWriter::WriteSourceManagerBlock(SourceManager &SourceMgr,
2219
2250
SLocEntryOffsets.push_back (Offset);
2220
2251
// Starting offset of this entry within this module, so skip the dummy.
2221
2252
Record.push_back (getAdjustedOffset (SLoc->getOffset ()) - 2 );
2222
- AddSourceLocation (File. getIncludeLoc ( ), Record);
2253
+ AddSourceLocation (getAffectingIncludeLoc (SourceMgr, File ), Record);
2223
2254
Record.push_back (File.getFileCharacteristic ()); // FIXME: stable encoding
2224
2255
Record.push_back (File.hasLineDirectives ());
2225
2256
0 commit comments