[clang] 4c4ff00 - [C++20][Modules][Driver][HU 2/N] Add fmodule-header, fmodule-header=
Iain Sandoe via cfe-commits
cfe-commits at lists.llvm.org
Fri Apr 22 06:15:02 PDT 2022
Author: Iain Sandoe
Date: 2022-04-22T14:14:19+01:00
New Revision: 4c4ff004a2702b9b7538efd569bb621a5efac8f3
URL: https://github.com/llvm/llvm-project/commit/4c4ff004a2702b9b7538efd569bb621a5efac8f3
DIFF: https://github.com/llvm/llvm-project/commit/4c4ff004a2702b9b7538efd569bb621a5efac8f3.diff
LOG: [C++20][Modules][Driver][HU 2/N] Add fmodule-header, fmodule-header=
These command-line flags are alternates to providing the -x
c++-*-header indicators that we are building a header unit.
Act on fmodule-header= for headers on the c/l:
If we have x.hh -fmodule-header, then we should treat that header
as a header unit input (equivalent to -xc++-header-unit-header x.hh).
Likewise, for fmodule-header={user,system} the source should be now
recognised as a header unit input (since this can affect the job list
that we need).
It's not practical to recognise a header without any suffix so
-fmodule-header=system foo isn't going to happen. Although
-fmodule-header=system foo.hh will work OK. However we can make it
work if the user indicates that the item without a suffix is a valid
header. (so -fmodule-header=system -xc++-header vector)
Differential Revision: https://reviews.llvm.org/D121589
Added:
clang/test/Driver/cxx20-header-units-02.cpp
Modified:
clang/docs/ClangCommandLineReference.rst
clang/include/clang/Driver/Driver.h
clang/include/clang/Driver/Options.td
clang/lib/Driver/Driver.cpp
Removed:
################################################################################
diff --git a/clang/docs/ClangCommandLineReference.rst b/clang/docs/ClangCommandLineReference.rst
index 1a0e4805bc263..33f9a55f62484 100644
--- a/clang/docs/ClangCommandLineReference.rst
+++ b/clang/docs/ClangCommandLineReference.rst
@@ -1176,6 +1176,14 @@ Validate the system headers that a module depends on when loading the module
Specify the prebuilt module path
+.. option:: -fmodule-header
+
+Build a C++20 header unit from a header specified.
+
+.. option:: -fmodule-header=\[user,system\]
+
+Build a C++20 header unit, but search for the header in the user or system header search paths respectively.
+
.. option:: --hip-path=<arg>
HIP runtime installation path, used for finding HIP version and adding HIP include path.
diff --git a/clang/include/clang/Driver/Driver.h b/clang/include/clang/Driver/Driver.h
index b33b64cd9e6a2..f68f281f0e931 100644
--- a/clang/include/clang/Driver/Driver.h
+++ b/clang/include/clang/Driver/Driver.h
@@ -56,6 +56,16 @@ enum LTOKind {
LTOK_Unknown
};
+/// Whether headers used to construct C++20 module units should be looked
+/// up by the path supplied on the command line, or in the user or system
+/// search paths.
+enum ModuleHeaderMode {
+ HeaderMode_None,
+ HeaderMode_Default,
+ HeaderMode_User,
+ HeaderMode_System
+};
+
/// Driver - Encapsulate logic for constructing compilation processes
/// from a set of gcc-driver-like command line arguments.
class Driver {
@@ -84,6 +94,13 @@ class Driver {
EmbedBitcode
} BitcodeEmbed;
+ /// Header unit mode set by -fmodule-header={user,system}.
+ ModuleHeaderMode CXX20HeaderType;
+
+ /// Set if we should process inputs and jobs with C++20 module
+ /// interpretation.
+ bool ModulesModeCXX20;
+
/// LTO mode selected via -f(no-)?lto(=.*)? options.
LTOKind LTOMode;
@@ -574,6 +591,12 @@ class Driver {
/// ShouldEmitStaticLibrary - Should the linker emit a static library.
bool ShouldEmitStaticLibrary(const llvm::opt::ArgList &Args) const;
+ /// Returns true if the user has indicated a C++20 header unit mode.
+ bool hasHeaderMode() const { return CXX20HeaderType != HeaderMode_None; }
+
+ /// Get the mode for handling headers as set by fmodule-header{=}.
+ ModuleHeaderMode getModuleHeaderMode() const { return CXX20HeaderType; }
+
/// Returns true if we are performing any kind of LTO.
bool isUsingLTO(bool IsOffload = false) const {
return getLTOMode(IsOffload) != LTOK_None;
diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
index 8c013e3fe5b19..8e3611cff2d63 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -2296,6 +2296,11 @@ defm implicit_modules : BoolFOption<"implicit-modules",
NegFlag<SetFalse, [CC1Option]>, PosFlag<SetTrue>, BothFlags<[NoXarchOption,CoreOption]>>;
def fretain_comments_from_system_headers : Flag<["-"], "fretain-comments-from-system-headers">, Group<f_Group>, Flags<[CC1Option]>,
MarshallingInfoFlag<LangOpts<"RetainCommentsFromSystemHeaders">>;
+def fmodule_header : Flag <["-"], "fmodule-header">, Group<f_Group>,
+ Flags<[NoXarchOption]>, HelpText<"Build a C++20 Header Unit from a header.">;
+def fmodule_header_EQ : Joined<["-"], "fmodule-header=">, Group<f_Group>,
+ Flags<[NoXarchOption]>, MetaVarName<"<kind>">,
+ HelpText<"Build a C++20 Header Unit from a header that should be found in the user (fmodule-header=user) or system (fmodule-header=system) search path.">;
def fno_knr_functions : Flag<["-"], "fno-knr-functions">, Group<f_Group>,
MarshallingInfoFlag<LangOpts<"DisableKNRFunctions">>,
diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp
index 6fa95a8834a2c..0da079b1deb38 100644
--- a/clang/lib/Driver/Driver.cpp
+++ b/clang/lib/Driver/Driver.cpp
@@ -191,13 +191,14 @@ Driver::Driver(StringRef ClangExecutable, StringRef TargetTriple,
DiagnosticsEngine &Diags, std::string Title,
IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS)
: Diags(Diags), VFS(std::move(VFS)), Mode(GCCMode),
- SaveTemps(SaveTempsNone), BitcodeEmbed(EmbedNone), LTOMode(LTOK_None),
- ClangExecutable(ClangExecutable), SysRoot(DEFAULT_SYSROOT),
- DriverTitle(Title), CCCPrintBindings(false), CCPrintOptions(false),
- CCPrintHeaders(false), CCLogDiagnostics(false), CCGenDiagnostics(false),
- CCPrintProcessStats(false), TargetTriple(TargetTriple), Saver(Alloc),
- CheckInputsExist(true), GenReproducer(false),
- SuppressMissingInputWarning(false) {
+ SaveTemps(SaveTempsNone), BitcodeEmbed(EmbedNone),
+ CXX20HeaderType(HeaderMode_None), ModulesModeCXX20(false),
+ LTOMode(LTOK_None), ClangExecutable(ClangExecutable),
+ SysRoot(DEFAULT_SYSROOT), DriverTitle(Title), CCCPrintBindings(false),
+ CCPrintOptions(false), CCPrintHeaders(false), CCLogDiagnostics(false),
+ CCGenDiagnostics(false), CCPrintProcessStats(false),
+ TargetTriple(TargetTriple), Saver(Alloc), CheckInputsExist(true),
+ GenReproducer(false), SuppressMissingInputWarning(false) {
// Provide a sane fallback if no VFS is specified.
if (!this->VFS)
this->VFS = llvm::vfs::getRealFileSystem();
@@ -337,9 +338,13 @@ phases::ID Driver::getFinalPhase(const DerivedArgList &DAL,
CCGenDiagnostics) {
FinalPhase = phases::Preprocess;
- // --precompile only runs up to precompilation.
+ // --precompile only runs up to precompilation.
+ // Options that cause the output of C++20 compiled module interfaces or
+ // header units have the same effect.
} else if ((PhaseArg = DAL.getLastArg(options::OPT__precompile)) ||
- (PhaseArg = DAL.getLastArg(options::OPT_extract_api))) {
+ (PhaseArg = DAL.getLastArg(options::OPT_extract_api)) ||
+ (PhaseArg = DAL.getLastArg(options::OPT_fmodule_header,
+ options::OPT_fmodule_header_EQ))) {
FinalPhase = phases::Precompile;
// -{fsyntax-only,-analyze,emit-ast} only run up to the compiler.
} else if ((PhaseArg = DAL.getLastArg(options::OPT_fsyntax_only)) ||
@@ -1251,6 +1256,37 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) {
BitcodeEmbed = static_cast<BitcodeEmbedMode>(Model);
}
+ // Setting up the jobs for some precompile cases depends on whether we are
+ // treating them as PCH, implicit modules or C++20 ones.
+ // TODO: inferring the mode like this seems fragile (it meets the objective
+ // of not requiring anything new for operation, however).
+ const Arg *Std = Args.getLastArg(options::OPT_std_EQ);
+ ModulesModeCXX20 =
+ !Args.hasArg(options::OPT_fmodules) && Std &&
+ (Std->containsValue("c++20") || Std->containsValue("c++2b") ||
+ Std->containsValue("c++2a") || Std->containsValue("c++latest"));
+
+ // Process -fmodule-header{=} flags.
+ if (Arg *A = Args.getLastArg(options::OPT_fmodule_header_EQ,
+ options::OPT_fmodule_header)) {
+ // These flags force C++20 handling of headers.
+ ModulesModeCXX20 = true;
+ if (A->getOption().matches(options::OPT_fmodule_header))
+ CXX20HeaderType = HeaderMode_Default;
+ else {
+ StringRef ArgName = A->getValue();
+ unsigned Kind = llvm::StringSwitch<unsigned>(ArgName)
+ .Case("user", HeaderMode_User)
+ .Case("system", HeaderMode_System)
+ .Default(~0U);
+ if (Kind == ~0U) {
+ Diags.Report(diag::err_drv_invalid_value)
+ << A->getAsString(Args) << ArgName;
+ } else
+ CXX20HeaderType = static_cast<ModuleHeaderMode>(Kind);
+ }
+ }
+
std::unique_ptr<llvm::opt::InputArgList> UArgs =
std::make_unique<InputArgList>(std::move(Args));
@@ -2220,8 +2256,11 @@ bool Driver::DiagnoseInputExistence(const DerivedArgList &Args, StringRef Value,
return true;
// If it's a header to be found in the system or user search path, then defer
- // complaints about its absence until those searches can be done.
- if (Ty == types::TY_CXXSHeader || Ty == types::TY_CXXUHeader)
+ // complaints about its absence until those searches can be done. When we
+ // are definitely processing headers for C++20 header units, extend this to
+ // allow the user to put "-fmodule-header -xc++-header vector" for example.
+ if (Ty == types::TY_CXXSHeader || Ty == types::TY_CXXUHeader ||
+ (ModulesModeCXX20 && Ty == types::TY_CXXHeader))
return true;
if (getVFS().exists(Value))
@@ -2287,6 +2326,21 @@ bool Driver::DiagnoseInputExistence(const DerivedArgList &Args, StringRef Value,
return false;
}
+// Get the C++20 Header Unit type corresponding to the input type.
+static types::ID CXXHeaderUnitType(ModuleHeaderMode HM) {
+ switch (HM) {
+ case HeaderMode_User:
+ return types::TY_CXXUHeader;
+ case HeaderMode_System:
+ return types::TY_CXXSHeader;
+ case HeaderMode_Default:
+ break;
+ case HeaderMode_None:
+ llvm_unreachable("should not be called in this case");
+ }
+ return types::TY_CXXHUHeader;
+}
+
// Construct a the list of inputs and their types.
void Driver::BuildInputs(const ToolChain &TC, DerivedArgList &Args,
InputList &Inputs) const {
@@ -2406,6 +2460,11 @@ void Driver::BuildInputs(const ToolChain &TC, DerivedArgList &Args,
else if (Args.hasArg(options::OPT_ObjCXX))
Ty = types::TY_ObjCXX;
}
+
+ // Disambiguate headers that are meant to be header units from those
+ // intended to be PCH.
+ if (Ty == types::TY_CXXHeader && hasHeaderMode())
+ Ty = CXXHeaderUnitType(CXX20HeaderType);
} else {
assert(InputTypeArg && "InputType set w/o InputTypeArg");
if (!InputTypeArg->getOption().matches(options::OPT_x)) {
@@ -2457,6 +2516,11 @@ void Driver::BuildInputs(const ToolChain &TC, DerivedArgList &Args,
Diag(clang::diag::err_drv_unknown_language) << A->getValue();
InputType = types::TY_Object;
}
+
+ // If the user has put -fmodule-header{,=} then we treat C++ headers as
+ // header unit inputs. So we 'promote' -xc++-header appropriately.
+ if (InputType == types::TY_CXXHeader && hasHeaderMode())
+ InputType = CXXHeaderUnitType(CXX20HeaderType);
} else if (A->getOption().getID() == options::OPT_U) {
assert(A->getNumValues() == 1 && "The /U option has one value.");
StringRef Val = A->getValue(0);
diff --git a/clang/test/Driver/cxx20-header-units-02.cpp b/clang/test/Driver/cxx20-header-units-02.cpp
new file mode 100644
index 0000000000000..aab999cda2276
--- /dev/null
+++ b/clang/test/Driver/cxx20-header-units-02.cpp
@@ -0,0 +1,32 @@
+// Test user-facing command line options to generate C++20 header units.
+
+// RUN: %clang -### -std=c++20 -fmodule-header=user foo.hh 2>&1 | \
+// RUN: FileCheck -check-prefix=CHECK-USER %s
+
+// RUN: %clang -### -std=c++20 -fmodule-header=system foo.hh 2>&1 | \
+// RUN: FileCheck -check-prefix=CHECK-SYS1 %s
+
+// RUN: %clang -### -std=c++20 -fmodule-header=system \
+// RUN: -xc++-system-header vector 2>&1 | FileCheck -check-prefix=CHECK-SYS2 %s
+
+// RUN: %clang -### -std=c++20 -fmodule-header=system \
+// RUN: -xc++-header vector 2>&1 | FileCheck -check-prefix=CHECK-SYS2 %s
+
+// RUN: %clang -### -std=c++20 -fmodule-header %/S/Inputs/header-unit-01.hh \
+// RUN: 2>&1 | FileCheck -check-prefix=CHECK-ABS %s -DTDIR=%/S/Inputs
+
+// CHECK-USER: "-emit-header-unit"
+// CHECK-USER-SAME: "-o" "foo.pcm"
+// CHECK-USER-SAME: "-x" "c++-user-header" "foo.hh"
+
+// CHECK-SYS1: "-emit-header-unit"
+// CHECK-SYS1-SAME: "-o" "foo.pcm"
+// CHECK-SYS1-SAME: "-x" "c++-system-header" "foo.hh"
+
+// CHECK-SYS2: "-emit-header-unit"
+// CHECK-SYS2-SAME: "-o" "vector.pcm"
+// CHECK-SYS2-SAME: "-x" "c++-system-header" "vector"
+
+// CHECK-ABS: "-emit-header-unit"
+// CHECK-ABS-SAME: "-o" "header-unit-01.pcm"
+// CHECK-ABS-SAME: "-x" "c++-header-unit-header" "[[TDIR]]/header-unit-01.hh"
More information about the cfe-commits
mailing list