Skip to content

[clang][clang-scan-deps] Add named modules to format 'experimental-full' #145221

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 7 commits into
base: main
Choose a base branch
from

Conversation

naveen-seth
Copy link
Contributor

This adds standard C++ named modules to the scanning output format 'experimental-full'.

This is motivated by an effort to provide native support for explicit module builds from the Clang driver.
The driver support for explicit module builds is planned to support combined usage of Clang modules and C++ named modules. With this, only a single scan is required to capture dependencies for both module types.

This adds standard C++ named modules to the scanning output format
'experimental-full'.

This is motivated by an effort to provide native support for explicit
module builds from the Clang driver.
The driver support for explicit module builds is planned to support
combined usage of Clang modules and C++ named modules.
With this, only a single scan is required to capture dependencies for
both module types.
@llvmbot llvmbot added the clang Clang issues not falling into any other category label Jun 22, 2025
@llvmbot
Copy link
Member

llvmbot commented Jun 22, 2025

@llvm/pr-subscribers-clang-modules

@llvm/pr-subscribers-clang

Author: Naveen Seth Hanig (naveen-seth)

Changes

This adds standard C++ named modules to the scanning output format 'experimental-full'.

This is motivated by an effort to provide native support for explicit module builds from the Clang driver.
The driver support for explicit module builds is planned to support combined usage of Clang modules and C++ named modules. With this, only a single scan is required to capture dependencies for both module types.


Patch is 42.13 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/145221.diff

29 Files Affected:

  • (modified) clang/include/clang/Tooling/DependencyScanning/DependencyScanningTool.h (+14)
  • (modified) clang/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp (+2)
  • (modified) clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp (+3-1)
  • (modified) clang/test/ClangScanDeps/diagnostics.c (+1-1)
  • (modified) clang/test/ClangScanDeps/header-search-pruning-transitive.c (+2-2)
  • (modified) clang/test/ClangScanDeps/modules-context-hash-cwd.c (+9-9)
  • (modified) clang/test/ClangScanDeps/modules-context-hash.c (+2-2)
  • (modified) clang/test/ClangScanDeps/modules-dep-args.c (+1-1)
  • (modified) clang/test/ClangScanDeps/modules-extern-submodule.c (+1-1)
  • (modified) clang/test/ClangScanDeps/modules-extern-unrelated.m (+1-1)
  • (modified) clang/test/ClangScanDeps/modules-fmodule-name-no-module-built.m (+1-1)
  • (added) clang/test/ClangScanDeps/modules-full-named-modules.cppm (+347)
  • (modified) clang/test/ClangScanDeps/modules-full-output-tu-order.c (+2-2)
  • (modified) clang/test/ClangScanDeps/modules-full.cpp (+4-4)
  • (modified) clang/test/ClangScanDeps/modules-has-include-umbrella-header.c (+1-1)
  • (modified) clang/test/ClangScanDeps/modules-implementation-private.m (+1-1)
  • (modified) clang/test/ClangScanDeps/modules-implicit-dot-private.m (+1-1)
  • (modified) clang/test/ClangScanDeps/modules-incomplete-umbrella.c (+2-2)
  • (modified) clang/test/ClangScanDeps/modules-inferred.m (+1-1)
  • (modified) clang/test/ClangScanDeps/modules-no-undeclared-includes.c (+1-1)
  • (modified) clang/test/ClangScanDeps/modules-pch-common-stale.c (+2-2)
  • (modified) clang/test/ClangScanDeps/modules-pch-common-submodule.c (+2-2)
  • (modified) clang/test/ClangScanDeps/modules-pch-common-via-submodule.c (+2-2)
  • (modified) clang/test/ClangScanDeps/modules-pch.c (+3-3)
  • (modified) clang/test/ClangScanDeps/modules-priv-fw-from-pub.m (+1-1)
  • (modified) clang/test/ClangScanDeps/multiple-commands.c (+2-2)
  • (modified) clang/test/ClangScanDeps/removed-args.c (+1-1)
  • (modified) clang/test/ClangScanDeps/tu-buffer.c (+1-1)
  • (modified) clang/tools/clang-scan-deps/ClangScanDeps.cpp (+20-4)
diff --git a/clang/include/clang/Tooling/DependencyScanning/DependencyScanningTool.h b/clang/include/clang/Tooling/DependencyScanning/DependencyScanningTool.h
index cb5d7e36d21c9..ee24e5d1543d3 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 @@ class FullDependencyConsumer : public DependencyConsumer {
     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 @@ class FullDependencyConsumer : public DependencyConsumer {
   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 b015e79f400cf..515211d47b348 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 b1495163ccc24..894b52a0a5673 100644
--- a/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp
+++ b/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp
@@ -714,7 +714,9 @@ void ModuleDepCollectorPP::EndOfMainFile() {
 
   MDC.Consumer.handleDependencyOutputOpts(*MDC.Opts);
 
-  if (MDC.Service.getFormat() == ScanningOutputFormat::P1689)
+  if (const auto Format = MDC.Service.getFormat();
+      Format == ScanningOutputFormat::P1689 ||
+      Format == ScanningOutputFormat::Full)
     MDC.Consumer.handleProvidedAndRequiredStdCXXModules(
         MDC.ProvidedStdCXXModule, MDC.RequiredStdCXXModules);
 
diff --git a/clang/test/ClangScanDeps/diagnostics.c b/clang/test/ClangScanDeps/diagnostics.c
index 8e3cf4c9f9fa6..5e99ba10b89f2 100644
--- a/clang/test/ClangScanDeps/diagnostics.c
+++ b/clang/test/ClangScanDeps/diagnostics.c
@@ -44,7 +44,7 @@ module mod { header "mod.h" }
 // CHECK-NEXT:   "translation-units": [
 // CHECK-NEXT:     {
 // CHECK:            "clang-context-hash": "[[HASH_TU:.*]],
-// CHECK-NEXT:       "clang-module-deps": [
+// CHECK:            "clang-module-deps": [
 // CHECK-NEXT:         {
 // CHECK-NEXT:           "context-hash": "[[HASH_MOD]]",
 // CHECK-NEXT:           "module-name": "mod"
diff --git a/clang/test/ClangScanDeps/header-search-pruning-transitive.c b/clang/test/ClangScanDeps/header-search-pruning-transitive.c
index 1e829bb02ddc4..09a746e9af26b 100644
--- a/clang/test/ClangScanDeps/header-search-pruning-transitive.c
+++ b/clang/test/ClangScanDeps/header-search-pruning-transitive.c
@@ -98,7 +98,7 @@ module X { header "X.h" }
 // CHECK-NEXT:   "translation-units": [
 // CHECK-NEXT:     {
 // CHECK:            "clang-context-hash": "{{.*}}",
-// CHECK-NEXT:       "clang-module-deps": [
+// CHECK:            "clang-module-deps": [
 // CHECK-NEXT:         {
 // CHECK-NEXT:           "context-hash": "[[HASH_X]]",
 // CHECK-NEXT:           "module-name": "X"
@@ -153,7 +153,7 @@ module X { header "X.h" }
 // CHECK-NEXT:   "translation-units": [
 // CHECK-NEXT:     {
 // CHECK:            "clang-context-hash": "{{.*}}",
-// CHECK-NEXT:       "clang-module-deps": [
+// CHECK:            "clang-module-deps": [
 // CHECK-NEXT:         {
 // CHECK-NEXT:           "context-hash": "{{.*}}",
 // CHECK-NEXT:           "module-name": "X"
diff --git a/clang/test/ClangScanDeps/modules-context-hash-cwd.c b/clang/test/ClangScanDeps/modules-context-hash-cwd.c
index c609a7dcbc80e..82cee2a19e2dc 100644
--- a/clang/test/ClangScanDeps/modules-context-hash-cwd.c
+++ b/clang/test/ClangScanDeps/modules-context-hash-cwd.c
@@ -75,7 +75,7 @@ module mod {
 // CHECK:     {
 // CHECK-NEXT:  "modules": [
 // CHECK-NEXT:   {
-// CHECK-NEXT:     "clang-module-deps": [],
+// CHECK:          "clang-module-deps": [],
 // CHECK:          "context-hash": "[[HASH:.*]]",
 // CHECK:        }
 // CHECK:       "translation-units": [
@@ -83,7 +83,7 @@ module mod {
 // CHECK:          "commands": [
 // CHECK:          {
 // CHECK-NEXT:        "clang-context-hash": "{{.*}}",
-// CHECK-NEXT:        "clang-module-deps": [
+// CHECK:             "clang-module-deps": [
 // CHECK-NEXT:          {
 // CHECK-NEXT:            "context-hash": "[[HASH]]",
 // CHECK-NEXT:            "module-name": "mod"
@@ -100,7 +100,7 @@ module mod {
 // CHECK:           "commands": [
 // CHECK:           {
 // CHECK-NEXT:         "clang-context-hash": "{{.*}}",
-// CHECK-NEXT:         "clang-module-deps": [
+// CHECK:              "clang-module-deps": [
 // CHECK-NEXT:           {
 // CHECK-NEXT:             "context-hash": "[[HASH]]",
 // CHECK-NEXT:             "module-name": "mod"
@@ -112,7 +112,7 @@ module mod {
 // SKIPOPT:      {
 // SKIPOPT-NEXT:   "modules": [
 // SKIPOPT-NEXT:    {
-// SKIPOPT-NEXT:      "clang-module-deps": [],
+// SKIPOPT:           "clang-module-deps": [],
 // SKIPOPT:           "context-hash": "[[HASH0:.*]]",
 // SKIPOPT:         }
 // SKIPOPT:        "translation-units": [
@@ -120,7 +120,7 @@ module mod {
 // SKIPOPT:            "commands": [
 // SKIPOPT:             {
 // SKIPOPT-NEXT:          "clang-context-hash": "{{.*}}",
-// SKIPOPT-NEXT:          "clang-module-deps": [
+// SKIPOPT:               "clang-module-deps": [
 // SKIPOPT-NEXT:            {
 // SKIPOPT-NEXT:              "context-hash": "[[HASH0]]",
 // SKIPOPT-NEXT:              "module-name": "mod"
@@ -129,7 +129,7 @@ module mod {
 // SKIPOPT:      {
 // SKIPOPT-NEXT:   "modules": [
 // SKIPOPT-NEXT:     {
-// SKIPOPT-NEXT:       "clang-module-deps": [],
+// SKIPOPT:            "clang-module-deps": [],
 // SKIPOPT-NOT:        "context-hash": "[[HASH0]]",
 // SKIPOPT:            "context-hash": "[[HASH2:.*]]",
 // SKIPOPT:          }
@@ -138,7 +138,7 @@ module mod {
 // SKIPOPT:           "commands": [
 // SKIPOPT:             {
 // SKIPOPT-NEXT:          "clang-context-hash": "{{.*}}",
-// SKIPOPT-NEXT:          "clang-module-deps": [
+// SKIPOPT:               "clang-module-deps": [
 // SKIPOPT-NEXT:            {
 // SKIPOPT-NOT:              "context-hash": "[[HASH0]]",
 // SKIPOPT-NEXT:             "context-hash": "[[HASH2]]"
@@ -160,7 +160,7 @@ module mod {
 // RELPATH:            "commands": [
 // RELPATH:             {
 // RELPATH-NEXT:          "clang-context-hash": "{{.*}}",
-// RELPATH-NEXT:          "clang-module-deps": [
+// RELPATH:               "clang-module-deps": [
 // RELPATH-NEXT:            {
 // RELPATH-NEXT:              "context-hash": "[[HASH3]]",
 // RELPATH-NEXT:              "module-name": "mod"
@@ -178,7 +178,7 @@ module mod {
 // RELPATH:           "commands": [
 // RELPATH:             {
 // RELPATH-NEXT:          "clang-context-hash": "{{.*}}",
-// RELPATH-NEXT:          "clang-module-deps": [
+// RELPATH:               "clang-module-deps": [
 // RELPATH-NEXT:            {
 // RELPATH-NOT:              "context-hash": "[[HASH3]]",
 // RELPATH-NEXT:             "context-hash": "[[HASH4]]"
diff --git a/clang/test/ClangScanDeps/modules-context-hash.c b/clang/test/ClangScanDeps/modules-context-hash.c
index 9489563576d3b..0622e1dd96974 100644
--- a/clang/test/ClangScanDeps/modules-context-hash.c
+++ b/clang/test/ClangScanDeps/modules-context-hash.c
@@ -45,7 +45,7 @@
 // CHECK-NEXT:   "translation-units": [
 // CHECK-NEXT:     {
 // CHECK:            "clang-context-hash": "{{.*}}",
-// CHECK-NEXT:       "clang-module-deps": [
+// CHECK:            "clang-module-deps": [
 // CHECK-NEXT:         {
 // CHECK-NEXT:           "context-hash": "[[HASH_MOD_A]]",
 // CHECK-NEXT:           "module-name": "mod"
@@ -83,7 +83,7 @@
 // CHECK-NEXT:   "translation-units": [
 // CHECK-NEXT:     {
 // CHECK:            "clang-context-hash": "{{.*}}",
-// CHECK-NEXT:       "clang-module-deps": [
+// CHECK:            "clang-module-deps": [
 // CHECK-NEXT:         {
 // CHECK-NOT:            "context-hash": "[[HASH_MOD_A]]",
 // CHECK:                "module-name": "mod"
diff --git a/clang/test/ClangScanDeps/modules-dep-args.c b/clang/test/ClangScanDeps/modules-dep-args.c
index 19f915923b84c..41b06580fabb7 100644
--- a/clang/test/ClangScanDeps/modules-dep-args.c
+++ b/clang/test/ClangScanDeps/modules-dep-args.c
@@ -81,7 +81,7 @@ module Direct { header "direct.h" }
 // CHECK-NEXT:   "translation-units": [
 // CHECK-NEXT:     {
 // CHECK:            "clang-context-hash": "{{.*}}",
-// CHECK-NEXT:       "clang-module-deps": [
+// CHECK:            "clang-module-deps": [
 // CHECK-NEXT:         {
 // CHECK-NEXT:           "context-hash": "{{.*}}",
 // CHECK-NEXT:           "module-name": "Direct"
diff --git a/clang/test/ClangScanDeps/modules-extern-submodule.c b/clang/test/ClangScanDeps/modules-extern-submodule.c
index 01d3d6ba5e0d3..757bcdf46edac 100644
--- a/clang/test/ClangScanDeps/modules-extern-submodule.c
+++ b/clang/test/ClangScanDeps/modules-extern-submodule.c
@@ -101,7 +101,7 @@ module third {}
 // CHECK-NEXT:       "commands": [
 // CHECK-NEXT:         {
 // CHECK-NEXT:           "clang-context-hash": "{{.*}}",
-// CHECK-NEXT:           "clang-module-deps": [
+// CHECK:                "clang-module-deps": [
 // CHECK-NEXT:             {
 // CHECK-NEXT:               "context-hash": "{{.*}}",
 // CHECK-NEXT:               "module-name": "first"
diff --git a/clang/test/ClangScanDeps/modules-extern-unrelated.m b/clang/test/ClangScanDeps/modules-extern-unrelated.m
index c003f0d9a2ee8..b81dad896c1ff 100644
--- a/clang/test/ClangScanDeps/modules-extern-unrelated.m
+++ b/clang/test/ClangScanDeps/modules-extern-unrelated.m
@@ -107,7 +107,7 @@
 // CHECK-NEXT:       "commands": [
 // CHECK-NEXT:         {
 // CHECK-NEXT:           "clang-context-hash": "{{.*}}",
-// CHECK-NEXT:           "clang-module-deps": [
+// CHECK:                "clang-module-deps": [
 // CHECK-NEXT:             {
 // CHECK-NEXT:               "context-hash": "{{.*}}",
 // CHECK-NEXT:               "module-name": "zeroth"
diff --git a/clang/test/ClangScanDeps/modules-fmodule-name-no-module-built.m b/clang/test/ClangScanDeps/modules-fmodule-name-no-module-built.m
index cfe29c2bf7cdb..1078545848f20 100644
--- a/clang/test/ClangScanDeps/modules-fmodule-name-no-module-built.m
+++ b/clang/test/ClangScanDeps/modules-fmodule-name-no-module-built.m
@@ -35,7 +35,7 @@
 // CHECK-NEXT:   "translation-units": [
 // CHECK-NEXT:     {
 // CHECK:            "clang-context-hash": "[[HASH_TU:[A-Z0-9]+]]",
-// CHECK-NEXT:       "clang-module-deps": [
+// CHECK:            "clang-module-deps": [
 // CHECK-NEXT:         {
 // CHECK-NEXT:           "context-hash": "[[HASH_H2]]",
 // CHECK-NEXT:           "module-name": "header2"
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 0000000000000..e042b702a1fa7
--- /dev/null
+++ b/clang/test/ClangScanDeps/modules-full-named-modules.cppm
@@ -0,0 +1,347 @@
+// This check that clang-scan-deps properly outputs named module dependencies 
+// when using the the scanning output format 'experimental-full'.
+//
+// See commit 72304.
+// UNSUPPORTED: target={{.*}}-aix{{.*}}
+//
+// The slash direction in linux and windows are different.
+// UNSUPPORTED: system-windows
+//
+// 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:   | 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:   | 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:   | 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:   | 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:   | 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:   | FileCheck %t/Checks.cpp -DPREFIX=%/t
+// RUN: clang-scan-deps --mode=preprocess-dependency-directives -compilation-database %t/compile_commands.json -format=experimental-full \
+// 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:                 "module-name": "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:             "module-name":
+// 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:                 "module-name": "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:                 "module-name": "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:                 "module-name": "M:interface_part"
+// CHECK-NEXT:            "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:                 "module-name": "M:interface_part"
+// CHECK-NEXT:            "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:             "module-name":
+// CHECK:                 "named-module-deps": [
+// CHECK-NEXT:              "M"
+// CHECK-NEXT:   ...
[truncated]

@naveen-seth naveen-seth added the clang:modules C++20 modules and Clang Header Modules label Jun 22, 2025
@naveen-seth naveen-seth requested a review from ChuanqiXu9 June 22, 2025 08:42
Copy link
Member

@ChuanqiXu9 ChuanqiXu9 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't feel bad but I'd like to leave the formal approvals to @jansvoboda11 and @Bigcheese here.

@naveen-seth naveen-seth requested a review from jansvoboda11 June 23, 2025 23:28
Copy link
Contributor

@jansvoboda11 jansvoboda11 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, but let's wait for @Bigcheese to take a look as well.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang:modules C++20 modules and Clang Header Modules clang Clang issues not falling into any other category
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants