forked from OSchip/llvm-project
[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
This commit is contained in:
parent
fc760c0260
commit
4c4ff004a2
|
@ -1176,6 +1176,14 @@ Validate the system headers that a module depends on when loading the module
|
||||||
|
|
||||||
Specify the prebuilt module path
|
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>
|
.. option:: --hip-path=<arg>
|
||||||
|
|
||||||
HIP runtime installation path, used for finding HIP version and adding HIP include path.
|
HIP runtime installation path, used for finding HIP version and adding HIP include path.
|
||||||
|
|
|
@ -56,6 +56,16 @@ enum LTOKind {
|
||||||
LTOK_Unknown
|
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
|
/// Driver - Encapsulate logic for constructing compilation processes
|
||||||
/// from a set of gcc-driver-like command line arguments.
|
/// from a set of gcc-driver-like command line arguments.
|
||||||
class Driver {
|
class Driver {
|
||||||
|
@ -84,6 +94,13 @@ class Driver {
|
||||||
EmbedBitcode
|
EmbedBitcode
|
||||||
} BitcodeEmbed;
|
} 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.
|
/// LTO mode selected via -f(no-)?lto(=.*)? options.
|
||||||
LTOKind LTOMode;
|
LTOKind LTOMode;
|
||||||
|
|
||||||
|
@ -574,6 +591,12 @@ public:
|
||||||
/// ShouldEmitStaticLibrary - Should the linker emit a static library.
|
/// ShouldEmitStaticLibrary - Should the linker emit a static library.
|
||||||
bool ShouldEmitStaticLibrary(const llvm::opt::ArgList &Args) const;
|
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.
|
/// Returns true if we are performing any kind of LTO.
|
||||||
bool isUsingLTO(bool IsOffload = false) const {
|
bool isUsingLTO(bool IsOffload = false) const {
|
||||||
return getLTOMode(IsOffload) != LTOK_None;
|
return getLTOMode(IsOffload) != LTOK_None;
|
||||||
|
|
|
@ -2296,6 +2296,11 @@ defm implicit_modules : BoolFOption<"implicit-modules",
|
||||||
NegFlag<SetFalse, [CC1Option]>, PosFlag<SetTrue>, BothFlags<[NoXarchOption,CoreOption]>>;
|
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]>,
|
def fretain_comments_from_system_headers : Flag<["-"], "fretain-comments-from-system-headers">, Group<f_Group>, Flags<[CC1Option]>,
|
||||||
MarshallingInfoFlag<LangOpts<"RetainCommentsFromSystemHeaders">>;
|
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>,
|
def fno_knr_functions : Flag<["-"], "fno-knr-functions">, Group<f_Group>,
|
||||||
MarshallingInfoFlag<LangOpts<"DisableKNRFunctions">>,
|
MarshallingInfoFlag<LangOpts<"DisableKNRFunctions">>,
|
||||||
|
|
|
@ -191,13 +191,14 @@ Driver::Driver(StringRef ClangExecutable, StringRef TargetTriple,
|
||||||
DiagnosticsEngine &Diags, std::string Title,
|
DiagnosticsEngine &Diags, std::string Title,
|
||||||
IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS)
|
IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS)
|
||||||
: Diags(Diags), VFS(std::move(VFS)), Mode(GCCMode),
|
: Diags(Diags), VFS(std::move(VFS)), Mode(GCCMode),
|
||||||
SaveTemps(SaveTempsNone), BitcodeEmbed(EmbedNone), LTOMode(LTOK_None),
|
SaveTemps(SaveTempsNone), BitcodeEmbed(EmbedNone),
|
||||||
ClangExecutable(ClangExecutable), SysRoot(DEFAULT_SYSROOT),
|
CXX20HeaderType(HeaderMode_None), ModulesModeCXX20(false),
|
||||||
DriverTitle(Title), CCCPrintBindings(false), CCPrintOptions(false),
|
LTOMode(LTOK_None), ClangExecutable(ClangExecutable),
|
||||||
CCPrintHeaders(false), CCLogDiagnostics(false), CCGenDiagnostics(false),
|
SysRoot(DEFAULT_SYSROOT), DriverTitle(Title), CCCPrintBindings(false),
|
||||||
CCPrintProcessStats(false), TargetTriple(TargetTriple), Saver(Alloc),
|
CCPrintOptions(false), CCPrintHeaders(false), CCLogDiagnostics(false),
|
||||||
CheckInputsExist(true), GenReproducer(false),
|
CCGenDiagnostics(false), CCPrintProcessStats(false),
|
||||||
SuppressMissingInputWarning(false) {
|
TargetTriple(TargetTriple), Saver(Alloc), CheckInputsExist(true),
|
||||||
|
GenReproducer(false), SuppressMissingInputWarning(false) {
|
||||||
// Provide a sane fallback if no VFS is specified.
|
// Provide a sane fallback if no VFS is specified.
|
||||||
if (!this->VFS)
|
if (!this->VFS)
|
||||||
this->VFS = llvm::vfs::getRealFileSystem();
|
this->VFS = llvm::vfs::getRealFileSystem();
|
||||||
|
@ -337,9 +338,13 @@ phases::ID Driver::getFinalPhase(const DerivedArgList &DAL,
|
||||||
CCGenDiagnostics) {
|
CCGenDiagnostics) {
|
||||||
FinalPhase = phases::Preprocess;
|
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)) ||
|
} 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;
|
FinalPhase = phases::Precompile;
|
||||||
// -{fsyntax-only,-analyze,emit-ast} only run up to the compiler.
|
// -{fsyntax-only,-analyze,emit-ast} only run up to the compiler.
|
||||||
} else if ((PhaseArg = DAL.getLastArg(options::OPT_fsyntax_only)) ||
|
} 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);
|
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::unique_ptr<llvm::opt::InputArgList> UArgs =
|
||||||
std::make_unique<InputArgList>(std::move(Args));
|
std::make_unique<InputArgList>(std::move(Args));
|
||||||
|
|
||||||
|
@ -2220,8 +2256,11 @@ bool Driver::DiagnoseInputExistence(const DerivedArgList &Args, StringRef Value,
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
// If it's a header to be found in the system or user search path, then defer
|
// 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.
|
// complaints about its absence until those searches can be done. When we
|
||||||
if (Ty == types::TY_CXXSHeader || Ty == types::TY_CXXUHeader)
|
// 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;
|
return true;
|
||||||
|
|
||||||
if (getVFS().exists(Value))
|
if (getVFS().exists(Value))
|
||||||
|
@ -2287,6 +2326,21 @@ bool Driver::DiagnoseInputExistence(const DerivedArgList &Args, StringRef Value,
|
||||||
return false;
|
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.
|
// Construct a the list of inputs and their types.
|
||||||
void Driver::BuildInputs(const ToolChain &TC, DerivedArgList &Args,
|
void Driver::BuildInputs(const ToolChain &TC, DerivedArgList &Args,
|
||||||
InputList &Inputs) const {
|
InputList &Inputs) const {
|
||||||
|
@ -2406,6 +2460,11 @@ void Driver::BuildInputs(const ToolChain &TC, DerivedArgList &Args,
|
||||||
else if (Args.hasArg(options::OPT_ObjCXX))
|
else if (Args.hasArg(options::OPT_ObjCXX))
|
||||||
Ty = types::TY_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 {
|
} else {
|
||||||
assert(InputTypeArg && "InputType set w/o InputTypeArg");
|
assert(InputTypeArg && "InputType set w/o InputTypeArg");
|
||||||
if (!InputTypeArg->getOption().matches(options::OPT_x)) {
|
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();
|
Diag(clang::diag::err_drv_unknown_language) << A->getValue();
|
||||||
InputType = types::TY_Object;
|
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) {
|
} else if (A->getOption().getID() == options::OPT_U) {
|
||||||
assert(A->getNumValues() == 1 && "The /U option has one value.");
|
assert(A->getNumValues() == 1 && "The /U option has one value.");
|
||||||
StringRef Val = A->getValue(0);
|
StringRef Val = A->getValue(0);
|
||||||
|
|
|
@ -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"
|
Loading…
Reference in New Issue