Skip to content

Commit

Permalink
[clang][modules] Report module maps affecting `no_undeclared_includes…
Browse files Browse the repository at this point in the history
…` modules

Since D106876, PCM files don't report module maps as input files unless they contributed to the compilation.

Reporting only module maps of (transitively) imported modules is not enough, though. For modules marked with `[no_undeclared_includes]`, other module maps affect the compilation by introducing anti-dependencies.

This patch makes sure such module maps are being reported as input files.

Depends on D120463.

Reviewed By: dexonsmith

Differential Revision: https://reviews.llvm.org/D120464
  • Loading branch information
jansvoboda11 committed Mar 7, 2022
1 parent 242b24c commit b45888e
Show file tree
Hide file tree
Showing 4 changed files with 49 additions and 7 deletions.
6 changes: 5 additions & 1 deletion clang/include/clang/Basic/Module.h
Expand Up @@ -371,6 +371,10 @@ class Module {
/// The set of use declarations that have yet to be resolved.
SmallVector<ModuleId, 2> UnresolvedDirectUses;

/// When \c NoUndeclaredIncludes is true, the set of modules this module tried
/// to import but didn't because they are not direct uses.
llvm::SmallSetVector<const Module *, 2> UndeclaredUses;

/// A library or framework to link against when an entity from this
/// module is used.
struct LinkLibrary {
Expand Down Expand Up @@ -601,7 +605,7 @@ class Module {

/// Determine whether this module has declared its intention to
/// directly use another module.
bool directlyUses(const Module *Requested) const;
bool directlyUses(const Module *Requested);

/// Add the given feature requirement to the list of features
/// required by this module.
Expand Down
5 changes: 4 additions & 1 deletion clang/lib/Basic/Module.cpp
Expand Up @@ -267,7 +267,7 @@ ArrayRef<const FileEntry *> Module::getTopHeaders(FileManager &FileMgr) {
return llvm::makeArrayRef(TopHeaders.begin(), TopHeaders.end());
}

bool Module::directlyUses(const Module *Requested) const {
bool Module::directlyUses(const Module *Requested) {
auto *Top = getTopLevelModule();

// A top-level module implicitly uses itself.
Expand All @@ -282,6 +282,9 @@ bool Module::directlyUses(const Module *Requested) const {
if (!Requested->Parent && Requested->Name == "_Builtin_stddef_max_align_t")
return true;

if (NoUndeclaredIncludes)
UndeclaredUses.insert(Requested);

return false;
}

Expand Down
11 changes: 9 additions & 2 deletions clang/lib/Serialization/ASTWriter.cpp
Expand Up @@ -164,8 +164,8 @@ namespace {
std::set<const FileEntry *> GetAllModuleMaps(const HeaderSearch &HS,
Module *RootModule) {
std::set<const FileEntry *> ModuleMaps{};
std::set<Module *> ProcessedModules;
SmallVector<Module *> ModulesToProcess{RootModule};
std::set<const Module *> ProcessedModules;
SmallVector<const Module *> ModulesToProcess{RootModule};

SmallVector<const FileEntry *, 16> FilesByUID;
HS.getFileMgr().GetUniqueIDMapping(FilesByUID);
Expand Down Expand Up @@ -209,6 +209,11 @@ std::set<const FileEntry *> GetAllModuleMaps(const HeaderSearch &HS,
}
ModulesToProcess.push_back(ImportedModule);
}

for (const Module *UndeclaredModule : CurrentModule->UndeclaredUses)
if (UndeclaredModule &&
ProcessedModules.find(UndeclaredModule) == ProcessedModules.end())
ModulesToProcess.push_back(UndeclaredModule);
}

return ModuleMaps;
Expand Down Expand Up @@ -2861,6 +2866,8 @@ void ASTWriter::WriteSubmodules(Module *WritingModule) {
// Might be unnecessary as use declarations are only used to build the
// module itself.

// TODO: Consider serializing undeclared uses of modules.

// Emit the link libraries.
for (const auto &LL : Mod->LinkLibraries) {
RecordData::value_type Record[] = {SUBMODULE_LINK_LIBRARY,
Expand Down
34 changes: 31 additions & 3 deletions clang/test/Modules/add-remove-irrelevant-module-map.m
Expand Up @@ -25,6 +25,34 @@

// Neither PCM file considers 'b.modulemap' an input:
//
// RUN: %clang_cc1 -module-file-info %t/cache-without-b/a.pcm | FileCheck %s
// RUN: %clang_cc1 -module-file-info %t/cache-with-b/a.pcm | FileCheck %s
// CHECK-NOT: Input file: {{.*}}/b.modulemap
// RUN: %clang_cc1 -module-file-info %t/cache-without-b/a.pcm | FileCheck %s --check-prefix=CHECK-B
// RUN: %clang_cc1 -module-file-info %t/cache-with-b/a.pcm | FileCheck %s --check-prefix=CHECK-B
// CHECK-B-NOT: Input file: {{.*}}/b.modulemap

//--- c.modulemap
module c [no_undeclared_includes] { header "c.h" }

//--- c.h
#if __has_include("d.h") // This should use 'd.modulemap' in order to determine that 'd.h'
// doesn't exist for 'c' because of its '[no_undeclared_includes]'.
#endif

//--- d.modulemap
module d { header "d.h" }

//--- d.h
// empty

//--- test-no-undeclared-includes.m
// expected-no-diagnostics
@import c;

// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t/cache -fdisable-module-hash \
// RUN: -fmodule-map-file=%t/c.modulemap -fmodule-map-file=%t/d.modulemap \
// RUN: %t/test-no-undeclared-includes.m -verify

// The PCM file considers 'd.modulemap' an input because it affects the compilation,
// although it doesn't describe the built module or its imports.
//
// RUN: %clang_cc1 -module-file-info %t/cache/c.pcm | FileCheck %s --check-prefix=CHECK-D -DDIR=%t
// CHECK-D: Input file: [[DIR]]/d.modulemap

0 comments on commit b45888e

Please sign in to comment.