Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions clang/include/clang/Basic/DiagnosticDriverKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -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">,
Expand Down
36 changes: 4 additions & 32 deletions clang/include/clang/Driver/Driver.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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
Expand Down
3 changes: 3 additions & 0 deletions clang/include/clang/Driver/Job.h
Original file line number Diff line number Diff line change
Expand Up @@ -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; }
Expand Down Expand Up @@ -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(); }
Expand Down
60 changes: 60 additions & 0 deletions clang/include/clang/Driver/ModulesDriver.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
//===- 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"

namespace llvm {
namespace vfs {
class FileSystem;
} // namespace vfs
} // namespace llvm

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(clang::driver::Compilation &C,
InputList &Inputs);

/// Modifies the compilations JobList to support Clang and C++20 named module
/// imports between source files, importing Standard library modules
bool performDriverModuleBuild(clang::driver::Compilation &C,
clang::DiagnosticsEngine &Diags);

} // namespace clang::driver::modules

#endif
6 changes: 6 additions & 0 deletions clang/include/clang/Driver/Options.td
Original file line number Diff line number Diff line change
Expand Up @@ -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>;
Expand Down
2 changes: 2 additions & 0 deletions clang/lib/Driver/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ add_clang_library(clangDriver
Driver.cpp
DriverOptions.cpp
Job.cpp
ModulesDriver.cpp
Multilib.cpp
MultilibBuilder.cpp
OffloadBundler.cpp
Expand Down Expand Up @@ -98,6 +99,7 @@ add_clang_library(clangDriver

LINK_LIBS
clangBasic
clangDependencyScanning
clangLex
${system_libs}
)
97 changes: 33 additions & 64 deletions clang/lib/Driver/Driver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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");
Expand All @@ -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) ||
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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 {
Expand Down
Loading
Loading