Skip to content

Conversation

naveen-seth
Copy link
Contributor

With -fmodules-driver enabled, the Clang driver provides native support for:

  • Named module imports defined in other source files on the command
    line
  • Standard library imports (import std; and import std.compat;)
  • Clang modules discovered via module map files

Regular translation units can import both Clang modules and C++20 named modules.
Importing a Clang module into a C++20 named module interface unit, or vice versa, is not supported by this patch.

This patch is part of a series to support driver-managed module builds
for C++ named modules and Clang modules.

Commit 9403c2d introduced the entry point for the driver-managed
module build logic and assumed that it would live in the BuildActions
phase of the driver.
That proved unnecessary: the logic can be fully implemented in the
BuildJobs phase.

This reverts changes to BuildActions in preparation for the upcoming
patches.
@llvmbot llvmbot added clang Clang issues not falling into any other category clang:driver 'clang' and 'clang++' user-facing binaries. Not 'clang-cl' clang:frontend Language frontend issues, e.g. anything involving "Sema" labels Aug 31, 2025
@naveen-seth naveen-seth marked this pull request as draft August 31, 2025 15:27
@llvmbot
Copy link
Member

llvmbot commented Aug 31, 2025

@llvm/pr-subscribers-clang

Author: Naveen Seth Hanig (naveen-seth)

Changes

With -fmodules-driver enabled, the Clang driver provides native support for:

  • Named module imports defined in other source files on the command
    line
  • Standard library imports (import std; and import std.compat;)
  • Clang modules discovered via module map files

Regular translation units can import both Clang modules and C++20 named modules.
Importing a Clang module into a C++20 named module interface unit, or vice versa, is not supported by this patch.


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

12 Files Affected:

  • (modified) clang/include/clang/Basic/DiagnosticDriverKinds.td (+16)
  • (modified) clang/include/clang/Driver/Driver.h (+4-32)
  • (modified) clang/include/clang/Driver/Job.h (+3)
  • (added) clang/include/clang/Driver/ModulesDriver.h (+52)
  • (modified) clang/include/clang/Driver/Options.td (+6)
  • (modified) clang/lib/Driver/CMakeLists.txt (+2)
  • (modified) clang/lib/Driver/Driver.cpp (+33-64)
  • (added) clang/lib/Driver/ModulesDriver.cpp (+1477)
  • (added) clang/test/Driver/modules-driver-compile-both-kinds.cpp (+94)
  • (added) clang/test/Driver/modules-driver-dep-scan-diagnostics.cpp (+25)
  • (added) clang/test/Driver/modules-driver-dep-scan-graphviz.cpp (+89)
  • (added) clang/test/Driver/modules-driver-duplicate-named-module.cpp (+20)
diff --git a/clang/include/clang/Basic/DiagnosticDriverKinds.td b/clang/include/clang/Basic/DiagnosticDriverKinds.td
index b8c7c6e8d6909..596fd4a37d83f 100644
--- a/clang/include/clang/Basic/DiagnosticDriverKinds.td
+++ b/clang/include/clang/Basic/DiagnosticDriverKinds.td
@@ -587,6 +587,22 @@ def remark_found_cxx20_module_usage : Remark<
 def remark_performing_driver_managed_module_build : Remark<
   "performing driver managed module build">,
   InGroup<ModulesDriver>;
+def remark_std_module_manifest_path : Remark<
+  "using std modules manifest: '%0'">, InGroup<ModulesDriver>;
+def err_failed_parse_modules_manifest_json: Error<
+  "failed to parse the std modules manifest">;
+def err_failed_depdendency_scan : Error<
+  "failed to perform dependency scan">;
+def remark_failed_dependency_scan_for_input : Remark<
+  "dependency scan failed for source input '%0'">,
+  InGroup<ModulesDriver>;
+def err_mod_graph_named_module_redefinition : Error<
+  "duplicate definitions of C++20 named module '%0' in '%1' and '%2'">;
+def  err_building_depdendency_graph : Error<
+  "failed to construct the module dependency graph">;
+def remark_printing_module_graph : Remark<
+  "printing module dependency graph">,
+  InGroup<ModulesDriver>;
 
 def warn_drv_delayed_template_parsing_after_cxx20 : Warning<
   "-fdelayed-template-parsing is deprecated after C++20">,
diff --git a/clang/include/clang/Driver/Driver.h b/clang/include/clang/Driver/Driver.h
index b9b187ada8add..ba0168385c69b 100644
--- a/clang/include/clang/Driver/Driver.h
+++ b/clang/include/clang/Driver/Driver.h
@@ -135,6 +135,10 @@ class Driver {
   /// interpretation.
   bool ModulesModeCXX20;
 
+  /// Set if the dirver should plan the compilation after scanning module
+  /// dependencies, using the scan results (set by -f(no-)modules-driver.)
+  bool DriverManagedModulesBuild;
+
   /// LTO mode selected via -f(no-)?lto(=.*)? options.
   LTOKind LTOMode;
 
@@ -512,9 +516,6 @@ class Driver {
 
   /// BuildActions - Construct the list of actions to perform for the
   /// given arguments, which are only done for a single architecture.
-  /// If the compilation is an explicit module build, delegates to
-  /// BuildDriverManagedModuleBuildActions. Otherwise, BuildDefaultActions is
-  /// used.
   ///
   /// \param C - The compilation that is being built.
   /// \param Args - The input arguments.
@@ -799,35 +800,6 @@ class Driver {
   /// compilation based on which -f(no-)?lto(=.*)? option occurs last.
   void setLTOMode(const llvm::opt::ArgList &Args);
 
-  /// BuildDefaultActions - Constructs the list of actions to perform
-  /// for the provided arguments, which are only done for a single architecture.
-  ///
-  /// \param C - The compilation that is being built.
-  /// \param Args - The input arguments.
-  /// \param Actions - The list to store the resulting actions onto.
-  void BuildDefaultActions(Compilation &C, llvm::opt::DerivedArgList &Args,
-                           const InputList &Inputs, ActionList &Actions) const;
-
-  /// BuildDriverManagedModuleBuildActions - Performs a dependency
-  /// scan and constructs the list of actions to perform for dependency order
-  /// and the provided arguments. This is only done for a single a architecture.
-  ///
-  /// \param C - The compilation that is being built.
-  /// \param Args - The input arguments.
-  /// \param Actions - The list to store the resulting actions onto.
-  void BuildDriverManagedModuleBuildActions(Compilation &C,
-                                            llvm::opt::DerivedArgList &Args,
-                                            const InputList &Inputs,
-                                            ActionList &Actions) const;
-
-  /// Scans the leading lines of the C++ source inputs to detect C++20 module
-  /// usage.
-  ///
-  /// \returns True if module usage is detected, false otherwise, or an error on
-  /// read failure.
-  llvm::ErrorOr<bool>
-  ScanInputsForCXX20ModulesUsage(const InputList &Inputs) const;
-
   /// Retrieves a ToolChain for a particular \p Target triple.
   ///
   /// Will cache ToolChains for the life of the driver object, and create them
diff --git a/clang/include/clang/Driver/Job.h b/clang/include/clang/Driver/Job.h
index 561866197b780..c71ad8538e6c2 100644
--- a/clang/include/clang/Driver/Job.h
+++ b/clang/include/clang/Driver/Job.h
@@ -221,6 +221,8 @@ class Command {
 
   const char *getExecutable() const { return Executable; }
 
+  llvm::opt::ArgStringList &getArguments() { return Arguments; }
+
   const llvm::opt::ArgStringList &getArguments() const { return Arguments; }
 
   const std::vector<InputInfo> &getInputInfos() const { return InputInfoList; }
@@ -277,6 +279,7 @@ class JobList {
   /// Clear the job list.
   void clear();
 
+  list_type &getJobs() { return Jobs; }
   const list_type &getJobs() const { return Jobs; }
 
   bool empty() const { return Jobs.empty(); }
diff --git a/clang/include/clang/Driver/ModulesDriver.h b/clang/include/clang/Driver/ModulesDriver.h
new file mode 100644
index 0000000000000..7720bddb8d4b0
--- /dev/null
+++ b/clang/include/clang/Driver/ModulesDriver.h
@@ -0,0 +1,52 @@
+//===- DependencyScanner.h - Module dependency discovery --------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file defines the module dependency graph and dependency-scanning
+/// functionality.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_DRIVER_DEPENDENCYSCANNER_H
+#define LLVM_CLANG_DRIVER_DEPENDENCYSCANNER_H
+
+#include "clang/Driver/Types.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/VirtualFileSystem.h"
+
+namespace clang {
+class DiagnosticsEngine;
+namespace driver {
+class Compilation;
+} // namespace driver
+} // namespace clang
+
+namespace clang::driver::modules {
+
+using InputTy = std::pair<types::ID, const llvm::opt::Arg *>;
+
+using InputList = llvm::SmallVector<InputTy, 16>;
+
+/// Checks whether the -fmodules-driver feature should be implicitly enabled.
+///
+/// When -fmodules-driver is no longer experimental, it should be enabled by
+/// default iff both conditions are met:
+/// (1) there are two or more C++ source inputs; and
+/// (2) at least one input uses C++20 named modules.
+bool shouldEnableModulesDriver(const InputList &Inputs,
+                               llvm::vfs::FileSystem &VFS,
+                               DiagnosticsEngine &Diags);
+
+/// Appends the std and std.compat module inputs.
+bool ensureNamedModuleStdLibraryInputs(Compilation &C, InputList &Inputs);
+
+bool performDriverModuleBuild(Compilation &C, DiagnosticsEngine &Diags);
+
+} // namespace clang::driver::modules
+
+#endif
diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
index 82e8212bee12d..ed097130ac54f 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -3302,6 +3302,12 @@ def fmodules_driver : Flag<["-"], "fmodules-driver">,
 def fno_modules_driver : Flag<["-"], "fno-modules-driver">,
   Group<f_Group>, Visibility<[ClangOption]>,
   HelpText<"Disable support for driver managed module builds (experimental)">;
+def fimplicit_import_std : Flag<["-"], "fimplicit-import-std">,
+  Group<f_Group>, Visibility<[ClangOption]>,
+  HelpText<"Implicitly add the std module when discovered in driver managed module builds">;
+def fno_implicit_import_std : Flag<["-"], "fno-implicit-import-std">,
+  Group<f_Group>, Visibility<[ClangOption]>,
+  HelpText<"Don't implicitly add the std module when discovered in driver managed module builds">;
 
 def experimental_modules_reduced_bmi : Flag<["-"], "fexperimental-modules-reduced-bmi">,
   Group<f_Group>, Visibility<[ClangOption, CC1Option]>, Alias<fmodules_reduced_bmi>;
diff --git a/clang/lib/Driver/CMakeLists.txt b/clang/lib/Driver/CMakeLists.txt
index 7c4f70b966c48..43f11fe623893 100644
--- a/clang/lib/Driver/CMakeLists.txt
+++ b/clang/lib/Driver/CMakeLists.txt
@@ -21,6 +21,7 @@ add_clang_library(clangDriver
   Driver.cpp
   DriverOptions.cpp
   Job.cpp
+  ModulesDriver.cpp
   Multilib.cpp
   MultilibBuilder.cpp
   OffloadBundler.cpp
@@ -98,6 +99,7 @@ add_clang_library(clangDriver
 
   LINK_LIBS
   clangBasic
+  clangDependencyScanning
   clangLex
   ${system_libs}
   )
diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp
index f110dbab3e5a5..89ee1884393fa 100644
--- a/clang/lib/Driver/Driver.cpp
+++ b/clang/lib/Driver/Driver.cpp
@@ -60,6 +60,7 @@
 #include "clang/Driver/Compilation.h"
 #include "clang/Driver/InputInfo.h"
 #include "clang/Driver/Job.h"
+#include "clang/Driver/ModulesDriver.h"
 #include "clang/Driver/Options.h"
 #include "clang/Driver/Phases.h"
 #include "clang/Driver/SanitizerArgs.h"
@@ -1826,6 +1827,18 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) {
     }
   }
 
+  if (C->getArgs().hasFlag(options::OPT_fmodules_driver,
+                           options::OPT_fno_modules_driver, false)) {
+    // The detection logic for this is kept here only for diagnostics until
+    // is enabled by default.
+    modules::shouldEnableModulesDriver(Inputs, getVFS(), Diags);
+    Diags.Report(diag::remark_performing_driver_managed_module_build);
+    if (C->getArgs().hasFlag(options::OPT_fimplicit_import_std,
+                             options::OPT_fno_implicit_import_std, true)) {
+      modules::ensureNamedModuleStdLibraryInputs(*C, Inputs);
+    }
+  }
+
   // Populate the tool chains for the offloading devices, if any.
   CreateOffloadingDeviceToolChains(*C, Inputs);
 
@@ -4189,10 +4202,20 @@ void Driver::handleArguments(Compilation &C, DerivedArgList &Args,
     YcArg = nullptr;
   }
 
-  if (Args.hasArgNoClaim(options::OPT_fmodules_driver))
-    // TODO: Check against all incompatible -fmodules-driver arguments
-    if (!ModulesModeCXX20 && !Args.hasArgNoClaim(options::OPT_fmodules))
-      Args.eraseArg(options::OPT_fmodules_driver);
+  if (Args.hasArgNoClaim(options::OPT_fmodules_driver)) {
+    // HACK: This should be only added for the Standard library jobs, explicitly
+    // created by the modules driver.
+    MakeInputArg(Args, getOpts(),
+                 Args.MakeArgString("-Wno-reserved-module-identifier"));
+    if (Args.hasArg(options::OPT_fmodules)) {
+      Args.eraseArg(options::OPT_fmodules);
+      Arg *Arg = Args.MakeSeparateArg(
+          nullptr, getOpts().getOption(options::OPT_fimplicit_modules),
+          Args.MakeArgString(("-fimplicit-modules")));
+      Arg->claim();
+      Args.append(Arg);
+    }
+  }
 
   Arg *FinalPhaseArg;
   phases::ID FinalPhase = getFinalPhase(Args, &FinalPhaseArg);
@@ -4320,33 +4343,6 @@ void Driver::handleArguments(Compilation &C, DerivedArgList &Args,
   }
 }
 
-static bool hasCXXModuleInputType(const Driver::InputList &Inputs) {
-  const auto IsTypeCXXModule = [](const auto &Input) -> bool {
-    const auto TypeID = Input.first;
-    return (TypeID == types::TY_CXXModule);
-  };
-  return llvm::any_of(Inputs, IsTypeCXXModule);
-}
-
-llvm::ErrorOr<bool>
-Driver::ScanInputsForCXX20ModulesUsage(const InputList &Inputs) const {
-  const auto CXXInputs = llvm::make_filter_range(
-      Inputs, [](const auto &Input) { return types::isCXX(Input.first); });
-  for (const auto &Input : CXXInputs) {
-    StringRef Filename = Input.second->getSpelling();
-    auto ErrOrBuffer = VFS->getBufferForFile(Filename);
-    if (!ErrOrBuffer)
-      return ErrOrBuffer.getError();
-    const auto Buffer = std::move(*ErrOrBuffer);
-
-    if (scanInputForCXX20ModulesUsage(Buffer->getBuffer())) {
-      Diags.Report(diag::remark_found_cxx20_module_usage) << Filename;
-      return true;
-    }
-  }
-  return false;
-}
-
 void Driver::BuildActions(Compilation &C, DerivedArgList &Args,
                           const InputList &Inputs, ActionList &Actions) const {
   llvm::PrettyStackTraceString CrashInfo("Building compilation actions");
@@ -4358,33 +4354,6 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args,
 
   handleArguments(C, Args, Inputs, Actions);
 
-  if (Args.hasFlag(options::OPT_fmodules_driver,
-                   options::OPT_fno_modules_driver, false)) {
-    // TODO: Move the logic for implicitly enabling explicit-module-builds out
-    // of -fmodules-driver once it is no longer experimental.
-    // Currently, this serves diagnostic purposes only.
-    bool UsesCXXModules = hasCXXModuleInputType(Inputs);
-    if (!UsesCXXModules) {
-      const auto ErrOrScanResult = ScanInputsForCXX20ModulesUsage(Inputs);
-      if (!ErrOrScanResult) {
-        Diags.Report(diag::err_cannot_open_file)
-            << ErrOrScanResult.getError().message();
-        return;
-      }
-      UsesCXXModules = *ErrOrScanResult;
-    }
-    if (UsesCXXModules || Args.hasArg(options::OPT_fmodules))
-      BuildDriverManagedModuleBuildActions(C, Args, Inputs, Actions);
-    return;
-  }
-
-  BuildDefaultActions(C, Args, Inputs, Actions);
-}
-
-void Driver::BuildDefaultActions(Compilation &C, DerivedArgList &Args,
-                                 const InputList &Inputs,
-                                 ActionList &Actions) const {
-
   bool UseNewOffloadingDriver =
       C.isOffloadingHostKind(Action::OFK_OpenMP) ||
       C.isOffloadingHostKind(Action::OFK_SYCL) ||
@@ -4680,12 +4649,6 @@ void Driver::BuildDefaultActions(Compilation &C, DerivedArgList &Args,
   Args.ClaimAllArgs(options::OPT_cl_ignored_Group);
 }
 
-void Driver::BuildDriverManagedModuleBuildActions(
-    Compilation &C, llvm::opt::DerivedArgList &Args, const InputList &Inputs,
-    ActionList &Actions) const {
-  Diags.Report(diag::remark_performing_driver_managed_module_build);
-}
-
 /// Returns the canonical name for the offloading architecture when using a HIP
 /// or CUDA architecture.
 static StringRef getCanonicalArchString(Compilation &C,
@@ -5440,6 +5403,12 @@ void Driver::BuildJobs(Compilation &C) const {
       }
     }
   }
+  if (C.getArgs().hasFlag(options::OPT_fmodules_driver,
+                          options::OPT_fno_modules_driver, false)) {
+    auto Success = modules::performDriverModuleBuild(C, C.getDriver().Diags);
+    if (!Success)
+      return;
+  }
 }
 
 namespace {
diff --git a/clang/lib/Driver/ModulesDriver.cpp b/clang/lib/Driver/ModulesDriver.cpp
new file mode 100644
index 0000000000000..e21d7fc55a168
--- /dev/null
+++ b/clang/lib/Driver/ModulesDriver.cpp
@@ -0,0 +1,1477 @@
+//===- DependencyScanner.cpp - Module dependency discovery ----------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Driver/ModulesDriver.h"
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/DiagnosticDriver.h"
+#include "clang/Driver/Compilation.h"
+#include "clang/Driver/Driver.h"
+#include "clang/Driver/InputInfo.h"
+#include "clang/Driver/Job.h"
+#include "clang/Driver/Tool.h"
+#include "clang/Driver/Types.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Tooling/DependencyScanning/DependencyScanningTool.h"
+#include "clang/Tooling/DependencyScanning/DependencyScanningWorker.h"
+#include "clang/Tooling/DependencyScanning/ModuleDepCollector.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/DepthFirstIterator.h"
+#include "llvm/ADT/DirectedGraph.h"
+#include "llvm/ADT/PostOrderIterator.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/TypeSwitch.h"
+#include "llvm/Option/ArgList.h"
+#include "llvm/Option/Option.h"
+#include "llvm/Support/Allocator.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/GraphWriter.h"
+#include "llvm/Support/JSON.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/ThreadPool.h"
+#include "llvm/TargetParser/Host.h"
+#include <atomic>
+#include <memory>
+#include <optional>
+#include <string>
+#include <utility>
+#include <vector>
+
+using namespace clang;
+using namespace clang::driver;
+using namespace llvm;
+using namespace llvm::opt;
+
+namespace clang::tooling {
+namespace deps = dependencies;
+} // namespace clang::tooling
+
+using OwnedJobList = SmallVector<std::unique_ptr<Command>, 4>;
+
+//===----------------------------------------------------------------------===//
+// Check: Enable -fmodules-driver implicitly
+//===----------------------------------------------------------------------===//
+
+namespace clang::driver::modules {
+
+/// Returns true if any input is a `.cppm` file.
+static bool hasCXXModuleInputType(const InputList &Inputs) {
+  const auto IsTypeCXXModule = [](const auto &Input) -> bool {
+    const auto TypeID = Input.first;
+    return (TypeID == types::TY_CXXModule);
+  };
+  return llvm::any_of(Inputs, IsTypeCXXModule);
+}
+
+/// Scans the leading lines of the C++ source inputs to detect C++20 module
+/// usage.
+///
+/// \returns true if module usage is detected, false otherwise, or an error on
+/// failure to read the input source.
+static llvm::ErrorOr<bool>
+ScanInputsForCXX20ModulesUsage(const InputList &Inputs,
+                               llvm::vfs::FileSystem &VFS,
+                               DiagnosticsEngine &Diags) {
+  const auto CXXInputs = llvm::make_filter_range(
+      Inputs, [](const auto &Input) { return types::isCXX(Input.first); });
+  for (const auto &Input : CXXInputs) {
+    StringRef Filename = Input.second->getSpelling();
+    auto ErrOrBuffer = VFS.getBufferForFile(Filename);
+    if (!ErrOrBuffer)
+      return ErrOrBuffer.getError();
+    const auto Buffer = std::move(*ErrOrBuffer);
+
+    if (scanInputForCXX20ModulesUsage(Buffer->getBuffer())) {
+      Diags.Report(diag::remark_found_cxx20_module_usage) << Filename;
+      return true;
+    }
+  }
+  return false;
+}
+
+/// Checks if the -fmodules-driver feature should be implicitly enabled for this
+/// compilation.
+///
+/// The -fmodules-driver feature should be implicitly enabled iff (1) any input
+/// makes used of C++20 named modules; and (2) there are more than two source
+/// input files.
+///
+/// \returns true if the -fmodules-driver feature should be enabled, false
+/// otherwise.
+bool shouldEnableModulesDriver(const InputList &Inputs,
+                               llvm::vfs::FileSystem &VFS,
+                               DiagnosticsEngine &Diags) {
+  if (Inputs.size() < 2)
+    return false;
+
+  bool UsesCXXModules = hasCXXModuleInputType(Inputs);
+  if (UsesCXXModules)
+    return true;
+
+  const auto ErrOrScanResult =
+      ScanInputsForCXX20ModulesUsage(Inputs, VFS, Diags);
+  if (!ErrOrScanResult) {
+    Diags.Report(diag::err_cannot_open_file)
+        << ErrOrScanResult.getError().message();
+  }
+  return *ErrOrScanResult;
+}
+
+/// Builds the a C++ named module input for \c InputFile and adds it to \c Args.
+static void addCXXModuleInput(InputList &Inputs, DerivedArgList &Args,
+                              const OptTable &Opts, StringRef InputFile) {
+  Arg *A = new Arg(Opts.getOption(options::OPT_INPUT), InputFile,
+                   Args.getBaseArgs().MakeIndex(InputFile),
+                   Args.getBaseArgs().MakeArgString(InputFile));
+  Args.AddSynthesizedArg(A);
+  A->claim();
+  Inputs.push_back(std::make_pair(types::TY_CXXModule, A));
+}
+
+/// Parses the std modules manifest and builds the inputs for the discovered
+/// std modules.
+///
+/// \returns true if the modules were added, false failure to read/parse the
+/// manifest (with diagnostics reported using the drivers DiagnosticEngine).
+bool ensureNamedModuleStdLibraryInputs(Compilation &C, InputList &Inputs) {
+  const auto &Driver = C.getDriver();
+  auto &Diags = Driver.getDiags();
+
+  const auto ManifestPath =
+      Driver.GetStdModuleManifestPath(C, C.getDefaultToolChain());
+  Diags.Report(diag::remark_std_module_manifest_path) << ManifestPath;
+  if (ManifestPath == "<NOT PRESENT>")
+    return false;
+
+  llvm::SmallString<256> Mani...
[truncated]

@llvmbot
Copy link
Member

llvmbot commented Aug 31, 2025

@llvm/pr-subscribers-clang-driver

Author: Naveen Seth Hanig (naveen-seth)

Changes

With -fmodules-driver enabled, the Clang driver provides native support for:

  • Named module imports defined in other source files on the command
    line
  • Standard library imports (import std; and import std.compat;)
  • Clang modules discovered via module map files

Regular translation units can import both Clang modules and C++20 named modules.
Importing a Clang module into a C++20 named module interface unit, or vice versa, is not supported by this patch.


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

12 Files Affected:

  • (modified) clang/include/clang/Basic/DiagnosticDriverKinds.td (+16)
  • (modified) clang/include/clang/Driver/Driver.h (+4-32)
  • (modified) clang/include/clang/Driver/Job.h (+3)
  • (added) clang/include/clang/Driver/ModulesDriver.h (+52)
  • (modified) clang/include/clang/Driver/Options.td (+6)
  • (modified) clang/lib/Driver/CMakeLists.txt (+2)
  • (modified) clang/lib/Driver/Driver.cpp (+33-64)
  • (added) clang/lib/Driver/ModulesDriver.cpp (+1477)
  • (added) clang/test/Driver/modules-driver-compile-both-kinds.cpp (+94)
  • (added) clang/test/Driver/modules-driver-dep-scan-diagnostics.cpp (+25)
  • (added) clang/test/Driver/modules-driver-dep-scan-graphviz.cpp (+89)
  • (added) clang/test/Driver/modules-driver-duplicate-named-module.cpp (+20)
diff --git a/clang/include/clang/Basic/DiagnosticDriverKinds.td b/clang/include/clang/Basic/DiagnosticDriverKinds.td
index b8c7c6e8d6909..596fd4a37d83f 100644
--- a/clang/include/clang/Basic/DiagnosticDriverKinds.td
+++ b/clang/include/clang/Basic/DiagnosticDriverKinds.td
@@ -587,6 +587,22 @@ def remark_found_cxx20_module_usage : Remark<
 def remark_performing_driver_managed_module_build : Remark<
   "performing driver managed module build">,
   InGroup<ModulesDriver>;
+def remark_std_module_manifest_path : Remark<
+  "using std modules manifest: '%0'">, InGroup<ModulesDriver>;
+def err_failed_parse_modules_manifest_json: Error<
+  "failed to parse the std modules manifest">;
+def err_failed_depdendency_scan : Error<
+  "failed to perform dependency scan">;
+def remark_failed_dependency_scan_for_input : Remark<
+  "dependency scan failed for source input '%0'">,
+  InGroup<ModulesDriver>;
+def err_mod_graph_named_module_redefinition : Error<
+  "duplicate definitions of C++20 named module '%0' in '%1' and '%2'">;
+def  err_building_depdendency_graph : Error<
+  "failed to construct the module dependency graph">;
+def remark_printing_module_graph : Remark<
+  "printing module dependency graph">,
+  InGroup<ModulesDriver>;
 
 def warn_drv_delayed_template_parsing_after_cxx20 : Warning<
   "-fdelayed-template-parsing is deprecated after C++20">,
diff --git a/clang/include/clang/Driver/Driver.h b/clang/include/clang/Driver/Driver.h
index b9b187ada8add..ba0168385c69b 100644
--- a/clang/include/clang/Driver/Driver.h
+++ b/clang/include/clang/Driver/Driver.h
@@ -135,6 +135,10 @@ class Driver {
   /// interpretation.
   bool ModulesModeCXX20;
 
+  /// Set if the dirver should plan the compilation after scanning module
+  /// dependencies, using the scan results (set by -f(no-)modules-driver.)
+  bool DriverManagedModulesBuild;
+
   /// LTO mode selected via -f(no-)?lto(=.*)? options.
   LTOKind LTOMode;
 
@@ -512,9 +516,6 @@ class Driver {
 
   /// BuildActions - Construct the list of actions to perform for the
   /// given arguments, which are only done for a single architecture.
-  /// If the compilation is an explicit module build, delegates to
-  /// BuildDriverManagedModuleBuildActions. Otherwise, BuildDefaultActions is
-  /// used.
   ///
   /// \param C - The compilation that is being built.
   /// \param Args - The input arguments.
@@ -799,35 +800,6 @@ class Driver {
   /// compilation based on which -f(no-)?lto(=.*)? option occurs last.
   void setLTOMode(const llvm::opt::ArgList &Args);
 
-  /// BuildDefaultActions - Constructs the list of actions to perform
-  /// for the provided arguments, which are only done for a single architecture.
-  ///
-  /// \param C - The compilation that is being built.
-  /// \param Args - The input arguments.
-  /// \param Actions - The list to store the resulting actions onto.
-  void BuildDefaultActions(Compilation &C, llvm::opt::DerivedArgList &Args,
-                           const InputList &Inputs, ActionList &Actions) const;
-
-  /// BuildDriverManagedModuleBuildActions - Performs a dependency
-  /// scan and constructs the list of actions to perform for dependency order
-  /// and the provided arguments. This is only done for a single a architecture.
-  ///
-  /// \param C - The compilation that is being built.
-  /// \param Args - The input arguments.
-  /// \param Actions - The list to store the resulting actions onto.
-  void BuildDriverManagedModuleBuildActions(Compilation &C,
-                                            llvm::opt::DerivedArgList &Args,
-                                            const InputList &Inputs,
-                                            ActionList &Actions) const;
-
-  /// Scans the leading lines of the C++ source inputs to detect C++20 module
-  /// usage.
-  ///
-  /// \returns True if module usage is detected, false otherwise, or an error on
-  /// read failure.
-  llvm::ErrorOr<bool>
-  ScanInputsForCXX20ModulesUsage(const InputList &Inputs) const;
-
   /// Retrieves a ToolChain for a particular \p Target triple.
   ///
   /// Will cache ToolChains for the life of the driver object, and create them
diff --git a/clang/include/clang/Driver/Job.h b/clang/include/clang/Driver/Job.h
index 561866197b780..c71ad8538e6c2 100644
--- a/clang/include/clang/Driver/Job.h
+++ b/clang/include/clang/Driver/Job.h
@@ -221,6 +221,8 @@ class Command {
 
   const char *getExecutable() const { return Executable; }
 
+  llvm::opt::ArgStringList &getArguments() { return Arguments; }
+
   const llvm::opt::ArgStringList &getArguments() const { return Arguments; }
 
   const std::vector<InputInfo> &getInputInfos() const { return InputInfoList; }
@@ -277,6 +279,7 @@ class JobList {
   /// Clear the job list.
   void clear();
 
+  list_type &getJobs() { return Jobs; }
   const list_type &getJobs() const { return Jobs; }
 
   bool empty() const { return Jobs.empty(); }
diff --git a/clang/include/clang/Driver/ModulesDriver.h b/clang/include/clang/Driver/ModulesDriver.h
new file mode 100644
index 0000000000000..7720bddb8d4b0
--- /dev/null
+++ b/clang/include/clang/Driver/ModulesDriver.h
@@ -0,0 +1,52 @@
+//===- DependencyScanner.h - Module dependency discovery --------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file defines the module dependency graph and dependency-scanning
+/// functionality.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_DRIVER_DEPENDENCYSCANNER_H
+#define LLVM_CLANG_DRIVER_DEPENDENCYSCANNER_H
+
+#include "clang/Driver/Types.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/VirtualFileSystem.h"
+
+namespace clang {
+class DiagnosticsEngine;
+namespace driver {
+class Compilation;
+} // namespace driver
+} // namespace clang
+
+namespace clang::driver::modules {
+
+using InputTy = std::pair<types::ID, const llvm::opt::Arg *>;
+
+using InputList = llvm::SmallVector<InputTy, 16>;
+
+/// Checks whether the -fmodules-driver feature should be implicitly enabled.
+///
+/// When -fmodules-driver is no longer experimental, it should be enabled by
+/// default iff both conditions are met:
+/// (1) there are two or more C++ source inputs; and
+/// (2) at least one input uses C++20 named modules.
+bool shouldEnableModulesDriver(const InputList &Inputs,
+                               llvm::vfs::FileSystem &VFS,
+                               DiagnosticsEngine &Diags);
+
+/// Appends the std and std.compat module inputs.
+bool ensureNamedModuleStdLibraryInputs(Compilation &C, InputList &Inputs);
+
+bool performDriverModuleBuild(Compilation &C, DiagnosticsEngine &Diags);
+
+} // namespace clang::driver::modules
+
+#endif
diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
index 82e8212bee12d..ed097130ac54f 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -3302,6 +3302,12 @@ def fmodules_driver : Flag<["-"], "fmodules-driver">,
 def fno_modules_driver : Flag<["-"], "fno-modules-driver">,
   Group<f_Group>, Visibility<[ClangOption]>,
   HelpText<"Disable support for driver managed module builds (experimental)">;
+def fimplicit_import_std : Flag<["-"], "fimplicit-import-std">,
+  Group<f_Group>, Visibility<[ClangOption]>,
+  HelpText<"Implicitly add the std module when discovered in driver managed module builds">;
+def fno_implicit_import_std : Flag<["-"], "fno-implicit-import-std">,
+  Group<f_Group>, Visibility<[ClangOption]>,
+  HelpText<"Don't implicitly add the std module when discovered in driver managed module builds">;
 
 def experimental_modules_reduced_bmi : Flag<["-"], "fexperimental-modules-reduced-bmi">,
   Group<f_Group>, Visibility<[ClangOption, CC1Option]>, Alias<fmodules_reduced_bmi>;
diff --git a/clang/lib/Driver/CMakeLists.txt b/clang/lib/Driver/CMakeLists.txt
index 7c4f70b966c48..43f11fe623893 100644
--- a/clang/lib/Driver/CMakeLists.txt
+++ b/clang/lib/Driver/CMakeLists.txt
@@ -21,6 +21,7 @@ add_clang_library(clangDriver
   Driver.cpp
   DriverOptions.cpp
   Job.cpp
+  ModulesDriver.cpp
   Multilib.cpp
   MultilibBuilder.cpp
   OffloadBundler.cpp
@@ -98,6 +99,7 @@ add_clang_library(clangDriver
 
   LINK_LIBS
   clangBasic
+  clangDependencyScanning
   clangLex
   ${system_libs}
   )
diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp
index f110dbab3e5a5..89ee1884393fa 100644
--- a/clang/lib/Driver/Driver.cpp
+++ b/clang/lib/Driver/Driver.cpp
@@ -60,6 +60,7 @@
 #include "clang/Driver/Compilation.h"
 #include "clang/Driver/InputInfo.h"
 #include "clang/Driver/Job.h"
+#include "clang/Driver/ModulesDriver.h"
 #include "clang/Driver/Options.h"
 #include "clang/Driver/Phases.h"
 #include "clang/Driver/SanitizerArgs.h"
@@ -1826,6 +1827,18 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) {
     }
   }
 
+  if (C->getArgs().hasFlag(options::OPT_fmodules_driver,
+                           options::OPT_fno_modules_driver, false)) {
+    // The detection logic for this is kept here only for diagnostics until
+    // is enabled by default.
+    modules::shouldEnableModulesDriver(Inputs, getVFS(), Diags);
+    Diags.Report(diag::remark_performing_driver_managed_module_build);
+    if (C->getArgs().hasFlag(options::OPT_fimplicit_import_std,
+                             options::OPT_fno_implicit_import_std, true)) {
+      modules::ensureNamedModuleStdLibraryInputs(*C, Inputs);
+    }
+  }
+
   // Populate the tool chains for the offloading devices, if any.
   CreateOffloadingDeviceToolChains(*C, Inputs);
 
@@ -4189,10 +4202,20 @@ void Driver::handleArguments(Compilation &C, DerivedArgList &Args,
     YcArg = nullptr;
   }
 
-  if (Args.hasArgNoClaim(options::OPT_fmodules_driver))
-    // TODO: Check against all incompatible -fmodules-driver arguments
-    if (!ModulesModeCXX20 && !Args.hasArgNoClaim(options::OPT_fmodules))
-      Args.eraseArg(options::OPT_fmodules_driver);
+  if (Args.hasArgNoClaim(options::OPT_fmodules_driver)) {
+    // HACK: This should be only added for the Standard library jobs, explicitly
+    // created by the modules driver.
+    MakeInputArg(Args, getOpts(),
+                 Args.MakeArgString("-Wno-reserved-module-identifier"));
+    if (Args.hasArg(options::OPT_fmodules)) {
+      Args.eraseArg(options::OPT_fmodules);
+      Arg *Arg = Args.MakeSeparateArg(
+          nullptr, getOpts().getOption(options::OPT_fimplicit_modules),
+          Args.MakeArgString(("-fimplicit-modules")));
+      Arg->claim();
+      Args.append(Arg);
+    }
+  }
 
   Arg *FinalPhaseArg;
   phases::ID FinalPhase = getFinalPhase(Args, &FinalPhaseArg);
@@ -4320,33 +4343,6 @@ void Driver::handleArguments(Compilation &C, DerivedArgList &Args,
   }
 }
 
-static bool hasCXXModuleInputType(const Driver::InputList &Inputs) {
-  const auto IsTypeCXXModule = [](const auto &Input) -> bool {
-    const auto TypeID = Input.first;
-    return (TypeID == types::TY_CXXModule);
-  };
-  return llvm::any_of(Inputs, IsTypeCXXModule);
-}
-
-llvm::ErrorOr<bool>
-Driver::ScanInputsForCXX20ModulesUsage(const InputList &Inputs) const {
-  const auto CXXInputs = llvm::make_filter_range(
-      Inputs, [](const auto &Input) { return types::isCXX(Input.first); });
-  for (const auto &Input : CXXInputs) {
-    StringRef Filename = Input.second->getSpelling();
-    auto ErrOrBuffer = VFS->getBufferForFile(Filename);
-    if (!ErrOrBuffer)
-      return ErrOrBuffer.getError();
-    const auto Buffer = std::move(*ErrOrBuffer);
-
-    if (scanInputForCXX20ModulesUsage(Buffer->getBuffer())) {
-      Diags.Report(diag::remark_found_cxx20_module_usage) << Filename;
-      return true;
-    }
-  }
-  return false;
-}
-
 void Driver::BuildActions(Compilation &C, DerivedArgList &Args,
                           const InputList &Inputs, ActionList &Actions) const {
   llvm::PrettyStackTraceString CrashInfo("Building compilation actions");
@@ -4358,33 +4354,6 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args,
 
   handleArguments(C, Args, Inputs, Actions);
 
-  if (Args.hasFlag(options::OPT_fmodules_driver,
-                   options::OPT_fno_modules_driver, false)) {
-    // TODO: Move the logic for implicitly enabling explicit-module-builds out
-    // of -fmodules-driver once it is no longer experimental.
-    // Currently, this serves diagnostic purposes only.
-    bool UsesCXXModules = hasCXXModuleInputType(Inputs);
-    if (!UsesCXXModules) {
-      const auto ErrOrScanResult = ScanInputsForCXX20ModulesUsage(Inputs);
-      if (!ErrOrScanResult) {
-        Diags.Report(diag::err_cannot_open_file)
-            << ErrOrScanResult.getError().message();
-        return;
-      }
-      UsesCXXModules = *ErrOrScanResult;
-    }
-    if (UsesCXXModules || Args.hasArg(options::OPT_fmodules))
-      BuildDriverManagedModuleBuildActions(C, Args, Inputs, Actions);
-    return;
-  }
-
-  BuildDefaultActions(C, Args, Inputs, Actions);
-}
-
-void Driver::BuildDefaultActions(Compilation &C, DerivedArgList &Args,
-                                 const InputList &Inputs,
-                                 ActionList &Actions) const {
-
   bool UseNewOffloadingDriver =
       C.isOffloadingHostKind(Action::OFK_OpenMP) ||
       C.isOffloadingHostKind(Action::OFK_SYCL) ||
@@ -4680,12 +4649,6 @@ void Driver::BuildDefaultActions(Compilation &C, DerivedArgList &Args,
   Args.ClaimAllArgs(options::OPT_cl_ignored_Group);
 }
 
-void Driver::BuildDriverManagedModuleBuildActions(
-    Compilation &C, llvm::opt::DerivedArgList &Args, const InputList &Inputs,
-    ActionList &Actions) const {
-  Diags.Report(diag::remark_performing_driver_managed_module_build);
-}
-
 /// Returns the canonical name for the offloading architecture when using a HIP
 /// or CUDA architecture.
 static StringRef getCanonicalArchString(Compilation &C,
@@ -5440,6 +5403,12 @@ void Driver::BuildJobs(Compilation &C) const {
       }
     }
   }
+  if (C.getArgs().hasFlag(options::OPT_fmodules_driver,
+                          options::OPT_fno_modules_driver, false)) {
+    auto Success = modules::performDriverModuleBuild(C, C.getDriver().Diags);
+    if (!Success)
+      return;
+  }
 }
 
 namespace {
diff --git a/clang/lib/Driver/ModulesDriver.cpp b/clang/lib/Driver/ModulesDriver.cpp
new file mode 100644
index 0000000000000..e21d7fc55a168
--- /dev/null
+++ b/clang/lib/Driver/ModulesDriver.cpp
@@ -0,0 +1,1477 @@
+//===- DependencyScanner.cpp - Module dependency discovery ----------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Driver/ModulesDriver.h"
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/DiagnosticDriver.h"
+#include "clang/Driver/Compilation.h"
+#include "clang/Driver/Driver.h"
+#include "clang/Driver/InputInfo.h"
+#include "clang/Driver/Job.h"
+#include "clang/Driver/Tool.h"
+#include "clang/Driver/Types.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Tooling/DependencyScanning/DependencyScanningTool.h"
+#include "clang/Tooling/DependencyScanning/DependencyScanningWorker.h"
+#include "clang/Tooling/DependencyScanning/ModuleDepCollector.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/DepthFirstIterator.h"
+#include "llvm/ADT/DirectedGraph.h"
+#include "llvm/ADT/PostOrderIterator.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/TypeSwitch.h"
+#include "llvm/Option/ArgList.h"
+#include "llvm/Option/Option.h"
+#include "llvm/Support/Allocator.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/GraphWriter.h"
+#include "llvm/Support/JSON.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/ThreadPool.h"
+#include "llvm/TargetParser/Host.h"
+#include <atomic>
+#include <memory>
+#include <optional>
+#include <string>
+#include <utility>
+#include <vector>
+
+using namespace clang;
+using namespace clang::driver;
+using namespace llvm;
+using namespace llvm::opt;
+
+namespace clang::tooling {
+namespace deps = dependencies;
+} // namespace clang::tooling
+
+using OwnedJobList = SmallVector<std::unique_ptr<Command>, 4>;
+
+//===----------------------------------------------------------------------===//
+// Check: Enable -fmodules-driver implicitly
+//===----------------------------------------------------------------------===//
+
+namespace clang::driver::modules {
+
+/// Returns true if any input is a `.cppm` file.
+static bool hasCXXModuleInputType(const InputList &Inputs) {
+  const auto IsTypeCXXModule = [](const auto &Input) -> bool {
+    const auto TypeID = Input.first;
+    return (TypeID == types::TY_CXXModule);
+  };
+  return llvm::any_of(Inputs, IsTypeCXXModule);
+}
+
+/// Scans the leading lines of the C++ source inputs to detect C++20 module
+/// usage.
+///
+/// \returns true if module usage is detected, false otherwise, or an error on
+/// failure to read the input source.
+static llvm::ErrorOr<bool>
+ScanInputsForCXX20ModulesUsage(const InputList &Inputs,
+                               llvm::vfs::FileSystem &VFS,
+                               DiagnosticsEngine &Diags) {
+  const auto CXXInputs = llvm::make_filter_range(
+      Inputs, [](const auto &Input) { return types::isCXX(Input.first); });
+  for (const auto &Input : CXXInputs) {
+    StringRef Filename = Input.second->getSpelling();
+    auto ErrOrBuffer = VFS.getBufferForFile(Filename);
+    if (!ErrOrBuffer)
+      return ErrOrBuffer.getError();
+    const auto Buffer = std::move(*ErrOrBuffer);
+
+    if (scanInputForCXX20ModulesUsage(Buffer->getBuffer())) {
+      Diags.Report(diag::remark_found_cxx20_module_usage) << Filename;
+      return true;
+    }
+  }
+  return false;
+}
+
+/// Checks if the -fmodules-driver feature should be implicitly enabled for this
+/// compilation.
+///
+/// The -fmodules-driver feature should be implicitly enabled iff (1) any input
+/// makes used of C++20 named modules; and (2) there are more than two source
+/// input files.
+///
+/// \returns true if the -fmodules-driver feature should be enabled, false
+/// otherwise.
+bool shouldEnableModulesDriver(const InputList &Inputs,
+                               llvm::vfs::FileSystem &VFS,
+                               DiagnosticsEngine &Diags) {
+  if (Inputs.size() < 2)
+    return false;
+
+  bool UsesCXXModules = hasCXXModuleInputType(Inputs);
+  if (UsesCXXModules)
+    return true;
+
+  const auto ErrOrScanResult =
+      ScanInputsForCXX20ModulesUsage(Inputs, VFS, Diags);
+  if (!ErrOrScanResult) {
+    Diags.Report(diag::err_cannot_open_file)
+        << ErrOrScanResult.getError().message();
+  }
+  return *ErrOrScanResult;
+}
+
+/// Builds the a C++ named module input for \c InputFile and adds it to \c Args.
+static void addCXXModuleInput(InputList &Inputs, DerivedArgList &Args,
+                              const OptTable &Opts, StringRef InputFile) {
+  Arg *A = new Arg(Opts.getOption(options::OPT_INPUT), InputFile,
+                   Args.getBaseArgs().MakeIndex(InputFile),
+                   Args.getBaseArgs().MakeArgString(InputFile));
+  Args.AddSynthesizedArg(A);
+  A->claim();
+  Inputs.push_back(std::make_pair(types::TY_CXXModule, A));
+}
+
+/// Parses the std modules manifest and builds the inputs for the discovered
+/// std modules.
+///
+/// \returns true if the modules were added, false failure to read/parse the
+/// manifest (with diagnostics reported using the drivers DiagnosticEngine).
+bool ensureNamedModuleStdLibraryInputs(Compilation &C, InputList &Inputs) {
+  const auto &Driver = C.getDriver();
+  auto &Diags = Driver.getDiags();
+
+  const auto ManifestPath =
+      Driver.GetStdModuleManifestPath(C, C.getDefaultToolChain());
+  Diags.Report(diag::remark_std_module_manifest_path) << ManifestPath;
+  if (ManifestPath == "<NOT PRESENT>")
+    return false;
+
+  llvm::SmallString<256> Mani...
[truncated]

… builds

With -fmodules-driver enabled, the Clang driver provides native
support for:

- Named module imports defined in other source files on the command
  line
- Standard library imports (import std; and import std.compat;)
- Clang modules discovered via module map files

Regular translation units can import both Clang modules and C++20
named modules. Importing a Clang module into a C++20 named
module interface unit, or vice versa, is not supported by this patch.
Because Standard library modules are not available in the CI, this
removes them until a proper way to test them is found.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang:driver 'clang' and 'clang++' user-facing binaries. Not 'clang-cl' clang:frontend Language frontend issues, e.g. anything involving "Sema" clang Clang issues not falling into any other category
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants