Skip to content

Commit 002bfdd

Browse files
committed
[clang][modules] Track affecting modules
When compiling a module, its semantics and Clang's behavior are affected by other modules. These modules are typically the **imported** ones. However, during implicit build, some modules end up being compiled and read without being actually imported. This patch starts tracking such modules and serializing them into `.pcm` files. This enables the dependency scanner to construct explicit compilations that mimic implicit build. Reviewed By: benlangmuir Differential Revision: https://reviews.llvm.org/D132430
1 parent b20104f commit 002bfdd

File tree

13 files changed

+299
-2
lines changed

13 files changed

+299
-2
lines changed

clang/include/clang/Basic/Module.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,10 @@ class Module {
345345
/// module depends.
346346
llvm::SmallSetVector<Module *, 2> Imports;
347347

348+
/// The set of top-level modules that affected the compilation of this module,
349+
/// but were not imported.
350+
llvm::SmallSetVector<Module *, 2> AffectingModules;
351+
348352
/// Describes an exported module.
349353
///
350354
/// The pointer is the module being re-exported, while the bit will be true

clang/include/clang/Lex/ModuleLoader.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,11 @@ class ModuleLoadResult {
5151
ModuleLoadResult() = default;
5252
ModuleLoadResult(Module *M) : Storage(M, Normal) {}
5353
ModuleLoadResult(LoadResultKind Kind) : Storage(nullptr, Kind) {}
54+
ModuleLoadResult(Module *M, LoadResultKind Kind) : Storage(M, Kind) {}
55+
56+
operator bool() const {
57+
return Storage.getInt() == Normal && Storage.getPointer();
58+
}
5459

5560
operator Module *() const { return Storage.getPointer(); }
5661

clang/include/clang/Lex/Preprocessor.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -860,6 +860,10 @@ class Preprocessor {
860860
/// The files that have been included.
861861
IncludedFilesSet IncludedFiles;
862862

863+
/// The set of top-level modules that affected preprocessing, but were not
864+
/// imported.
865+
llvm::SmallSetVector<Module *, 2> AffectingModules;
866+
863867
/// The set of known macros exported from modules.
864868
llvm::FoldingSet<ModuleMacro> ModuleMacros;
865869

@@ -1331,6 +1335,12 @@ class Preprocessor {
13311335

13321336
/// \}
13331337

1338+
/// Get the set of top-level modules that affected preprocessing, but were not
1339+
/// imported.
1340+
const llvm::SmallSetVector<Module *, 2> &getAffectingModules() const {
1341+
return AffectingModules;
1342+
}
1343+
13341344
/// Mark the file as included.
13351345
/// Returns true if this is the first time the file was included.
13361346
bool markIncluded(const FileEntry *File) {

clang/include/clang/Serialization/ASTBitCodes.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -829,6 +829,9 @@ enum SubmoduleRecordTypes {
829829
/// Specifies the name of the module that will eventually
830830
/// re-export the entities in this module.
831831
SUBMODULE_EXPORT_AS = 17,
832+
833+
/// Specifies affecting modules that were not imported.
834+
SUBMODULE_AFFECTING_MODULES = 18,
832835
};
833836

834837
/// Record types used within a comments block.

clang/include/clang/Serialization/ASTReader.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -689,7 +689,7 @@ class ASTReader
689689
Module *Mod;
690690

691691
/// The kind of module reference.
692-
enum { Import, Export, Conflict } Kind;
692+
enum { Import, Export, Conflict, Affecting } Kind;
693693

694694
/// The local ID of the module that is being exported.
695695
unsigned ID;

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,13 @@ class ModuleDepCollectorPP final : public PPCallbacks {
176176
llvm::DenseSet<const Module *> &AddedModules);
177177
void addModuleDep(const Module *M, ModuleDeps &MD,
178178
llvm::DenseSet<const Module *> &AddedModules);
179+
180+
/// Traverses the affecting modules and updates \c MD with references to the
181+
/// parent \c ModuleDepCollector info.
182+
void addAllAffectingModules(const Module *M, ModuleDeps &MD,
183+
llvm::DenseSet<const Module *> &AddedModules);
184+
void addAffectingModule(const Module *M, ModuleDeps &MD,
185+
llvm::DenseSet<const Module *> &AddedModules);
179186
};
180187

181188
/// Collects modular and non-modular dependencies of the main file by attaching

clang/lib/Frontend/CompilerInstance.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2099,7 +2099,7 @@ CompilerInstance::loadModule(SourceLocation ImportLoc,
20992099
<< Module->getFullModuleName()
21002100
<< SourceRange(Path.front().second, Path.back().second);
21012101

2102-
return ModuleLoadResult::MissingExpected;
2102+
return ModuleLoadResult(Module, ModuleLoadResult::MissingExpected);
21032103
}
21042104

21052105
// Check whether this module is available.

clang/lib/Lex/HeaderSearch.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1563,6 +1563,8 @@ static bool suggestModule(HeaderSearch &HS, const FileEntry *File,
15631563
*SuggestedModule = ModuleMap::KnownHeader();
15641564
return true;
15651565
}
1566+
// TODO: Add this module (or just its module map file) into something like
1567+
// `RequestingModule->AffectingModules`.
15661568
return false;
15671569
}
15681570
}

clang/lib/Lex/PPDirectives.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2281,6 +2281,13 @@ Preprocessor::ImportAction Preprocessor::HandleHeaderIncludeOrImport(
22812281
if (Imported) {
22822282
Action = Import;
22832283
} else if (Imported.isMissingExpected()) {
2284+
Module *M = static_cast<Module *>(Imported)->getTopLevelModule();
2285+
if (!BuildingSubmoduleStack.empty()) {
2286+
if (Imported != BuildingSubmoduleStack.back().M)
2287+
BuildingSubmoduleStack.back().M->AffectingModules.insert(M);
2288+
} else {
2289+
AffectingModules.insert(M);
2290+
}
22842291
// We failed to find a submodule that we assumed would exist (because it
22852292
// was in the directory of an umbrella header, for instance), but no
22862293
// actual module containing it exists (because the umbrella header is

clang/lib/Serialization/ASTReader.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4376,6 +4376,11 @@ ASTReader::ASTReadResult ASTReader::ReadAST(StringRef FileName,
43764376
Unresolved.Mod->Imports.insert(ResolvedMod);
43774377
continue;
43784378

4379+
case UnresolvedModuleRef::Affecting:
4380+
if (ResolvedMod)
4381+
Unresolved.Mod->AffectingModules.insert(ResolvedMod);
4382+
continue;
4383+
43794384
case UnresolvedModuleRef::Export:
43804385
if (ResolvedMod || Unresolved.IsWildcard)
43814386
Unresolved.Mod->Exports.push_back(
@@ -5674,6 +5679,18 @@ llvm::Error ASTReader::ReadSubmoduleBlock(ModuleFile &F,
56745679
}
56755680
break;
56765681

5682+
case SUBMODULE_AFFECTING_MODULES:
5683+
for (unsigned Idx = 0; Idx != Record.size(); ++Idx) {
5684+
UnresolvedModuleRef Unresolved;
5685+
Unresolved.File = &F;
5686+
Unresolved.Mod = CurrentModule;
5687+
Unresolved.ID = Record[Idx];
5688+
Unresolved.Kind = UnresolvedModuleRef::Affecting;
5689+
Unresolved.IsWildcard = false;
5690+
UnresolvedModuleRefs.push_back(Unresolved);
5691+
}
5692+
break;
5693+
56775694
case SUBMODULE_EXPORTS:
56785695
for (unsigned Idx = 0; Idx + 1 < Record.size(); Idx += 2) {
56795696
UnresolvedModuleRef Unresolved;

clang/lib/Serialization/ASTWriter.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -883,6 +883,7 @@ void ASTWriter::WriteBlockInfoBlock() {
883883
RECORD(SUBMODULE_TOPHEADER);
884884
RECORD(SUBMODULE_UMBRELLA_DIR);
885885
RECORD(SUBMODULE_IMPORTS);
886+
RECORD(SUBMODULE_AFFECTING_MODULES);
886887
RECORD(SUBMODULE_EXPORTS);
887888
RECORD(SUBMODULE_REQUIRES);
888889
RECORD(SUBMODULE_EXCLUDED_HEADER);
@@ -2865,6 +2866,14 @@ void ASTWriter::WriteSubmodules(Module *WritingModule) {
28652866
Stream.EmitRecord(SUBMODULE_IMPORTS, Record);
28662867
}
28672868

2869+
// Emit the modules affecting compilation that were not imported.
2870+
if (!Mod->AffectingModules.empty()) {
2871+
RecordData Record;
2872+
for (auto *I : Mod->AffectingModules)
2873+
Record.push_back(getSubmoduleID(I));
2874+
Stream.EmitRecord(SUBMODULE_AFFECTING_MODULES, Record);
2875+
}
2876+
28682877
// Emit the exports.
28692878
if (!Mod->Exports.empty()) {
28702879
RecordData Record;

clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,11 @@ void ModuleDepCollectorPP::EndOfMainFile() {
278278
if (!MDC.ScanInstance.getPreprocessorOpts().ImplicitPCHInclude.empty())
279279
MDC.addFileDep(MDC.ScanInstance.getPreprocessorOpts().ImplicitPCHInclude);
280280

281+
for (const Module *M :
282+
MDC.ScanInstance.getPreprocessor().getAffectingModules())
283+
if (!MDC.isPrebuiltModule(M))
284+
DirectModularDeps.insert(M);
285+
281286
for (const Module *M : DirectModularDeps) {
282287
// A top-level module might not be actually imported as a module when
283288
// -fmodule-name is used to compile a translation unit that imports this
@@ -389,6 +394,8 @@ ModuleID ModuleDepCollectorPP::handleTopLevelModule(const Module *M) {
389394
addAllSubmodulePrebuiltDeps(M, MD, SeenModules);
390395
llvm::DenseSet<const Module *> AddedModules;
391396
addAllSubmoduleDeps(M, MD, AddedModules);
397+
llvm::DenseSet<const Module *> ProcessedModules;
398+
addAllAffectingModules(M, MD, ProcessedModules);
392399

393400
MD.BuildInvocation = MDC.makeInvocationForModuleBuildWithoutOutputs(
394401
MD, [&](CompilerInvocation &BuildInvocation) {
@@ -461,6 +468,30 @@ void ModuleDepCollectorPP::addModuleDep(
461468
}
462469
}
463470

471+
void ModuleDepCollectorPP::addAllAffectingModules(
472+
const Module *M, ModuleDeps &MD,
473+
llvm::DenseSet<const Module *> &AddedModules) {
474+
addAffectingModule(M, MD, AddedModules);
475+
476+
for (const Module *SubM : M->submodules())
477+
addAllAffectingModules(SubM, MD, AddedModules);
478+
}
479+
480+
void ModuleDepCollectorPP::addAffectingModule(
481+
const Module *M, ModuleDeps &MD,
482+
llvm::DenseSet<const Module *> &AddedModules) {
483+
for (const Module *Affecting : M->AffectingModules) {
484+
assert(Affecting == Affecting->getTopLevelModule() &&
485+
"Not quite import not top-level module");
486+
if (Affecting != M->getTopLevelModule() &&
487+
!MDC.isPrebuiltModule(Affecting)) {
488+
ModuleID ImportID = handleTopLevelModule(Affecting);
489+
if (AddedModules.insert(Affecting).second)
490+
MD.ClangModuleDeps.push_back(ImportID);
491+
}
492+
}
493+
}
494+
464495
ModuleDepCollector::ModuleDepCollector(
465496
std::unique_ptr<DependencyOutputOptions> Opts,
466497
CompilerInstance &ScanInstance, DependencyConsumer &C,

0 commit comments

Comments
 (0)