[clang] 002bfdd - [clang][modules] Track affecting modules
Jan Svoboda via cfe-commits
cfe-commits at lists.llvm.org
Wed Aug 24 11:10:00 PDT 2022
Author: Jan Svoboda
Date: 2022-08-24T11:09:50-07:00
New Revision: 002bfdd6b119e3543415971fbb219768fd96f86f
URL: https://github.com/llvm/llvm-project/commit/002bfdd6b119e3543415971fbb219768fd96f86f
DIFF: https://github.com/llvm/llvm-project/commit/002bfdd6b119e3543415971fbb219768fd96f86f.diff
LOG: [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
Added:
clang/test/ClangScanDeps/modules-incomplete-umbrella.c
Modified:
clang/include/clang/Basic/Module.h
clang/include/clang/Lex/ModuleLoader.h
clang/include/clang/Lex/Preprocessor.h
clang/include/clang/Serialization/ASTBitCodes.h
clang/include/clang/Serialization/ASTReader.h
clang/include/clang/Tooling/DependencyScanning/ModuleDepCollector.h
clang/lib/Frontend/CompilerInstance.cpp
clang/lib/Lex/HeaderSearch.cpp
clang/lib/Lex/PPDirectives.cpp
clang/lib/Serialization/ASTReader.cpp
clang/lib/Serialization/ASTWriter.cpp
clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp
Removed:
################################################################################
diff --git a/clang/include/clang/Basic/Module.h b/clang/include/clang/Basic/Module.h
index 8ef1c5991c56e..a2309f5d7faeb 100644
--- a/clang/include/clang/Basic/Module.h
+++ b/clang/include/clang/Basic/Module.h
@@ -345,6 +345,10 @@ class Module {
/// module depends.
llvm::SmallSetVector<Module *, 2> Imports;
+ /// The set of top-level modules that affected the compilation of this module,
+ /// but were not imported.
+ llvm::SmallSetVector<Module *, 2> AffectingModules;
+
/// Describes an exported module.
///
/// The pointer is the module being re-exported, while the bit will be true
diff --git a/clang/include/clang/Lex/ModuleLoader.h b/clang/include/clang/Lex/ModuleLoader.h
index bf044e0e5f506..f880a9091a2ed 100644
--- a/clang/include/clang/Lex/ModuleLoader.h
+++ b/clang/include/clang/Lex/ModuleLoader.h
@@ -51,6 +51,11 @@ class ModuleLoadResult {
ModuleLoadResult() = default;
ModuleLoadResult(Module *M) : Storage(M, Normal) {}
ModuleLoadResult(LoadResultKind Kind) : Storage(nullptr, Kind) {}
+ ModuleLoadResult(Module *M, LoadResultKind Kind) : Storage(M, Kind) {}
+
+ operator bool() const {
+ return Storage.getInt() == Normal && Storage.getPointer();
+ }
operator Module *() const { return Storage.getPointer(); }
diff --git a/clang/include/clang/Lex/Preprocessor.h b/clang/include/clang/Lex/Preprocessor.h
index 6e2517632717f..5f54a44e604e2 100644
--- a/clang/include/clang/Lex/Preprocessor.h
+++ b/clang/include/clang/Lex/Preprocessor.h
@@ -860,6 +860,10 @@ class Preprocessor {
/// The files that have been included.
IncludedFilesSet IncludedFiles;
+ /// The set of top-level modules that affected preprocessing, but were not
+ /// imported.
+ llvm::SmallSetVector<Module *, 2> AffectingModules;
+
/// The set of known macros exported from modules.
llvm::FoldingSet<ModuleMacro> ModuleMacros;
@@ -1331,6 +1335,12 @@ class Preprocessor {
/// \}
+ /// Get the set of top-level modules that affected preprocessing, but were not
+ /// imported.
+ const llvm::SmallSetVector<Module *, 2> &getAffectingModules() const {
+ return AffectingModules;
+ }
+
/// Mark the file as included.
/// Returns true if this is the first time the file was included.
bool markIncluded(const FileEntry *File) {
diff --git a/clang/include/clang/Serialization/ASTBitCodes.h b/clang/include/clang/Serialization/ASTBitCodes.h
index 297af86d0203d..8b0d2c0de1fe5 100644
--- a/clang/include/clang/Serialization/ASTBitCodes.h
+++ b/clang/include/clang/Serialization/ASTBitCodes.h
@@ -829,6 +829,9 @@ enum SubmoduleRecordTypes {
/// Specifies the name of the module that will eventually
/// re-export the entities in this module.
SUBMODULE_EXPORT_AS = 17,
+
+ /// Specifies affecting modules that were not imported.
+ SUBMODULE_AFFECTING_MODULES = 18,
};
/// Record types used within a comments block.
diff --git a/clang/include/clang/Serialization/ASTReader.h b/clang/include/clang/Serialization/ASTReader.h
index 25b14f4dfa422..19a18a2ef4030 100644
--- a/clang/include/clang/Serialization/ASTReader.h
+++ b/clang/include/clang/Serialization/ASTReader.h
@@ -689,7 +689,7 @@ class ASTReader
Module *Mod;
/// The kind of module reference.
- enum { Import, Export, Conflict } Kind;
+ enum { Import, Export, Conflict, Affecting } Kind;
/// The local ID of the module that is being exported.
unsigned ID;
diff --git a/clang/include/clang/Tooling/DependencyScanning/ModuleDepCollector.h b/clang/include/clang/Tooling/DependencyScanning/ModuleDepCollector.h
index 20f4715982b40..a82355e60ee83 100644
--- a/clang/include/clang/Tooling/DependencyScanning/ModuleDepCollector.h
+++ b/clang/include/clang/Tooling/DependencyScanning/ModuleDepCollector.h
@@ -176,6 +176,13 @@ class ModuleDepCollectorPP final : public PPCallbacks {
llvm::DenseSet<const Module *> &AddedModules);
void addModuleDep(const Module *M, ModuleDeps &MD,
llvm::DenseSet<const Module *> &AddedModules);
+
+ /// Traverses the affecting modules and updates \c MD with references to the
+ /// parent \c ModuleDepCollector info.
+ void addAllAffectingModules(const Module *M, ModuleDeps &MD,
+ llvm::DenseSet<const Module *> &AddedModules);
+ void addAffectingModule(const Module *M, ModuleDeps &MD,
+ llvm::DenseSet<const Module *> &AddedModules);
};
/// Collects modular and non-modular dependencies of the main file by attaching
diff --git a/clang/lib/Frontend/CompilerInstance.cpp b/clang/lib/Frontend/CompilerInstance.cpp
index 03b5d048c4b8d..6d1e378bf4dc1 100644
--- a/clang/lib/Frontend/CompilerInstance.cpp
+++ b/clang/lib/Frontend/CompilerInstance.cpp
@@ -2099,7 +2099,7 @@ CompilerInstance::loadModule(SourceLocation ImportLoc,
<< Module->getFullModuleName()
<< SourceRange(Path.front().second, Path.back().second);
- return ModuleLoadResult::MissingExpected;
+ return ModuleLoadResult(Module, ModuleLoadResult::MissingExpected);
}
// Check whether this module is available.
diff --git a/clang/lib/Lex/HeaderSearch.cpp b/clang/lib/Lex/HeaderSearch.cpp
index 219c62663ebd0..20696b1377d4d 100644
--- a/clang/lib/Lex/HeaderSearch.cpp
+++ b/clang/lib/Lex/HeaderSearch.cpp
@@ -1563,6 +1563,8 @@ static bool suggestModule(HeaderSearch &HS, const FileEntry *File,
*SuggestedModule = ModuleMap::KnownHeader();
return true;
}
+ // TODO: Add this module (or just its module map file) into something like
+ // `RequestingModule->AffectingModules`.
return false;
}
}
diff --git a/clang/lib/Lex/PPDirectives.cpp b/clang/lib/Lex/PPDirectives.cpp
index cc122cdcac927..716f866e139ab 100644
--- a/clang/lib/Lex/PPDirectives.cpp
+++ b/clang/lib/Lex/PPDirectives.cpp
@@ -2281,6 +2281,13 @@ Preprocessor::ImportAction Preprocessor::HandleHeaderIncludeOrImport(
if (Imported) {
Action = Import;
} else if (Imported.isMissingExpected()) {
+ Module *M = static_cast<Module *>(Imported)->getTopLevelModule();
+ if (!BuildingSubmoduleStack.empty()) {
+ if (Imported != BuildingSubmoduleStack.back().M)
+ BuildingSubmoduleStack.back().M->AffectingModules.insert(M);
+ } else {
+ AffectingModules.insert(M);
+ }
// We failed to find a submodule that we assumed would exist (because it
// was in the directory of an umbrella header, for instance), but no
// actual module containing it exists (because the umbrella header is
diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp
index efd05a7764e09..e7dea40a16100 100644
--- a/clang/lib/Serialization/ASTReader.cpp
+++ b/clang/lib/Serialization/ASTReader.cpp
@@ -4376,6 +4376,11 @@ ASTReader::ASTReadResult ASTReader::ReadAST(StringRef FileName,
Unresolved.Mod->Imports.insert(ResolvedMod);
continue;
+ case UnresolvedModuleRef::Affecting:
+ if (ResolvedMod)
+ Unresolved.Mod->AffectingModules.insert(ResolvedMod);
+ continue;
+
case UnresolvedModuleRef::Export:
if (ResolvedMod || Unresolved.IsWildcard)
Unresolved.Mod->Exports.push_back(
@@ -5674,6 +5679,18 @@ llvm::Error ASTReader::ReadSubmoduleBlock(ModuleFile &F,
}
break;
+ case SUBMODULE_AFFECTING_MODULES:
+ for (unsigned Idx = 0; Idx != Record.size(); ++Idx) {
+ UnresolvedModuleRef Unresolved;
+ Unresolved.File = &F;
+ Unresolved.Mod = CurrentModule;
+ Unresolved.ID = Record[Idx];
+ Unresolved.Kind = UnresolvedModuleRef::Affecting;
+ Unresolved.IsWildcard = false;
+ UnresolvedModuleRefs.push_back(Unresolved);
+ }
+ break;
+
case SUBMODULE_EXPORTS:
for (unsigned Idx = 0; Idx + 1 < Record.size(); Idx += 2) {
UnresolvedModuleRef Unresolved;
diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp
index b64770da14e40..1e835a4c68531 100644
--- a/clang/lib/Serialization/ASTWriter.cpp
+++ b/clang/lib/Serialization/ASTWriter.cpp
@@ -883,6 +883,7 @@ void ASTWriter::WriteBlockInfoBlock() {
RECORD(SUBMODULE_TOPHEADER);
RECORD(SUBMODULE_UMBRELLA_DIR);
RECORD(SUBMODULE_IMPORTS);
+ RECORD(SUBMODULE_AFFECTING_MODULES);
RECORD(SUBMODULE_EXPORTS);
RECORD(SUBMODULE_REQUIRES);
RECORD(SUBMODULE_EXCLUDED_HEADER);
@@ -2865,6 +2866,14 @@ void ASTWriter::WriteSubmodules(Module *WritingModule) {
Stream.EmitRecord(SUBMODULE_IMPORTS, Record);
}
+ // Emit the modules affecting compilation that were not imported.
+ if (!Mod->AffectingModules.empty()) {
+ RecordData Record;
+ for (auto *I : Mod->AffectingModules)
+ Record.push_back(getSubmoduleID(I));
+ Stream.EmitRecord(SUBMODULE_AFFECTING_MODULES, Record);
+ }
+
// Emit the exports.
if (!Mod->Exports.empty()) {
RecordData Record;
diff --git a/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp b/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp
index f2de01896ca76..ad2d9939896e2 100644
--- a/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp
+++ b/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp
@@ -278,6 +278,11 @@ void ModuleDepCollectorPP::EndOfMainFile() {
if (!MDC.ScanInstance.getPreprocessorOpts().ImplicitPCHInclude.empty())
MDC.addFileDep(MDC.ScanInstance.getPreprocessorOpts().ImplicitPCHInclude);
+ for (const Module *M :
+ MDC.ScanInstance.getPreprocessor().getAffectingModules())
+ if (!MDC.isPrebuiltModule(M))
+ DirectModularDeps.insert(M);
+
for (const Module *M : DirectModularDeps) {
// A top-level module might not be actually imported as a module when
// -fmodule-name is used to compile a translation unit that imports this
@@ -389,6 +394,8 @@ ModuleID ModuleDepCollectorPP::handleTopLevelModule(const Module *M) {
addAllSubmodulePrebuiltDeps(M, MD, SeenModules);
llvm::DenseSet<const Module *> AddedModules;
addAllSubmoduleDeps(M, MD, AddedModules);
+ llvm::DenseSet<const Module *> ProcessedModules;
+ addAllAffectingModules(M, MD, ProcessedModules);
MD.BuildInvocation = MDC.makeInvocationForModuleBuildWithoutOutputs(
MD, [&](CompilerInvocation &BuildInvocation) {
@@ -461,6 +468,30 @@ void ModuleDepCollectorPP::addModuleDep(
}
}
+void ModuleDepCollectorPP::addAllAffectingModules(
+ const Module *M, ModuleDeps &MD,
+ llvm::DenseSet<const Module *> &AddedModules) {
+ addAffectingModule(M, MD, AddedModules);
+
+ for (const Module *SubM : M->submodules())
+ addAllAffectingModules(SubM, MD, AddedModules);
+}
+
+void ModuleDepCollectorPP::addAffectingModule(
+ const Module *M, ModuleDeps &MD,
+ llvm::DenseSet<const Module *> &AddedModules) {
+ for (const Module *Affecting : M->AffectingModules) {
+ assert(Affecting == Affecting->getTopLevelModule() &&
+ "Not quite import not top-level module");
+ if (Affecting != M->getTopLevelModule() &&
+ !MDC.isPrebuiltModule(Affecting)) {
+ ModuleID ImportID = handleTopLevelModule(Affecting);
+ if (AddedModules.insert(Affecting).second)
+ MD.ClangModuleDeps.push_back(ImportID);
+ }
+ }
+}
+
ModuleDepCollector::ModuleDepCollector(
std::unique_ptr<DependencyOutputOptions> Opts,
CompilerInstance &ScanInstance, DependencyConsumer &C,
diff --git a/clang/test/ClangScanDeps/modules-incomplete-umbrella.c b/clang/test/ClangScanDeps/modules-incomplete-umbrella.c
new file mode 100644
index 0000000000000..973dc12192017
--- /dev/null
+++ b/clang/test/ClangScanDeps/modules-incomplete-umbrella.c
@@ -0,0 +1,202 @@
+// This test checks that modules loaded during compilation (but not imported)
+// are still reported as dependencies.
+
+// RUN: rm -rf %t && mkdir %t
+// RUN: split-file %s %t
+
+//--- frameworks/FW.framework/Modules/module.modulemap
+framework module FW {
+ umbrella header "FW.h"
+ module * { export * }
+}
+//--- frameworks/FW.framework/Headers/FW.h
+//--- frameworks/FW.framework/Modules/module.private.modulemap
+framework module FW_Private {
+ umbrella header "FW_Private.h"
+ module * { export * }
+}
+//--- frameworks/FW.framework/PrivateHeaders/FW_Private.h
+#include "One.h"
+//--- frameworks/FW.framework/PrivateHeaders/One.h
+//--- frameworks/FW.framework/PrivateHeaders/Two.h
+
+// Let's check we report the non-imported modular dependencies for a translation unit.
+
+//--- from_tu.cdb.json.template
+[{
+ "file": "DIR/from_tu.m",
+ "directory": "DIR",
+ "command": "clang -fmodules -fmodules-cache-path=DIR/cache -iframework DIR/frameworks -c DIR/from_tu.m -o DIR/from_tu.o"
+}]
+//--- from_tu.m
+#include "FW/FW.h"
+#include "FW/Two.h"
+
+// RUN: sed -e "s|DIR|%/t|g" %t/from_tu.cdb.json.template > %t/from_tu.cdb.json
+// RUN: clang-scan-deps -compilation-database %t/from_tu.cdb.json -format experimental-full > %t/from_tu_result.json
+// RUN: cat %t/from_tu_result.json | sed 's:\\\\\?:/:g' | FileCheck %s -DPREFIX=%/t --check-prefixes=CHECK_TU
+// CHECK_TU: {
+// CHECK_TU-NEXT: "modules": [
+// CHECK_TU-NEXT: {
+// CHECK_TU-NEXT: "clang-module-deps": [],
+// CHECK_TU-NEXT: "clang-modulemap-file": "[[PREFIX]]/frameworks/FW.framework/Modules/module.modulemap",
+// CHECK_TU-NEXT: "command-line": [
+// CHECK_TU: ],
+// CHECK_TU-NEXT: "context-hash": "{{.*}}",
+// CHECK_TU-NEXT: "file-deps": [
+// CHECK_TU-NEXT: "[[PREFIX]]/frameworks/FW.framework/Headers/FW.h",
+// CHECK_TU-NEXT: "[[PREFIX]]/frameworks/FW.framework/Modules/module.modulemap",
+// CHECK_TU-NEXT: "[[PREFIX]]/frameworks/FW.framework/Modules/module.private.modulemap"
+// CHECK_TU-NEXT: ],
+// CHECK_TU-NEXT: "name": "FW"
+// CHECK_TU-NEXT: },
+// CHECK_TU-NEXT: {
+// CHECK_TU-NEXT: "clang-module-deps": [],
+// CHECK_TU-NEXT: "clang-modulemap-file": "[[PREFIX]]/frameworks/FW.framework/Modules/module.private.modulemap",
+// CHECK_TU-NEXT: "command-line": [
+// CHECK_TU: ],
+// CHECK_TU-NEXT: "context-hash": "{{.*}}",
+// CHECK_TU-NEXT: "file-deps": [
+// CHECK_TU-NEXT: "[[PREFIX]]/frameworks/FW.framework/Modules/module.modulemap",
+// CHECK_TU-NEXT: "[[PREFIX]]/frameworks/FW.framework/Modules/module.private.modulemap",
+// CHECK_TU-NEXT: "[[PREFIX]]/frameworks/FW.framework/PrivateHeaders/FW_Private.h",
+// CHECK_TU-NEXT: "[[PREFIX]]/frameworks/FW.framework/PrivateHeaders/One.h"
+// CHECK_TU-NEXT: ],
+// CHECK_TU-NEXT: "name": "FW_Private"
+// CHECK_TU-NEXT: }
+// CHECK_TU-NEXT: ],
+// CHECK_TU-NEXT: "translation-units": [
+// CHECK_TU-NEXT: {
+// CHECK_TU-NEXT: "clang-context-hash": "{{.*}}",
+// CHECK_TU-NEXT: "clang-module-deps": [
+// CHECK_TU-NEXT: {
+// CHECK_TU-NEXT: "context-hash": "{{.*}}",
+// CHECK_TU-NEXT: "module-name": "FW"
+// CHECK_TU-NEXT: },
+// CHECK_TU-NEXT: {
+// CHECK_TU-NEXT: "context-hash": "{{.*}}",
+// CHECK_TU-NEXT: "module-name": "FW_Private"
+// CHECK_TU-NEXT: }
+// CHECK_TU-NEXT: ],
+// CHECK_TU-NEXT: "command-line": [
+// CHECK_TU: "-fmodule-file={{.*}}/FW-{{.*}}.pcm"
+// CHECK_TU: "-fmodule-file={{.*}}/FW_Private-{{.*}}.pcm"
+// CHECK_TU: ],
+// CHECK_TU-NEXT: "file-deps": [
+// CHECK_TU-NEXT: "[[PREFIX]]/from_tu.m",
+// CHECK_TU-NEXT: "[[PREFIX]]/frameworks/FW.framework/PrivateHeaders/Two.h"
+// CHECK_TU-NEXT: ],
+// CHECK_TU-NEXT: "input-file": "[[PREFIX]]/from_tu.m"
+// CHECK_TU-NEXT: }
+// CHECK_TU-NEXT: ]
+// CHECK_TU-NEXT: }
+
+// RUN: %deps-to-rsp %t/from_tu_result.json --module-name=FW > %t/FW.cc1.rsp
+// RUN: %deps-to-rsp %t/from_tu_result.json --module-name=FW_Private > %t/FW_Private.cc1.rsp
+// RUN: %deps-to-rsp %t/from_tu_result.json --tu-index=0 > %t/tu.rsp
+// RUN: %clang @%t/FW.cc1.rsp
+// RUN: %clang @%t/FW_Private.cc1.rsp
+// RUN: %clang @%t/tu.rsp
+
+// Now let's check we report the dependencies for modules as well.
+
+//--- from_module.cdb.json.template
+[{
+ "file": "DIR/from_module.m",
+ "directory": "DIR",
+ "command": "clang -fmodules -fmodules-cache-path=DIR/cache -iframework DIR/frameworks -c DIR/from_module.m -o DIR/from_module.o"
+}]
+//--- module.modulemap
+module Mod { header "Mod.h" }
+//--- Mod.h
+#include "FW/FW.h"
+#include "FW/Two.h"
+//--- from_module.m
+#include "Mod.h"
+
+// RUN: sed -e "s|DIR|%/t|g" %t/from_module.cdb.json.template > %t/from_module.cdb.json
+// RUN: clang-scan-deps -compilation-database %t/from_module.cdb.json -format experimental-full > %t/from_module_result.json
+// RUN: cat %t/from_module_result.json | sed 's:\\\\\?:/:g' | FileCheck %s -DPREFIX=%/t --check-prefixes=CHECK_MODULE
+// CHECK_MODULE: {
+// CHECK_MODULE-NEXT: "modules": [
+// CHECK_MODULE-NEXT: {
+// CHECK_MODULE-NEXT: "clang-module-deps": [],
+// CHECK_MODULE-NEXT: "clang-modulemap-file": "[[PREFIX]]/frameworks/FW.framework/Modules/module.modulemap",
+// CHECK_MODULE-NEXT: "command-line": [
+// CHECK_MODULE: ],
+// CHECK_MODULE-NEXT: "context-hash": "{{.*}}",
+// CHECK_MODULE-NEXT: "file-deps": [
+// CHECK_MODULE-NEXT: "[[PREFIX]]/frameworks/FW.framework/Headers/FW.h",
+// CHECK_MODULE-NEXT: "[[PREFIX]]/frameworks/FW.framework/Modules/module.modulemap",
+// CHECK_MODULE-NEXT: "[[PREFIX]]/frameworks/FW.framework/Modules/module.private.modulemap"
+// CHECK_MODULE-NEXT: ],
+// CHECK_MODULE-NEXT: "name": "FW"
+// CHECK_MODULE-NEXT: },
+// CHECK_MODULE-NEXT: {
+// CHECK_MODULE-NEXT: "clang-module-deps": [],
+// CHECK_MODULE-NEXT: "clang-modulemap-file": "[[PREFIX]]/frameworks/FW.framework/Modules/module.private.modulemap",
+// CHECK_MODULE-NEXT: "command-line": [
+// CHECK_MODULE: ],
+// CHECK_MODULE-NEXT: "context-hash": "{{.*}}",
+// CHECK_MODULE-NEXT: "file-deps": [
+// CHECK_MODULE-NEXT: "[[PREFIX]]/frameworks/FW.framework/Modules/module.modulemap",
+// CHECK_MODULE-NEXT: "[[PREFIX]]/frameworks/FW.framework/Modules/module.private.modulemap",
+// CHECK_MODULE-NEXT: "[[PREFIX]]/frameworks/FW.framework/PrivateHeaders/FW_Private.h",
+// CHECK_MODULE-NEXT: "[[PREFIX]]/frameworks/FW.framework/PrivateHeaders/One.h"
+// CHECK_MODULE-NEXT: ],
+// CHECK_MODULE-NEXT: "name": "FW_Private"
+// CHECK_MODULE-NEXT: },
+// CHECK_MODULE-NEXT: {
+// CHECK_MODULE-NEXT: "clang-module-deps": [
+// CHECK_MODULE-NEXT: {
+// CHECK_MODULE-NEXT: "context-hash": "{{.*}}",
+// CHECK_MODULE-NEXT: "module-name": "FW"
+// CHECK_MODULE-NEXT: },
+// CHECK_MODULE-NEXT: {
+// CHECK_MODULE-NEXT: "context-hash": "{{.*}}",
+// CHECK_MODULE-NEXT: "module-name": "FW_Private"
+// CHECK_MODULE-NEXT: }
+// CHECK_MODULE-NEXT: ],
+// CHECK_MODULE-NEXT: "clang-modulemap-file": "[[PREFIX]]/module.modulemap",
+// CHECK_MODULE-NEXT: "command-line": [
+// CHECK_MODULE: "-fmodule-file={{.*}}/FW-{{.*}}.pcm"
+// CHECK_MODULE: "-fmodule-file={{.*}}/FW_Private-{{.*}}.pcm"
+// CHECK_MODULE: ],
+// CHECK_MODULE-NEXT: "context-hash": "{{.*}}",
+// CHECK_MODULE-NEXT: "file-deps": [
+// CHECK_MODULE-NEXT: "[[PREFIX]]/Mod.h"
+// CHECK_MODULE-NEXT: "[[PREFIX]]/frameworks/FW.framework/Modules/module.modulemap",
+// CHECK_MODULE-NEXT: "[[PREFIX]]/frameworks/FW.framework/Modules/module.private.modulemap",
+// CHECK_MODULE-NEXT: "[[PREFIX]]/frameworks/FW.framework/PrivateHeaders/Two.h",
+// CHECK_MODULE-NEXT: "[[PREFIX]]/module.modulemap"
+// CHECK_MODULE-NEXT: ],
+// CHECK_MODULE-NEXT: "name": "Mod"
+// CHECK_MODULE-NEXT: }
+// CHECK_MODULE-NEXT: ],
+// CHECK_MODULE-NEXT: "translation-units": [
+// CHECK_MODULE-NEXT: {
+// CHECK_MODULE-NEXT: "clang-context-hash": "{{.*}}",
+// CHECK_MODULE-NEXT: "clang-module-deps": [
+// CHECK_MODULE-NEXT: {
+// CHECK_MODULE-NEXT: "context-hash": "{{.*}}",
+// CHECK_MODULE-NEXT: "module-name": "Mod"
+// CHECK_MODULE-NEXT: }
+// CHECK_MODULE-NEXT: ],
+// CHECK_MODULE-NEXT: "command-line": [
+// CHECK_MODULE: ],
+// CHECK_MODULE-NEXT: "file-deps": [
+// CHECK_MODULE-NEXT: "[[PREFIX]]/from_module.m"
+// CHECK_MODULE-NEXT: ],
+// CHECK_MODULE-NEXT: "input-file": "[[PREFIX]]/from_module.m"
+// CHECK_MODULE-NEXT: }
+// CHECK_MODULE-NEXT: ]
+// CHECK_MODULE-NEXT: }
+
+// RUN: %deps-to-rsp %t/from_module_result.json --module-name=FW > %t/FW.cc1.rsp
+// RUN: %deps-to-rsp %t/from_module_result.json --module-name=FW_Private > %t/FW_Private.cc1.rsp
+// RUN: %deps-to-rsp %t/from_module_result.json --module-name=Mod > %t/Mod.cc1.rsp
+// RUN: %deps-to-rsp %t/from_module_result.json --tu-index=0 > %t/tu.rsp
+// RUN: %clang @%t/FW.cc1.rsp
+// RUN: %clang @%t/FW_Private.cc1.rsp
+// RUN: %clang @%t/Mod.cc1.rsp
+// RUN: %clang @%t/tu.rsp
More information about the cfe-commits
mailing list