aboutsummaryrefslogtreecommitdiff
path: root/clang
diff options
context:
space:
mode:
authorNaveen Seth Hanig <naveen.hanig@outlook.com>2025-06-24 16:21:19 -0700
committerGitHub <noreply@github.com>2025-06-24 16:21:19 -0700
commit52fbefb281ea59f061d5ce3725d57ae60640c71f (patch)
treec0788ed394104697ad0c7e234c604d36d1a50cdc /clang
parent87ce754e98473220d63674316459ca84bf12376f (diff)
downloadllvm-52fbefb281ea59f061d5ce3725d57ae60640c71f.zip
llvm-52fbefb281ea59f061d5ce3725d57ae60640c71f.tar.gz
llvm-52fbefb281ea59f061d5ce3725d57ae60640c71f.tar.bz2
[clang][clang-scan-deps] Add named modules to format 'experimental-full' (#145221)
Diffstat (limited to 'clang')
-rw-r--r--clang/include/clang/Tooling/DependencyScanning/DependencyScanningTool.h14
-rw-r--r--clang/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp2
-rw-r--r--clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp5
-rw-r--r--clang/test/ClangScanDeps/modules-full-named-modules.cppm351
-rw-r--r--clang/tools/clang-scan-deps/ClangScanDeps.cpp26
5 files changed, 391 insertions, 7 deletions
diff --git a/clang/include/clang/Tooling/DependencyScanning/DependencyScanningTool.h b/clang/include/clang/Tooling/DependencyScanning/DependencyScanningTool.h
index cb5d7e3..ee24e5d 100644
--- a/clang/include/clang/Tooling/DependencyScanning/DependencyScanningTool.h
+++ b/clang/include/clang/Tooling/DependencyScanning/DependencyScanningTool.h
@@ -15,6 +15,7 @@
#include "clang/Tooling/JSONCompilationDatabase.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/MapVector.h"
+#include "llvm/ADT/STLExtras.h"
#include <functional>
#include <optional>
#include <string>
@@ -56,6 +57,9 @@ struct TranslationUnitDeps {
/// determined that the differences are benign for this compilation.
std::vector<ModuleID> ClangModuleDeps;
+ /// A list of the C++20 named modules this translation unit depends on.
+ std::vector<std::string> NamedModuleDeps;
+
/// The sequence of commands required to build the translation unit. Commands
/// should be executed in order.
///
@@ -188,6 +192,14 @@ public:
ContextHash = std::move(Hash);
}
+ void handleProvidedAndRequiredStdCXXModules(
+ std::optional<P1689ModuleInfo> Provided,
+ std::vector<P1689ModuleInfo> Requires) override {
+ ModuleName = Provided ? Provided->ModuleName : "";
+ llvm::transform(Requires, std::back_inserter(NamedModuleDeps),
+ [](const auto &Module) { return Module.ModuleName; });
+ }
+
TranslationUnitDeps takeTranslationUnitDeps();
ModuleDepsGraph takeModuleGraphDeps();
@@ -195,6 +207,8 @@ private:
std::vector<std::string> Dependencies;
std::vector<PrebuiltModuleDep> PrebuiltModuleDeps;
llvm::MapVector<ModuleID, ModuleDeps> ClangModuleDeps;
+ std::string ModuleName;
+ std::vector<std::string> NamedModuleDeps;
std::vector<ModuleID> DirectModuleDeps;
std::vector<Command> Commands;
std::string ContextHash;
diff --git a/clang/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp b/clang/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp
index b015e79..515211d 100644
--- a/clang/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp
+++ b/clang/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp
@@ -171,6 +171,8 @@ TranslationUnitDeps FullDependencyConsumer::takeTranslationUnitDeps() {
TranslationUnitDeps TU;
TU.ID.ContextHash = std::move(ContextHash);
+ TU.ID.ModuleName = std::move(ModuleName);
+ TU.NamedModuleDeps = std::move(NamedModuleDeps);
TU.FileDeps = std::move(Dependencies);
TU.PrebuiltModuleDeps = std::move(PrebuiltModuleDeps);
TU.Commands = std::move(Commands);
diff --git a/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp b/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp
index b149516..fa86d71 100644
--- a/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp
+++ b/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp
@@ -714,9 +714,8 @@ void ModuleDepCollectorPP::EndOfMainFile() {
MDC.Consumer.handleDependencyOutputOpts(*MDC.Opts);
- if (MDC.Service.getFormat() == ScanningOutputFormat::P1689)
- MDC.Consumer.handleProvidedAndRequiredStdCXXModules(
- MDC.ProvidedStdCXXModule, MDC.RequiredStdCXXModules);
+ MDC.Consumer.handleProvidedAndRequiredStdCXXModules(
+ MDC.ProvidedStdCXXModule, MDC.RequiredStdCXXModules);
for (auto &&I : MDC.ModularDeps)
MDC.Consumer.handleModuleDependency(*I.second);
diff --git a/clang/test/ClangScanDeps/modules-full-named-modules.cppm b/clang/test/ClangScanDeps/modules-full-named-modules.cppm
new file mode 100644
index 0000000..5967a87
--- /dev/null
+++ b/clang/test/ClangScanDeps/modules-full-named-modules.cppm
@@ -0,0 +1,351 @@
+// This checks that clang-scan-deps properly outputs named module dependencies
+// when using the the scanning output format 'experimental-full'.
+//
+// See PR #72304.
+// UNSUPPORTED: target={{.*}}-aix{{.*}}
+//
+// RUN: rm -fr %t
+// RUN: mkdir -p %t
+// RUN: split-file %s %t
+//
+// Check the separated dependency format.
+// RUN: sed "s|DIR|%/t|g" %t/compile_commands.json.in > %t/compile_commands.json
+// RUN: clang-scan-deps -format=experimental-full \
+// RUN: -- %clang++ -std=c++20 -c -fprebuilt-module-path=%t %t/M.cppm -o %t/M.o \
+// RUN: | sed 's:\\\\\?:/:g' \
+// RUN: | FileCheck %t/M.cppm -DPREFIX=%/t
+// RUN: clang-scan-deps -format=experimental-full \
+// RUN: -- %clang++ -std=c++20 -c -fprebuilt-module-path=%t %t/Impl.cpp -o %t/Impl.o \
+// RUN: | sed 's:\\\\\?:/:g' \
+// RUN: | FileCheck %t/Impl.cpp -DPREFIX=%/t
+// RUN: clang-scan-deps -format=experimental-full \
+// RUN: -- %clang++ -std=c++20 -c -fprebuilt-module-path=%t %t/impl_part.cppm -o %t/impl_part.o \
+// RUN: | sed 's:\\\\\?:/:g' \
+// RUN: | FileCheck %t/impl_part.cppm -DPREFIX=%/t
+// RUN: clang-scan-deps -format=experimental-full \
+// RUN: -- %clang++ -std=c++20 -c -fprebuilt-module-path=%t %t/interface_part.cppm -o %t/interface_part.o \
+// RUN: | sed 's:\\\\\?:/:g' \
+// RUN: | FileCheck %t/interface_part.cppm -DPREFIX=%/t
+// RUN: clang-scan-deps -format=experimental-full \
+// RUN: -- %clang++ -std=c++20 -c -fprebuilt-module-path=%t %t/User.cpp -o %t/User.o \
+// RUN: | sed 's:\\\\\?:/:g' \
+// RUN: | FileCheck %t/User.cpp -DPREFIX=%/t
+//
+// Check the combined dependency format.
+// RUN: clang-scan-deps -compilation-database %t/compile_commands.json -format=experimental-full \
+// RUN: | sed 's:\\\\\?:/:g' \
+// RUN: | FileCheck %t/Checks.cpp -DPREFIX=%/t
+// RUN: clang-scan-deps --mode=preprocess-dependency-directives -compilation-database %t/compile_commands.json -format=experimental-full \
+// RUN: | sed 's:\\\\\?:/:g' \
+// RUN: | FileCheck %t/Checks.cpp -DPREFIX=%/t
+
+//--- compile_commands.json.in
+[
+{
+ "directory": "DIR",
+ "command": "clang++ -std=c++20 DIR/M.cppm -c -o DIR/M.o -MT DIR/M.o.ddi -MD -MF DIR/P1689.dep",
+ "file": "DIR/M.cppm",
+ "output": "DIR/M.o"
+},
+{
+ "directory": "DIR",
+ "command": "clang++ -std=c++20 DIR/Impl.cpp -c -o DIR/Impl.o -MT DIR/Impl.o.ddi -MD -MF DIR/P1689.dep",
+ "file": "DIR/Impl.cpp",
+ "output": "DIR/Impl.o"
+},
+{
+ "directory": "DIR",
+ "command": "clang++ -std=c++20 DIR/impl_part.cppm -c -o DIR/impl_part.o -MT DIR/impl_part.o.ddi -MD -MF DIR/P1689.dep",
+ "file": "DIR/impl_part.cppm",
+ "output": "DIR/impl_part.o"
+},
+{
+ "directory": "DIR",
+ "command": "clang++ -std=c++20 DIR/interface_part.cppm -c -o DIR/interface_part.o -MT DIR/interface_part.o.ddi -MD -MF DIR/P1689.dep",
+ "file": "DIR/interface_part.cppm",
+ "output": "DIR/interface_part.o"
+},
+{
+ "directory": "DIR",
+ "command": "clang++ -std=c++20 DIR/User.cpp -c -o DIR/User.o -MT DIR/User.o.ddi -MD -MF DIR/P1689.dep",
+ "file": "DIR/User.cpp",
+ "output": "DIR/User.o"
+}
+]
+
+//--- M.cppm
+export module M;
+export import :interface_part;
+import :impl_part;
+export void Hello();
+
+// CHECK: {
+// CHECK: "modules": []
+// CHECK: "translation-units": [
+// CHECK-NEXT: {
+// CHECK: "commands": [
+// CHECK-NEXT: {
+// CHECK: "named-module": "M"
+// CHECK-NEXT: "named-module-deps": [
+// CHECK-NEXT: "M:interface_part",
+// CHECK-NEXT: "M:impl_part"
+// CHECK-NEXT: ]
+// CHECK: "command-line": [
+// CHECK: "-o",
+// CHECK-NEXT: "{{.*}}/M-{{.*}}.pcm"
+// CHECK: ]
+// CHECK: "input-file": "[[PREFIX]]/M.cppm"
+// CHECK: },
+// CHECK-NEXT: {
+// CHECK: "command-line": [
+// CHECK: "-o",
+// CHECK-NEXT: "[[PREFIX]]/M.o"
+// CHECK: ]
+// CHECK: "input-file": "[[PREFIX]]/M.cppm"
+// CHECK: }
+// CHECK: ]
+// CHECK: }
+// CHECK: ]
+// CHECK: }
+
+//--- Impl.cpp
+module;
+#include "header.mock"
+module M;
+void Hello() {
+ std::cout << "Hello ";
+}
+
+// CHECK: {
+// CHECK: "modules": []
+// CHECK: "translation-units": [
+// CHECK-NEXT: {
+// CHECK: "commands": [
+// CHECK-NEXT: {
+// CHECK-NOT: "named-module":
+// CHECK: "named-module-deps": [
+// CHECK-NEXT: "M"
+// CHECK-NEXT: ]
+// CHECK: "command-line": [
+// CHECK: "-o",
+// CHECK-NEXT: "[[PREFIX]]/Impl.o"
+// CHECK: ]
+// CHECK: "input-file": "[[PREFIX]]/Impl.cpp"
+// CHECK: }
+// CHECK: ]
+// CHECK: }
+// CHECK: ]
+// CHECK: }
+
+//--- impl_part.cppm
+module;
+#include "header.mock"
+module M:impl_part;
+import :interface_part;
+
+std::string W = "World.";
+void World() {
+ std::cout << W << std::endl;
+}
+
+// CHECK: {
+// CHECK: "modules": [],
+// CHECK: "translation-units": [
+// CHECK-NEXT: {
+// CHECK: "commands": [
+// CHECK-NEXT: {
+// CHECK: "named-module": "M:impl_part"
+// CHECK-NEXT: "named-module-deps": [
+// CHECK-NEXT: "M:interface_part"
+// CHECK-NEXT: ]
+// CHECK: "command-line": [
+// CHECK: "-o",
+// CHECK-NEXT: "{{.*}}/impl_part-{{.*}}.pcm",
+// CHECK: ]
+// CHECK: "input-file": "[[PREFIX]]/impl_part.cppm"
+// CHECK: },
+// CHECK-NEXT: {
+// CHECK: "named-module": "M:impl_part"
+// CHECK-NEXT: "named-module-deps": [
+// CHECK-NEXT: "M:interface_part"
+// CHECK-NEXT: ]
+// CHECK: "command-line": [
+// CHECK: "-o",
+// CHECK-NEXT: "[[PREFIX]]/impl_part.o",
+// CHECK: ]
+// CHECK: "input-file": "[[PREFIX]]/impl_part.cppm"
+// CHECK: }
+// CHECK: ]
+// CHECK: }
+// CHECK: ]
+// CHECK: }
+
+//--- interface_part.cppm
+export module M:interface_part;
+export void World();
+
+// CHECK: {
+// CHECK: "modules": []
+// CHECK: "translation-units": [
+// CHECK-NEXT: {
+// CHECK: "commands": [
+// CHECK-NEXT: {
+// CHECK: "named-module": "M:interface_part"
+// CHECK-NOT: "named-module-deps": []
+// CHECK: "command-line": [
+// CHECK: "-o",
+// CHECK-NEXT: "{{.*}}/interface_part-{{.*}}.pcm",
+// CHECK: ]
+// CHECK: "input-file": "[[PREFIX]]/interface_part.cppm"
+// CHECK: },
+// CHECK-NEXT: {
+// CHECK: "named-module": "M:interface_part"
+// CHECK-NOT: "named-module-deps": []
+// CHECK: "command-line": [
+// CHECK: "-o",
+// CHECK-NEXT: "[[PREFIX]]/interface_part.o",
+// CHECK: ]
+// CHECK: "input-file": "[[PREFIX]]/interface_part.cppm"
+// CHECK: }
+// CHECK: ]
+// CHECK: }
+// CHECK: ]
+// CHECK: }
+
+//--- User.cpp
+import M;
+import third_party_module;
+int main() {
+ Hello();
+ World();
+ return 0;
+}
+
+// CHECK: {
+// CHECK-NEXT: "modules": []
+// CHECK-NEXT: "translation-units": [
+// CHECK-NEXT: {
+// CHECK-NEXT: "commands": [
+// CHECK-NEXT: {
+// CHECK-NOT: "named-module":
+// CHECK: "named-module-deps": [
+// CHECK-NEXT: "M"
+// CHECK-NEXT: "third_party_module"
+// CHECK-NEXT: ]
+// CHECK: "command-line": [
+// CHECK: "-o",
+// CHECK-NEXT: "[[PREFIX]]/User.o",
+// CHECK: ]
+// CHECK: "input-file": "[[PREFIX]]/User.cpp
+// CHECK: }
+// CHECK: ]
+// CHECK-NEXT: }
+// CHECK-NEXT: ]
+// CHECK: }
+
+//--- header.mock
+
+//--- Checks.cpp
+// CHECK: {
+// CHECK: "modules": []
+// CHECK: "translation-units": [
+// CHECK-NEXT: {
+// CHECK: "commands": [
+// CHECK-NEXT: {
+// CHECK: "named-module": "M"
+// CHECK-NEXT: "named-module-deps": [
+// CHECK-NEXT: "M:interface_part",
+// CHECK-NEXT: "M:impl_part"
+// CHECK-NEXT: ]
+// CHECK: "command-line": [
+// CHECK: "-o",
+// CHECK-NEXT: "{{.*}}/M-{{.*}}.pcm"
+// CHECK: ]
+// CHECK: "input-file": "[[PREFIX]]/M.cppm"
+// CHECK: },
+// CHECK-NEXT: {
+// CHECK: "command-line": [
+// CHECK: "-o",
+// CHECK-NEXT: "[[PREFIX]]/M.o"
+// CHECK: ]
+// CHECK: "input-file": "[[PREFIX]]/M.cppm"
+// CHECK: },
+// CHECK: {
+// CHECK-NOT: "named-module":
+// CHECK: "named-module-deps": [
+// CHECK-NEXT: "M"
+// CHECK-NEXT: ]
+// CHECK: "command-line": [
+// CHECK: "-o",
+// CHECK-NEXT: "[[PREFIX]]/Impl.o"
+// CHECK: ]
+// CHECK: "input-file": "[[PREFIX]]/Impl.cpp"
+// CHECK: }
+// CHECK: ]
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK: "commands": [
+// CHECK-NEXT: {
+// CHECK: "named-module": "M:impl_part"
+// CHECK-NEXT: "named-module-deps": [
+// CHECK-NEXT: "M:interface_part"
+// CHECK-NEXT: ]
+// CHECK: "command-line": [
+// CHECK: "-o",
+// CHECK-NEXT: "{{.*}}/impl_part-{{.*}}.pcm",
+// CHECK: ]
+// CHECK: "input-file": "[[PREFIX]]/impl_part.cppm"
+// CHECK: },
+// CHECK-NEXT: {
+// CHECK: "named-module": "M:impl_part"
+// CHECK-NEXT: "named-module-deps": [
+// CHECK-NEXT: "M:interface_part"
+// CHECK-NEXT: ]
+// CHECK: "command-line": [
+// CHECK: "-o",
+// CHECK-NEXT: "[[PREFIX]]/impl_part.o",
+// CHECK: ]
+// CHECK: "input-file": "[[PREFIX]]/impl_part.cppm"
+// CHECK: }
+// CHECK: ]
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK: "commands": [
+// CHECK-NEXT: {
+// CHECK: "named-module": "M:interface_part"
+// CHECK-NOT: "named-module-deps": []
+// CHECK: "command-line": [
+// CHECK: "-o",
+// CHECK-NEXT: "{{.*}}/interface_part-{{.*}}.pcm",
+// CHECK: ]
+// CHECK: "input-file": "[[PREFIX]]/interface_part.cppm"
+// CHECK: },
+// CHECK-NEXT: {
+// CHECK: "named-module": "M:interface_part"
+// CHECK-NOT: "named-module-deps": []
+// CHECK: "command-line": [
+// CHECK: "-o",
+// CHECK-NEXT: "[[PREFIX]]/interface_part.o",
+// CHECK: ]
+// CHECK: "input-file": "[[PREFIX]]/interface_part.cppm"
+// CHECK: }
+// CHECK: ]
+// CHECK-NEXT: },
+// CHECK-NEXT: {
+// CHECK: "commands": [
+// CHECK-NEXT: {
+// CHECK-NOT: "named-module":
+// CHECK: "named-module-deps": [
+// CHECK-NEXT: "M"
+// CHECK-NEXT: "third_party_module"
+// CHECK-NEXT: ]
+// CHECK: "command-line": [
+// CHECK: "-o",
+// CHECK-NEXT: "[[PREFIX]]/User.o",
+// CHECK: ]
+// CHECK: "input-file": "[[PREFIX]]/User.cpp
+// CHECK: }
+// CHECK: ]
+// CHECK: }
+// CHECK: ]
+// CHECK: }
diff --git a/clang/tools/clang-scan-deps/ClangScanDeps.cpp b/clang/tools/clang-scan-deps/ClangScanDeps.cpp
index 921ba7a..8b590bd 100644
--- a/clang/tools/clang-scan-deps/ClangScanDeps.cpp
+++ b/clang/tools/clang-scan-deps/ClangScanDeps.cpp
@@ -393,7 +393,9 @@ public:
ID.FileName = std::string(Input);
ID.ContextHash = std::move(TUDeps.ID.ContextHash);
ID.FileDeps = std::move(TUDeps.FileDeps);
- ID.ModuleDeps = std::move(TUDeps.ClangModuleDeps);
+ ID.NamedModule = std::move(TUDeps.ID.ModuleName);
+ ID.NamedModuleDeps = std::move(TUDeps.NamedModuleDeps);
+ ID.ClangModuleDeps = std::move(TUDeps.ClangModuleDeps);
ID.DriverCommandLine = std::move(TUDeps.DriverCommandLine);
ID.Commands = std::move(TUDeps.Commands);
@@ -508,8 +510,15 @@ public:
JOS.object([&] {
JOS.attribute("clang-context-hash",
StringRef(I.ContextHash));
+ if (!I.NamedModule.empty())
+ JOS.attribute("named-module", (I.NamedModule));
+ if (!I.NamedModuleDeps.empty())
+ JOS.attributeArray("named-module-deps", [&] {
+ for (const auto &Dep : I.NamedModuleDeps)
+ JOS.value(Dep);
+ });
JOS.attributeArray("clang-module-deps",
- toJSONSorted(JOS, I.ModuleDeps));
+ toJSONSorted(JOS, I.ClangModuleDeps));
JOS.attributeArray("command-line",
toJSONStrings(JOS, Cmd.Arguments));
JOS.attribute("executable", StringRef(Cmd.Executable));
@@ -521,8 +530,15 @@ public:
} else {
JOS.object([&] {
JOS.attribute("clang-context-hash", StringRef(I.ContextHash));
+ if (!I.NamedModule.empty())
+ JOS.attribute("named-module", (I.NamedModule));
+ if (!I.NamedModuleDeps.empty())
+ JOS.attributeArray("named-module-deps", [&] {
+ for (const auto &Dep : I.NamedModuleDeps)
+ JOS.value(Dep);
+ });
JOS.attributeArray("clang-module-deps",
- toJSONSorted(JOS, I.ModuleDeps));
+ toJSONSorted(JOS, I.ClangModuleDeps));
JOS.attributeArray("command-line",
toJSONStrings(JOS, I.DriverCommandLine));
JOS.attribute("executable", "clang");
@@ -577,7 +593,9 @@ private:
std::string FileName;
std::string ContextHash;
std::vector<std::string> FileDeps;
- std::vector<ModuleID> ModuleDeps;
+ std::string NamedModule;
+ std::vector<std::string> NamedModuleDeps;
+ std::vector<ModuleID> ClangModuleDeps;
std::vector<std::string> DriverCommandLine;
std::vector<Command> Commands;
};