@@ -163,81 +163,106 @@ namespace {
163
163
164
164
std::optional<std::set<const FileEntry *>>
165
165
GetAffectingModuleMaps (const Preprocessor &PP, Module *RootModule) {
166
- // Without implicit module map search, there's no good reason to know about
167
- // any module maps that are not affecting.
168
- if (!PP. getHeaderSearchInfo (). getHeaderSearchOpts (). ImplicitModuleMaps )
166
+ if (!PP. getHeaderSearchInfo ()
167
+ . getHeaderSearchOpts ()
168
+ . ModulesPruneNonAffectingModuleMaps )
169
169
return std::nullopt;
170
170
171
- SmallVector<const Module *> ModulesToProcess{RootModule};
172
-
173
171
const HeaderSearch &HS = PP.getHeaderSearchInfo ();
174
-
175
- SmallVector<const FileEntry *, 16 > FilesByUID;
176
- HS.getFileMgr ().GetUniqueIDMapping (FilesByUID);
177
-
178
- if (FilesByUID.size () > HS.header_file_size ())
179
- FilesByUID.resize (HS.header_file_size ());
180
-
181
- for (unsigned UID = 0 , LastUID = FilesByUID.size (); UID != LastUID; ++UID) {
182
- const FileEntry *File = FilesByUID[UID];
183
- if (!File)
184
- continue ;
185
-
186
- const HeaderFileInfo *HFI = HS.getExistingLocalFileInfo (File);
187
- if (!HFI || (HFI->isModuleHeader && !HFI->isCompilingModuleHeader ))
188
- continue ;
189
-
190
- for (const auto &KH : HS.findResolvedModulesForHeader (File)) {
191
- if (!KH.getModule ())
192
- continue ;
193
- ModulesToProcess.push_back (KH.getModule ());
194
- }
195
- }
196
-
197
172
const ModuleMap &MM = HS.getModuleMap ();
198
- SourceManager &SourceMgr = PP.getSourceManager ();
199
173
200
174
std::set<const FileEntry *> ModuleMaps;
201
- auto CollectIncludingModuleMaps = [&](FileID FID, FileEntryRef F) {
202
- if (!ModuleMaps.insert (F).second )
175
+ std::set<const Module *> ProcessedModules;
176
+ auto CollectModuleMapsForHierarchy = [&](const Module *M) {
177
+ M = M->getTopLevelModule ();
178
+
179
+ if (!ProcessedModules.insert (M).second )
203
180
return ;
204
- SourceLocation Loc = SourceMgr.getIncludeLoc (FID);
205
- // The include location of inferred module maps can point into the header
206
- // file that triggered the inferring. Cut off the walk if that's the case.
207
- while (Loc.isValid () && isModuleMap (SourceMgr.getFileCharacteristic (Loc))) {
208
- FID = SourceMgr.getFileID (Loc);
209
- F = *SourceMgr.getFileEntryRefForID (FID);
210
- if (!ModuleMaps.insert (F).second )
211
- break ;
212
- Loc = SourceMgr.getIncludeLoc (FID);
213
- }
214
- };
215
181
216
- std::set<const Module *> ProcessedModules;
217
- auto CollectIncludingMapsFromAncestors = [&](const Module *M) {
218
- for (const Module *Mod = M; Mod; Mod = Mod->Parent ) {
219
- if (!ProcessedModules.insert (Mod).second )
220
- break ;
182
+ std::queue<const Module *> Q;
183
+ Q.push (M);
184
+ while (!Q.empty ()) {
185
+ const Module *Mod = Q.front ();
186
+ Q.pop ();
187
+
221
188
// The containing module map is affecting, because it's being pointed
222
189
// into by Module::DefinitionLoc.
223
- if (FileID FID = MM.getContainingModuleMapFileID (Mod); FID.isValid ())
224
- CollectIncludingModuleMaps (FID, *SourceMgr.getFileEntryRefForID (FID));
225
- // For inferred modules, the module map that allowed inferring is not in
226
- // the include chain of the virtual containing module map file. It did
227
- // affect the compilation, though.
228
- if (FileID FID = MM.getModuleMapFileIDForUniquing (Mod); FID.isValid ())
229
- CollectIncludingModuleMaps (FID, *SourceMgr.getFileEntryRefForID (FID));
190
+ if (auto FE = MM.getContainingModuleMapFile (Mod))
191
+ ModuleMaps.insert (*FE);
192
+ // For inferred modules, the module map that allowed inferring is not
193
+ // related to the virtual containing module map file. It did affect the
194
+ // compilation, though.
195
+ if (auto FE = MM.getModuleMapFileForUniquing (Mod))
196
+ ModuleMaps.insert (*FE);
197
+
198
+ for (auto *SubM : Mod->submodules ())
199
+ Q.push (SubM);
230
200
}
231
201
};
232
202
233
- for (const Module *CurrentModule : ModulesToProcess) {
234
- CollectIncludingMapsFromAncestors (CurrentModule);
203
+ // Handle all the affecting modules referenced from the root module.
204
+
205
+ CollectModuleMapsForHierarchy (RootModule);
206
+
207
+ std::queue<const Module *> Q;
208
+ Q.push (RootModule);
209
+ while (!Q.empty ()) {
210
+ const Module *CurrentModule = Q.front ();
211
+ Q.pop ();
212
+
235
213
for (const Module *ImportedModule : CurrentModule->Imports )
236
- CollectIncludingMapsFromAncestors (ImportedModule);
214
+ CollectModuleMapsForHierarchy (ImportedModule);
237
215
for (const Module *UndeclaredModule : CurrentModule->UndeclaredUses )
238
- CollectIncludingMapsFromAncestors (UndeclaredModule);
216
+ CollectModuleMapsForHierarchy (UndeclaredModule);
217
+
218
+ for (auto *M : CurrentModule->submodules ())
219
+ Q.push (M);
239
220
}
240
221
222
+ // Handle textually-included headers that belong to other modules.
223
+
224
+ SmallVector<const FileEntry *, 16 > FilesByUID;
225
+ HS.getFileMgr ().GetUniqueIDMapping (FilesByUID);
226
+
227
+ if (FilesByUID.size () > HS.header_file_size ())
228
+ FilesByUID.resize (HS.header_file_size ());
229
+
230
+ for (unsigned UID = 0 , LastUID = FilesByUID.size (); UID != LastUID; ++UID) {
231
+ const FileEntry *File = FilesByUID[UID];
232
+ if (!File)
233
+ continue ;
234
+
235
+ const HeaderFileInfo *HFI = HS.getExistingLocalFileInfo (File);
236
+ if (!HFI)
237
+ continue ; // We have no information on this being a header file.
238
+ if (!HFI->isCompilingModuleHeader && HFI->isModuleHeader )
239
+ continue ; // Modular header, handled in the above module-based loop.
240
+ if (!HFI->isCompilingModuleHeader && !HFI->IsLocallyIncluded )
241
+ continue ; // Non-modular header not included locally is not affecting.
242
+
243
+ for (const auto &KH : HS.findResolvedModulesForHeader (File))
244
+ if (const Module *M = KH.getModule ())
245
+ CollectModuleMapsForHierarchy (M);
246
+ }
247
+
248
+ // FIXME: This algorithm is not correct for module map hierarchies where
249
+ // module map file defining a (sub)module of a top-level module X includes
250
+ // a module map file that defines a (sub)module of another top-level module Y.
251
+ // Whenever X is affecting and Y is not, "replaying" this PCM file will fail
252
+ // when parsing module map files for X due to not knowing about the `extern`
253
+ // module map for Y.
254
+ //
255
+ // We don't have a good way to fix it here. We could mark all children of
256
+ // affecting module map files as being affecting as well, but that's
257
+ // expensive. SourceManager does not model the edge from parent to child
258
+ // SLocEntries, so instead, we would need to iterate over leaf module map
259
+ // files, walk up their include hierarchy and check whether we arrive at an
260
+ // affecting module map.
261
+ //
262
+ // Instead of complicating and slowing down this function, we should probably
263
+ // just ban module map hierarchies where module map defining a (sub)module X
264
+ // includes a module map defining a module that's not a submodule of X.
265
+
241
266
return ModuleMaps;
242
267
}
243
268
@@ -1637,6 +1662,18 @@ struct InputFileEntry {
1637
1662
1638
1663
} // namespace
1639
1664
1665
+ SourceLocation ASTWriter::getAffectingIncludeLoc (const SourceManager &SourceMgr,
1666
+ const SrcMgr::FileInfo &File) {
1667
+ SourceLocation IncludeLoc = File.getIncludeLoc ();
1668
+ if (IncludeLoc.isValid ()) {
1669
+ FileID IncludeFID = SourceMgr.getFileID (IncludeLoc);
1670
+ assert (IncludeFID.isValid () && " IncludeLoc in invalid file" );
1671
+ if (!IsSLocAffecting[IncludeFID.ID ])
1672
+ IncludeLoc = SourceLocation ();
1673
+ }
1674
+ return IncludeLoc;
1675
+ }
1676
+
1640
1677
void ASTWriter::WriteInputFiles (SourceManager &SourceMgr,
1641
1678
HeaderSearchOptions &HSOpts) {
1642
1679
using namespace llvm ;
@@ -1690,7 +1727,7 @@ void ASTWriter::WriteInputFiles(SourceManager &SourceMgr,
1690
1727
Entry.IsSystemFile = isSystem (File.getFileCharacteristic ());
1691
1728
Entry.IsTransient = Cache->IsTransient ;
1692
1729
Entry.BufferOverridden = Cache->BufferOverridden ;
1693
- Entry.IsTopLevel = File. getIncludeLoc ( ).isInvalid ();
1730
+ Entry.IsTopLevel = getAffectingIncludeLoc (SourceMgr, File ).isInvalid ();
1694
1731
Entry.IsModuleMap = isModuleMap (File.getFileCharacteristic ());
1695
1732
1696
1733
auto ContentHash = hash_code (-1 );
@@ -2061,14 +2098,13 @@ void ASTWriter::WriteHeaderSearch(const HeaderSearch &HS) {
2061
2098
if (!File)
2062
2099
continue ;
2063
2100
2064
- // Get the file info. Skip emitting this file if we have no information on
2065
- // it as a header file (in which case HFI will be null) or if it hasn't
2066
- // changed since it was loaded. Also skip it if it's for a modular header
2067
- // from a different module; in that case, we rely on the module(s)
2068
- // containing the header to provide this information.
2069
2101
const HeaderFileInfo *HFI = HS.getExistingLocalFileInfo (File);
2070
- if (!HFI || (HFI->isModuleHeader && !HFI->isCompilingModuleHeader ))
2071
- continue ;
2102
+ if (!HFI)
2103
+ continue ; // We have no information on this being a header file.
2104
+ if (!HFI->isCompilingModuleHeader && HFI->isModuleHeader )
2105
+ continue ; // Header file info is tracked by the owning module file.
2106
+ if (!HFI->isCompilingModuleHeader && !PP->alreadyIncluded (File))
2107
+ continue ; // Non-modular header not included is not needed.
2072
2108
2073
2109
// Massage the file path into an appropriate form.
2074
2110
StringRef Filename = File->getName ();
@@ -2217,7 +2253,7 @@ void ASTWriter::WriteSourceManagerBlock(SourceManager &SourceMgr,
2217
2253
SLocEntryOffsets.push_back (Offset);
2218
2254
// Starting offset of this entry within this module, so skip the dummy.
2219
2255
Record.push_back (getAdjustedOffset (SLoc->getOffset ()) - 2 );
2220
- AddSourceLocation (File. getIncludeLoc ( ), Record);
2256
+ AddSourceLocation (getAffectingIncludeLoc (SourceMgr, File ), Record);
2221
2257
Record.push_back (File.getFileCharacteristic ()); // FIXME: stable encoding
2222
2258
Record.push_back (File.hasLineDirectives ());
2223
2259
0 commit comments