[clang] d748908 - [clang][cli] Round-trip the whole CompilerInvocation
Jan Svoboda via cfe-commits
cfe-commits at lists.llvm.org
Thu Feb 25 02:03:16 PST 2021
Author: Jan Svoboda
Date: 2021-02-25T11:02:49+01:00
New Revision: d748908fa02b11c7840a7f03c7a52223126bdba9
URL: https://github.com/llvm/llvm-project/commit/d748908fa02b11c7840a7f03c7a52223126bdba9
DIFF: https://github.com/llvm/llvm-project/commit/d748908fa02b11c7840a7f03c7a52223126bdba9.diff
LOG: [clang][cli] Round-trip the whole CompilerInvocation
Finally, this patch moves from round-tripping one `CompilerInvocation` at a time to round-tripping the invocation as a whole.
This patch includes only the code required to make round-tripping the whole invocation work. More cleanups will be done in a follow-up patch.
Depends on D96847, D97041 & D97042.
Reviewed By: dexonsmith
Differential Revision: https://reviews.llvm.org/D96280
Added:
Modified:
clang/include/clang/Basic/DiagnosticDriverKinds.td
clang/include/clang/Frontend/CompilerInvocation.h
clang/lib/Frontend/CompilerInvocation.cpp
clang/test/Frontend/round-trip-cc1-args.c
Removed:
################################################################################
diff --git a/clang/include/clang/Basic/DiagnosticDriverKinds.td b/clang/include/clang/Basic/DiagnosticDriverKinds.td
index 2440240608fd..6f50774d8f1c 100644
--- a/clang/include/clang/Basic/DiagnosticDriverKinds.td
+++ b/clang/include/clang/Basic/DiagnosticDriverKinds.td
@@ -532,10 +532,10 @@ def err_drv_invalid_object_mode : Error<"OBJECT_MODE setting %0 is not recognize
def err_aix_default_altivec_abi : Error<
"The default Altivec ABI on AIX is not yet supported, use '-mabi=vec-extabi' for the extended Altivec ABI">;
-def note_cc1_round_trip_original : Note<"Original arguments in %0 round-trip: %1">;
-def note_cc1_round_trip_generated : Note<"Generated arguments #%1 in %0 round-trip: %2">;
-def remark_cc1_round_trip_generated : Remark<"Generated arguments #%1 in %0 round-trip: %2">, InGroup<RoundTripCC1Args>;
-def err_cc1_round_trip_fail_then_ok : Error<"Original arguments parse failed, then succeeded in %0 round-trip">;
-def err_cc1_round_trip_ok_then_fail : Error<"Generated arguments parse failed in %0 round-trip">;
-def err_cc1_round_trip_mismatch : Error<"Generated arguments do not match in %0 round-trip">;
+def note_cc1_round_trip_original : Note<"Original arguments in round-trip: %0">;
+def note_cc1_round_trip_generated : Note<"Generated arguments #%0 in round-trip: %1">;
+def remark_cc1_round_trip_generated : Remark<"Generated arguments #%0 in round-trip: %1">, InGroup<RoundTripCC1Args>;
+def err_cc1_round_trip_fail_then_ok : Error<"Original arguments parse failed, then succeeded in round-trip">;
+def err_cc1_round_trip_ok_then_fail : Error<"Generated arguments parse failed in round-trip">;
+def err_cc1_round_trip_mismatch : Error<"Generated arguments do not match in round-trip">;
}
diff --git a/clang/include/clang/Frontend/CompilerInvocation.h b/clang/include/clang/Frontend/CompilerInvocation.h
index 0ecb586bcf8c..cd3780d9f454 100644
--- a/clang/include/clang/Frontend/CompilerInvocation.h
+++ b/clang/include/clang/Frontend/CompilerInvocation.h
@@ -239,6 +239,10 @@ class CompilerInvocation : public CompilerInvocationBase {
/// @}
private:
+ static bool CreateFromArgsImpl(CompilerInvocation &Res,
+ ArrayRef<const char *> CommandLineArgs,
+ DiagnosticsEngine &Diags, const char *Argv0);
+
/// Parse command line options from DiagnosticOptions.
static bool ParseDiagnosticArgsRoundTrip(CompilerInvocation &Res,
DiagnosticOptions &Opts,
diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp
index 20ac5109084f..828e9c9cc6fc 100644
--- a/clang/lib/Frontend/CompilerInvocation.cpp
+++ b/clang/lib/Frontend/CompilerInvocation.cpp
@@ -423,9 +423,11 @@ static T extractMaskValue(T KeyPath) {
static const StringRef GetInputKindName(InputKind IK);
-static void FixupInvocation(CompilerInvocation &Invocation,
- DiagnosticsEngine &Diags, const InputArgList &Args,
+static bool FixupInvocation(CompilerInvocation &Invocation,
+ DiagnosticsEngine &Diags, const ArgList &Args,
InputKind IK) {
+ unsigned NumErrorsBefore = Diags.getNumErrors();
+
LangOptions &LangOpts = *Invocation.getLangOpts();
CodeGenOptions &CodeGenOpts = Invocation.getCodeGenOpts();
TargetOptions &TargetOpts = Invocation.getTargetOpts();
@@ -502,6 +504,8 @@ static void FixupInvocation(CompilerInvocation &Invocation,
Diags.Report(diag::err_drv_argument_only_allowed_with)
<< Args.getLastArg(OPT_fprofile_remapping_file_EQ)->getAsString(Args)
<< "-fno-legacy-pass-manager";
+
+ return Diags.getNumErrors() == NumErrorsBefore;
}
//===----------------------------------------------------------------------===//
@@ -569,27 +573,29 @@ static void GenerateArg(SmallVectorImpl<const char *> &Args,
Opt.getKind(), 0, Value);
}
-// Parse subset of command line arguments into a member of CompilerInvocation.
-using ParseFn = llvm::function_ref<bool(CompilerInvocation &, ArgList &,
- DiagnosticsEngine &)>;
+// Parse command line arguments into CompilerInvocation.
+using ParseFn =
+ llvm::function_ref<bool(CompilerInvocation &, ArrayRef<const char *>,
+ DiagnosticsEngine &, const char *)>;
-// Generate part of command line arguments from a member of CompilerInvocation.
+// Generate command line arguments from CompilerInvocation.
using GenerateFn = llvm::function_ref<void(
CompilerInvocation &, SmallVectorImpl<const char *> &,
CompilerInvocation::StringAllocator)>;
-// Swap between dummy/real instance of a CompilerInvocation member.
-using SwapOptsFn = llvm::function_ref<void(CompilerInvocation &)>;
-
-// Performs round-trip of command line arguments if OriginalArgs contain
-// "-round-trip-args". Effectively runs the Parse function for a part of
-// CompilerInvocation on command line arguments that were already once parsed
-// and generated. This is used to check the Generate function produces arguments
-// that are semantically equivalent to those that were used to create
-// CompilerInvocation.
-static bool RoundTrip(ParseFn Parse, GenerateFn Generate, SwapOptsFn SwapOpts,
- CompilerInvocation &Res, ArgList &OriginalArgs,
- DiagnosticsEngine &Diags, StringRef OptsName) {
+// May perform round-trip of command line arguments. By default, the round-trip
+// is enabled if CLANG_ROUND_TRIP_CC1_ARGS was defined during build. This can be
+// overwritten at run-time via the "-round-trip-args" and "-no-round-trip-args"
+// command line flags.
+// During round-trip, the command line arguments are parsed into a dummy
+// instance of CompilerInvocation which is used to generate the command line
+// arguments again. The real CompilerInvocation instance is then created by
+// parsing the generated arguments, not the original ones.
+static bool RoundTrip(ParseFn Parse, GenerateFn Generate,
+ CompilerInvocation &RealInvocation,
+ CompilerInvocation &DummyInvocation,
+ ArrayRef<const char *> CommandLineArgs,
+ DiagnosticsEngine &Diags, const char *Argv0) {
// FIXME: Switch to '#ifndef NDEBUG' when possible.
#ifdef CLANG_ROUND_TRIP_CC1_ARGS
bool DoRoundTripDefault = true;
@@ -597,16 +603,21 @@ static bool RoundTrip(ParseFn Parse, GenerateFn Generate, SwapOptsFn SwapOpts,
bool DoRoundTripDefault = false;
#endif
- bool DoRoundTrip = OriginalArgs.hasFlag(
- OPT_round_trip_args, OPT_no_round_trip_args, DoRoundTripDefault);
+ bool DoRoundTrip = DoRoundTripDefault;
+ for (const auto *Arg : CommandLineArgs) {
+ if (Arg == StringRef("-round-trip-args"))
+ DoRoundTrip = true;
+ if (Arg == StringRef("-no-round-trip-args"))
+ DoRoundTrip = false;
+ }
- // If round-trip was not requested, simply run the parser with the original
- // options and diagnostics.
+ // If round-trip was not requested, simply run the parser with the real
+ // invocation diagnostics.
if (!DoRoundTrip)
- return Parse(Res, OriginalArgs, Diags);
+ return Parse(RealInvocation, CommandLineArgs, Diags, Argv0);
// Serializes quoted (and potentially escaped) arguments.
- auto SerializeArgs = [](ArgStringList &Args) {
+ auto SerializeArgs = [](ArrayRef<const char *> Args) {
std::string Buffer;
llvm::raw_string_ostream OS(Buffer);
for (const char *Arg : Args) {
@@ -617,34 +628,28 @@ static bool RoundTrip(ParseFn Parse, GenerateFn Generate, SwapOptsFn SwapOpts,
return Buffer;
};
- OriginalArgs.clearQueriedOpts();
-
// Setup a dummy DiagnosticsEngine.
DiagnosticsEngine DummyDiags(new DiagnosticIDs(), new DiagnosticOptions());
DummyDiags.setClient(new TextDiagnosticBuffer());
- // Run the first parse on the original arguments with dummy options and
+ // Run the first parse on the original arguments with the dummy invocation and
// diagnostics.
- SwapOpts(Res);
- if (!Parse(Res, OriginalArgs, DummyDiags) ||
+ if (!Parse(DummyInvocation, CommandLineArgs, DummyDiags, Argv0) ||
DummyDiags.getNumWarnings() != 0) {
// If the first parse did not succeed, it must be user mistake (invalid
// command line arguments). We won't be able to generate arguments that
- // would reproduce the same result. Let's fail again with the original
- // options and diagnostics, so all side-effects of parsing are visible.
+ // would reproduce the same result. Let's fail again with the real
+ // invocation and diagnostics, so all side-effects of parsing are visible.
unsigned NumWarningsBefore = Diags.getNumWarnings();
- SwapOpts(Res);
- auto Success = Parse(Res, OriginalArgs, Diags);
+ auto Success = Parse(RealInvocation, CommandLineArgs, Diags, Argv0);
if (!Success || Diags.getNumWarnings() != NumWarningsBefore)
return Success;
// Parse with original options and diagnostics succeeded even though it
// shouldn't have. Something is off.
- Diags.Report(diag::err_cc1_round_trip_fail_then_ok) << OptsName;
- ArgStringList OriginalStrings;
- OriginalArgs.AddAllArgsExcept(OriginalStrings, {});
+ Diags.Report(diag::err_cc1_round_trip_fail_then_ok);
Diags.Report(diag::note_cc1_round_trip_original)
- << OptsName << SerializeArgs(OriginalStrings);
+ << SerializeArgs(CommandLineArgs);
return false;
}
@@ -655,50 +660,35 @@ static bool RoundTrip(ParseFn Parse, GenerateFn Generate, SwapOptsFn SwapOpts,
return StringPool.save(Arg).data();
};
- // Generate arguments. First simply copy any arguments the parser did not
- // query. Then, use the Generate function that uses the CompilerInvocation
- // options instance as the source of truth. If Generate is the inverse of
- // Parse, the newly generated arguments must have the same semantics as the
- // original.
- ArgStringList GeneratedStrings1;
- OriginalArgs.AddAllArgsExcept(GeneratedStrings1,
- OriginalArgs.getQueriedOpts());
- Generate(Res, GeneratedStrings1, SA);
-
- // Process the generated arguments.
- unsigned MissingArgIndex1, MissingArgCount1;
- InputArgList GeneratedArgs1 =
- getDriverOptTable().ParseArgs(GeneratedStrings1, MissingArgIndex1,
- MissingArgCount1, options::CC1Option);
-
- // TODO: Once we're responsible for generating all arguments, check that we
- // didn't create any unknown options or omitted required values.
-
- // Run the second parse, now on the generated arguments, and with the original
- // options and diagnostics. The result is what we will end up using for the
+ // Generate arguments from the dummy invocation. If Generate is the
+ // inverse of Parse, the newly generated arguments must have the same
+ // semantics as the original.
+ SmallVector<const char *> GeneratedArgs1;
+ Generate(DummyInvocation, GeneratedArgs1, SA);
+
+ // Run the second parse, now on the generated arguments, and with the real
+ // invocation and diagnostics. The result is what we will end up using for the
// rest of compilation, so if Generate is not inverse of Parse, something down
// the line will break.
- SwapOpts(Res);
- bool Success2 = Parse(Res, GeneratedArgs1, Diags);
+ bool Success2 = Parse(RealInvocation, GeneratedArgs1, Diags, Argv0);
// The first parse on original arguments succeeded, but second parse of
// generated arguments failed. Something must be wrong with the generator.
if (!Success2) {
- Diags.Report(diag::err_cc1_round_trip_ok_then_fail) << OptsName;
+ Diags.Report(diag::err_cc1_round_trip_ok_then_fail);
Diags.Report(diag::note_cc1_round_trip_generated)
- << OptsName << 1 << SerializeArgs(GeneratedStrings1);
+ << 1 << SerializeArgs(GeneratedArgs1);
return false;
}
// Generate arguments again, this time from the options we will end up using
// for the rest of the compilation.
- ArgStringList GeneratedStrings2;
- GeneratedArgs1.AddAllArgsExcept(GeneratedStrings2,
- GeneratedArgs1.getQueriedOpts());
- Generate(Res, GeneratedStrings2, SA);
+ SmallVector<const char *> GeneratedArgs2;
+ Generate(RealInvocation, GeneratedArgs2, SA);
// Compares two lists of generated arguments.
- auto Equal = [](const ArgStringList &A, const ArgStringList &B) {
+ auto Equal = [](const ArrayRef<const char *> A,
+ const ArrayRef<const char *> B) {
return std::equal(A.begin(), A.end(), B.begin(), B.end(),
[](const char *AElem, const char *BElem) {
return StringRef(AElem) == StringRef(BElem);
@@ -708,19 +698,19 @@ static bool RoundTrip(ParseFn Parse, GenerateFn Generate, SwapOptsFn SwapOpts,
// If we generated
diff erent arguments from what we assume are two
// semantically equivalent CompilerInvocations, the Generate function may
// be non-deterministic.
- if (!Equal(GeneratedStrings1, GeneratedStrings2)) {
- Diags.Report(diag::err_cc1_round_trip_mismatch) << OptsName;
+ if (!Equal(GeneratedArgs1, GeneratedArgs2)) {
+ Diags.Report(diag::err_cc1_round_trip_mismatch);
Diags.Report(diag::note_cc1_round_trip_generated)
- << OptsName << 1 << SerializeArgs(GeneratedStrings1);
+ << 1 << SerializeArgs(GeneratedArgs1);
Diags.Report(diag::note_cc1_round_trip_generated)
- << OptsName << 2 << SerializeArgs(GeneratedStrings2);
+ << 2 << SerializeArgs(GeneratedArgs2);
return false;
}
Diags.Report(diag::remark_cc1_round_trip_generated)
- << OptsName << 1 << SerializeArgs(GeneratedStrings1);
+ << 1 << SerializeArgs(GeneratedArgs1);
Diags.Report(diag::remark_cc1_round_trip_generated)
- << OptsName << 2 << SerializeArgs(GeneratedStrings2);
+ << 2 << SerializeArgs(GeneratedArgs2);
return Success2;
}
@@ -1028,20 +1018,7 @@ static bool ParseAnalyzerArgsImpl(AnalyzerOptions &Opts, ArgList &Args,
static bool ParseAnalyzerArgs(CompilerInvocation &Res, AnalyzerOptions &Opts,
ArgList &Args, DiagnosticsEngine &Diags) {
- auto DummyOpts = IntrusiveRefCntPtr<AnalyzerOptions>(new AnalyzerOptions());
-
- return RoundTrip(
- [](CompilerInvocation &Res, ArgList &Args, DiagnosticsEngine &Diags) {
- return ParseAnalyzerArgsImpl(*Res.getAnalyzerOpts(), Args, Diags);
- },
- [](CompilerInvocation &Res, SmallVectorImpl<const char *> &Args,
- CompilerInvocation::StringAllocator SA) {
- GenerateAnalyzerArgs(*Res.getAnalyzerOpts(), Args, SA);
- },
- [&DummyOpts](CompilerInvocation &Res) {
- Res.getAnalyzerOpts().swap(DummyOpts);
- },
- Res, Args, Diags, "AnalyzerOptions");
+ return ParseAnalyzerArgsImpl(*Res.getAnalyzerOpts(), Args, Diags);
}
static StringRef getStringOption(AnalyzerOptions::ConfigTable &Config,
@@ -1457,7 +1434,8 @@ void CompilerInvocation::GenerateCodeGenArgs(
}
if (memcmp(Opts.CoverageVersion, "408*", 4) != 0)
- GenerateArg(Args, OPT_coverage_version_EQ, Opts.CoverageVersion, SA);
+ GenerateArg(Args, OPT_coverage_version_EQ,
+ StringRef(Opts.CoverageVersion, 4), SA);
// TODO: Check if we need to generate arguments stored in CmdArgs. (Namely
// '-fembed_bitcode', which does not map to any CompilerInvocation field and
@@ -1976,23 +1954,8 @@ bool CompilerInvocation::ParseCodeGenArgs(
CompilerInvocation &Res, CodeGenOptions &Opts, ArgList &Args, InputKind IK,
DiagnosticsEngine &Diags, const llvm::Triple &T,
const std::string &OutputFile, const LangOptions &LangOptsRef) {
- CodeGenOptions DummyOpts;
-
- return RoundTrip(
- [&](CompilerInvocation &Res, ArgList &Args, DiagnosticsEngine &Diags) {
- Args.getLastArg(OPT_O0, OPT_O4, OPT_O, OPT_Ofast);
- return ParseCodeGenArgsImpl(Res.getCodeGenOpts(), Args, IK, Diags, T,
- OutputFile, LangOptsRef);
- },
- [&](CompilerInvocation &Res, SmallVectorImpl<const char *> &GeneratedArgs,
- StringAllocator SA) {
- GenerateCodeGenArgs(Res.getCodeGenOpts(), GeneratedArgs, SA, T,
- OutputFile, &LangOptsRef);
- },
- [&DummyOpts](CompilerInvocation &Res) {
- std::swap(Res.CodeGenOpts, DummyOpts);
- },
- Res, Args, Diags, "CodeGenOptions");
+ return ParseCodeGenArgsImpl(Res.getCodeGenOpts(), Args, IK, Diags, T,
+ OutputFile, LangOptsRef);
}
static void
@@ -2024,8 +1987,9 @@ GenerateDependencyOutputArgs(const DependencyOutputOptions &Opts,
// HeaderSearchOptions.
continue;
case EDK_ProfileList:
- GenerateArg(Args, OPT_fprofile_list_EQ, Dep.first, SA);
- break;
+ // Profile list arguments are generated from LanguageOptions via the
+ // marshalling infrastructure.
+ continue;
case EDK_DepFileEntry:
GenerateArg(Args, OPT_fdepfile_entry, Dep.first, SA);
break;
@@ -2106,50 +2070,8 @@ static bool ParseDependencyOutputArgs(CompilerInvocation &Res,
ArgList &Args, DiagnosticsEngine &Diags,
frontend::ActionKind Action,
bool ShowLineMarkers) {
- DependencyOutputOptions DummyOpts;
-
- return RoundTrip(
- [Action, ShowLineMarkers](CompilerInvocation &Res, ArgList &Args,
- DiagnosticsEngine &Diags) {
- return ParseDependencyOutputArgsImpl(Res.getDependencyOutputOpts(),
- Args, Diags, Action,
- ShowLineMarkers);
- },
- [&Args](CompilerInvocation &Res,
- SmallVectorImpl<const char *> &GeneratedArgs,
- CompilerInvocation::StringAllocator SA) {
- GenerateDependencyOutputArgs(Res.getDependencyOutputOpts(),
- GeneratedArgs, SA);
- // We're querying sanitizer blacklist and module file arguments, but
- // they are generated from LanguageOptions and HeaderSearchOptions.
- // Let's satisfy RoundTrip by generating them ourselves for now.
- if (!Args.hasArg(OPT_fno_sanitize_blacklist)) {
- for (const auto *A : Args.filtered(OPT_fsanitize_blacklist)) {
- StringRef Val = A->getValue();
- if (Val.find('=') == StringRef::npos)
- GenerateArg(GeneratedArgs, OPT_fsanitize_blacklist, Val, SA);
- }
- if (Res.getDependencyOutputOpts().IncludeSystemHeaders) {
- for (const auto *A :
- Args.filtered(OPT_fsanitize_system_blacklist)) {
- StringRef Val = A->getValue();
- if (Val.find('=') == StringRef::npos)
- GenerateArg(GeneratedArgs, OPT_fsanitize_system_blacklist, Val,
- SA);
- }
- }
- }
-
- for (const auto *A : Args.filtered(OPT_fmodule_file)) {
- StringRef Val = A->getValue();
- if (Val.find('=') == StringRef::npos)
- GenerateArg(GeneratedArgs, OPT_fmodule_file, Val, SA);
- }
- },
- [&DummyOpts](CompilerInvocation &Res) {
- std::swap(Res.getDependencyOutputOpts(), DummyOpts);
- },
- Res, Args, Diags, "DependencyOutputOptions");
+ return ParseDependencyOutputArgsImpl(Res.getDependencyOutputOpts(), Args,
+ Diags, Action, ShowLineMarkers);
}
static bool parseShowColorsArgs(const ArgList &Args, bool DefaultColor) {
@@ -2413,38 +2335,8 @@ bool CompilerInvocation::ParseDiagnosticArgsRoundTrip(CompilerInvocation &Res,
ArgList &Args,
DiagnosticsEngine *Diags,
bool DefaultDiagColor) {
- IntrusiveRefCntPtr<DiagnosticOptions> DummyOpts(new DiagnosticOptions);
-
- return RoundTrip(
- [DefaultDiagColor](CompilerInvocation &Res, ArgList &Args,
- DiagnosticsEngine &Diags) {
- // Query the options might not get queried properly during parsing, but
- // should be generated from DiagnosticOptions.
-
- Args.getLastArg(OPT_fcolor_diagnostics);
- Args.getLastArg(OPT_fno_color_diagnostics);
- Args.getLastArg(OPT_fdiagnostics_color);
- Args.getLastArg(OPT_fno_diagnostics_color);
- Args.getLastArg(OPT_fdiagnostics_color_EQ);
-
- for (auto *A : Args.filtered(OPT_W_Group))
- Args.getLastArg(A->getOption().getID());
- for (auto *A : Args.filtered(OPT_R_Group))
- Args.getLastArg(A->getOption().getID());
-
- return clang::ParseDiagnosticArgs(Res.getDiagnosticOpts(), Args, &Diags,
- DefaultDiagColor);
- },
- [DefaultDiagColor](CompilerInvocation &Res,
- SmallVectorImpl<const char *> &Args,
- CompilerInvocation::StringAllocator SA) {
- GenerateDiagnosticArgs(Res.getDiagnosticOpts(), Args, SA,
- DefaultDiagColor);
- },
- [&DummyOpts](CompilerInvocation &Res) {
- Res.DiagnosticOpts.swap(DummyOpts);
- },
- Res, Args, *Diags, "DiagnosticOptions");
+ return clang::ParseDiagnosticArgs(Res.getDiagnosticOpts(), Args, Diags,
+ DefaultDiagColor);
}
/// Parse the argument to the -ftest-module-file-extension
@@ -2926,29 +2818,8 @@ static bool ParseFrontendArgsImpl(FrontendOptions &Opts, ArgList &Args,
static bool ParseFrontendArgs(CompilerInvocation &Res, FrontendOptions &Opts,
ArgList &Args, DiagnosticsEngine &Diags,
bool &IsHeaderFile) {
- FrontendOptions DummyOpts;
-
- return RoundTrip(
- [&IsHeaderFile](CompilerInvocation &Res, ArgList &Args,
- DiagnosticsEngine &Diags) {
- // ParseFrontendArgsImpl handles frontend action without querying the
- // options. Let's do it now so RoundTrip considers us responsible for
- // generating it.
- for (const auto &Pair : getFrontendActionTable())
- Args.hasArg(Pair.second);
-
- return ParseFrontendArgsImpl(Res.getFrontendOpts(), Args, Diags,
- IsHeaderFile);
- },
- [&IsHeaderFile](CompilerInvocation &Res,
- SmallVectorImpl<const char *> &Args,
- CompilerInvocation::StringAllocator SA) {
- GenerateFrontendArgs(Res.getFrontendOpts(), Args, SA, IsHeaderFile);
- },
- [&DummyOpts](CompilerInvocation &Res) {
- std::swap(Res.getFrontendOpts(), DummyOpts);
- },
- Res, Args, Diags, "FrontendOptions");
+ return ParseFrontendArgsImpl(Res.getFrontendOpts(), Args, Diags,
+ IsHeaderFile);
}
std::string CompilerInvocation::GetResourcesPath(const char *Argv0,
@@ -3224,22 +3095,7 @@ void CompilerInvocation::ParseHeaderSearchArgs(CompilerInvocation &Res,
ArgList &Args,
DiagnosticsEngine &Diags,
const std::string &WorkingDir) {
- auto DummyOpts = std::make_shared<HeaderSearchOptions>();
-
- RoundTrip(
- [&WorkingDir](CompilerInvocation &Res, ArgList &Args,
- DiagnosticsEngine &Diags) {
- return ::ParseHeaderSearchArgs(Res.getHeaderSearchOpts(), Args, Diags,
- WorkingDir);
- },
- [](CompilerInvocation &Res, SmallVectorImpl<const char *> &GeneratedArgs,
- CompilerInvocation::StringAllocator SA) {
- GenerateHeaderSearchArgs(Res.getHeaderSearchOpts(), GeneratedArgs, SA);
- },
- [&DummyOpts](CompilerInvocation &Res) {
- Res.HeaderSearchOpts.swap(DummyOpts);
- },
- Res, Args, Diags, "HeaderSearchOptions");
+ ::ParseHeaderSearchArgs(Res.getHeaderSearchOpts(), Args, Diags, WorkingDir);
}
void CompilerInvocation::setLangDefaults(LangOptions &Opts, InputKind IK,
@@ -3633,11 +3489,8 @@ void CompilerInvocation::GenerateLangArgs(const LangOptions &Opts,
if (Opts.OpenMPCUDAForceFullRuntime)
GenerateArg(Args, OPT_fopenmp_cuda_force_full_runtime, SA);
- // The arguments used to set 'Optimize' and 'OptimizeSize' will be generated
- // by CodeGenOptions.
-
- if (Opts.NoInlineDefine && Opts.Optimize)
- GenerateArg(Args, OPT_fno_inline, SA);
+ // The arguments used to set Optimize, OptimizeSize and NoInlineDefine are
+ // generated from CodeGenOptions.
if (Opts.DefaultFPContractMode == LangOptions::FPM_Fast)
GenerateArg(Args, OPT_ffp_contract, "fast", SA);
@@ -4133,47 +3986,7 @@ bool CompilerInvocation::ParseLangArgs(CompilerInvocation &Res,
const llvm::Triple &T,
std::vector<std::string> &Includes,
DiagnosticsEngine &Diags) {
- auto DummyOpts = std::make_shared<LangOptions>();
-
- // We need to work around inconsistencies related to optimization flags. Their
- // primary consumer is CodeGenOptions. However, the LangOptions parser also
- // queries them, which means RoundTrip expects us to generate them. We don't
- // want to do it in GenerateLangArgs, because it should eventually be the
- // responsibility of GenerateCodeGenArgs. Until we start doing one big
- // round-trip, let's do it here.
- //
- // Our parser always queries OPT_O_Group. When given -O1, -O2 or -O3, it also
- // queries OPT_O. To ensure RoundTrip consistently considers us responsible
- // for generating all of them, we ensure to proactively query them all.
-
- return RoundTrip(
- [IK, &T, &Includes](CompilerInvocation &Res, ArgList &Args,
- DiagnosticsEngine &Diags) {
- // Proactively query all optimization flags.
- Args.getLastArg(OPT_O0, OPT_O4, OPT_O, OPT_Ofast);
- return ParseLangArgsImpl(*Res.getLangOpts(), Args, IK, T, Includes,
- Diags);
- },
- [&T, &Args](CompilerInvocation &Res,
- SmallVectorImpl<const char *> &GenArgs, StringAllocator SA) {
- GenerateLangArgs(*Res.getLangOpts(), GenArgs, SA, T);
- // Generate all optimization flags we queried.
- if (Arg *A = Args.getLastArg(OPT_O_Group)) {
- OptSpecifier Opt = A->getOption().getID();
-
- if (A->getNumValues() > 0)
- GenerateArg(GenArgs, Opt, A->getValues().back(), SA);
- else
- GenerateArg(GenArgs, Opt, SA);
- }
-
- // We also queried -fcf-protection, but don't have enough information to
- // generate it. Eventually, it will be generated from CodeGenOptions.
- if (const Arg *A = Args.getLastArg(OPT_fcf_protection_EQ))
- GenerateArg(GenArgs, OPT_fcf_protection_EQ, A->getValue(), SA);
- },
- [&DummyOpts](CompilerInvocation &Res) { Res.LangOpts.swap(DummyOpts); },
- Res, Args, Diags, "LangOptions");
+ return ParseLangArgsImpl(*Res.getLangOpts(), Args, IK, T, Includes, Diags);
}
static bool isStrictlyPreprocessorAction(frontend::ActionKind Action) {
@@ -4389,39 +4202,8 @@ static bool ParsePreprocessorArgs(CompilerInvocation &Res,
DiagnosticsEngine &Diags,
frontend::ActionKind Action,
FrontendOptions &FrontendOpts) {
- auto DummyOpts = std::make_shared<PreprocessorOptions>();
-
- auto Parse = [Action](CompilerInvocation &Res, ArgList &Args,
- DiagnosticsEngine &Diags) {
- return ParsePreprocessorArgsImpl(Res.getPreprocessorOpts(), Args, Diags,
- Action, Res.getFrontendOpts());
- };
-
- auto Generate = [&Args](CompilerInvocation &Res,
- SmallVectorImpl<const char *> &GeneratedArgs,
- CompilerInvocation::StringAllocator SA) {
- GeneratePreprocessorArgs(Res.getPreprocessorOpts(), GeneratedArgs, SA,
- *Res.getLangOpts(), Res.getFrontendOpts(),
- Res.getCodeGenOpts());
- // The ParsePreprocessorArgs function queries the -fcf-protection option,
- // which means that it won't be directly copied during argument generation.
- // The GeneratePreprocessorArgs function isn't responsible for generating it
- // either. This would cause -fcf-protection to get forgotten during
- // round-trip and the __CET__ macros wouldn't get deduced during second call
- // to ParsePreprocessorArgs. Let's fix this by generating -fcf-protection
- // here.
- // TODO: Remove this once we're doing one big round-trip instead of many
- // small ones.
- if (const Arg *A = Args.getLastArg(OPT_fcf_protection_EQ))
- GenerateArg(GeneratedArgs, OPT_fcf_protection_EQ, A->getValue(), SA);
- };
-
- auto Swap = [&DummyOpts](CompilerInvocation &Res) {
- std::swap(Res.PreprocessorOpts, DummyOpts);
- };
-
- return RoundTrip(Parse, Generate, Swap, Res, Args, Diags,
- "PreprocessorOptions");
+ return ParsePreprocessorArgsImpl(Res.getPreprocessorOpts(), Args, Diags,
+ Action, Res.getFrontendOpts());
}
static void GeneratePreprocessorOutputArgs(
@@ -4477,23 +4259,8 @@ static bool ParsePreprocessorOutputArgs(CompilerInvocation &Res,
PreprocessorOutputOptions &Opts,
ArgList &Args, DiagnosticsEngine &Diags,
frontend::ActionKind Action) {
- PreprocessorOutputOptions DummyOpts;
-
- return RoundTrip(
- [Action](CompilerInvocation &Res, ArgList &Args,
- DiagnosticsEngine &Diags) {
- return ParsePreprocessorOutputArgsImpl(Res.getPreprocessorOutputOpts(),
- Args, Diags, Action);
- },
- [Action](CompilerInvocation &Res, SmallVectorImpl<const char *> &Args,
- CompilerInvocation::StringAllocator SA) {
- GeneratePreprocessorOutputArgs(Res.getPreprocessorOutputOpts(), Args,
- SA, Action);
- },
- [&DummyOpts](CompilerInvocation &Res) {
- std::swap(DummyOpts, Res.getPreprocessorOutputOpts());
- },
- Res, Args, Diags, "PreprocessorOutputOptions");
+ return ParsePreprocessorOutputArgsImpl(Res.getPreprocessorOutputOpts(), Args,
+ Diags, Action);
}
static void GenerateTargetArgs(const TargetOptions &Opts,
@@ -4548,27 +4315,12 @@ static bool ParseTargetArgsImpl(TargetOptions &Opts, ArgList &Args,
static bool ParseTargetArgs(CompilerInvocation &Res, TargetOptions &Opts,
ArgList &Args, DiagnosticsEngine &Diags) {
- auto DummyOpts = std::make_shared<TargetOptions>();
-
- return RoundTrip(
- [](CompilerInvocation &Res, ArgList &Args,
- DiagnosticsEngine &Diags) {
- return ParseTargetArgsImpl(Res.getTargetOpts(), Args, Diags);
- },
- [](CompilerInvocation &Res, SmallVectorImpl<const char *> &GeneratedArgs,
- CompilerInvocation::StringAllocator SA) {
- GenerateTargetArgs(Res.getTargetOpts(), GeneratedArgs, SA);
- },
- [&DummyOpts](CompilerInvocation &Res) {
- Res.TargetOpts.swap(DummyOpts);
- },
- Res, Args, Diags, "TargetArgs");
+ return ParseTargetArgsImpl(Res.getTargetOpts(), Args, Diags);
}
-bool CompilerInvocation::CreateFromArgs(CompilerInvocation &Res,
- ArrayRef<const char *> CommandLineArgs,
- DiagnosticsEngine &Diags,
- const char *Argv0) {
+bool CompilerInvocation::CreateFromArgsImpl(
+ CompilerInvocation &Res, ArrayRef<const char *> CommandLineArgs,
+ DiagnosticsEngine &Diags, const char *Argv0) {
bool Success = true;
// Parse the arguments.
@@ -4608,7 +4360,7 @@ bool CompilerInvocation::CreateFromArgs(CompilerInvocation &Res,
LangOpts.IsHeaderFile);
// FIXME: We shouldn't have to pass the DashX option around here
InputKind DashX = Res.getFrontendOpts().DashX;
- ParseTargetArgs(Res, Res.getTargetOpts(), Args, Diags);
+ Success &= ParseTargetArgs(Res, Res.getTargetOpts(), Args, Diags);
llvm::Triple T(Res.getTargetOpts().Triple);
ParseHeaderSearchArgs(Res, Res.getHeaderSearchOpts(), Args, Diags,
Res.getFileSystemOpts().WorkingDir);
@@ -4683,11 +4435,27 @@ bool CompilerInvocation::CreateFromArgs(CompilerInvocation &Res,
Res.getCodeGenOpts().Argv0 = Argv0;
Res.getCodeGenOpts().CommandLineArgs = CommandLineArgs;
- FixupInvocation(Res, Diags, Args, DashX);
+ Success &= FixupInvocation(Res, Diags, Args, DashX);
return Success;
}
+bool CompilerInvocation::CreateFromArgs(CompilerInvocation &Invocation,
+ ArrayRef<const char *> CommandLineArgs,
+ DiagnosticsEngine &Diags,
+ const char *Argv0) {
+ CompilerInvocation DummyInvocation;
+
+ return RoundTrip(
+ [](CompilerInvocation &Invocation, ArrayRef<const char *> CommandLineArgs,
+ DiagnosticsEngine &Diags, const char *Argv0) {
+ return CreateFromArgsImpl(Invocation, CommandLineArgs, Diags, Argv0);
+ },
+ [](CompilerInvocation &Invocation, SmallVectorImpl<const char *> &Args,
+ StringAllocator SA) { Invocation.generateCC1CommandLine(Args, SA); },
+ Invocation, DummyInvocation, CommandLineArgs, Diags, Argv0);
+}
+
std::string CompilerInvocation::getModuleHash() const {
// Note: For QoI reasons, the things we use as a hash here should all be
// dumped via the -module-info flag.
@@ -4812,7 +4580,24 @@ void CompilerInvocation::generateCC1CommandLine(
GenerateFrontendArgs(FrontendOpts, Args, SA, LangOpts->IsHeaderFile);
GenerateTargetArgs(*TargetOpts, Args, SA);
GenerateHeaderSearchArgs(*HeaderSearchOpts, Args, SA);
- GenerateLangArgs(*LangOpts, Args, SA, T);
+
+ InputKind DashX = FrontendOpts.DashX;
+ if (DashX.getFormat() == InputKind::Precompiled ||
+ DashX.getLanguage() == Language::LLVM_IR) {
+ if (LangOpts->ObjCAutoRefCount)
+ GenerateArg(Args, OPT_fobjc_arc, SA);
+ if (LangOpts->PICLevel != 0)
+ GenerateArg(Args, OPT_pic_level, Twine(LangOpts->PICLevel), SA);
+ if (LangOpts->PIE)
+ GenerateArg(Args, OPT_pic_is_pie, SA);
+ for (StringRef Sanitizer : serializeSanitizerKinds(LangOpts->Sanitize))
+ GenerateArg(Args, OPT_fsanitize_EQ, Sanitizer, SA);
+ } else {
+ // FIXME: Move this whole condition into GenerateLangArgs. (And do the same
+ // for ParseLangArgs).
+ GenerateLangArgs(*LangOpts, Args, SA, T);
+ }
+
GenerateCodeGenArgs(CodeGenOpts, Args, SA, T, FrontendOpts.OutputFile,
&*LangOpts);
GeneratePreprocessorArgs(*PreprocessorOpts, Args, SA, *LangOpts, FrontendOpts,
diff --git a/clang/test/Frontend/round-trip-cc1-args.c b/clang/test/Frontend/round-trip-cc1-args.c
index 8e24f7f3a7fa..403fa982aafb 100644
--- a/clang/test/Frontend/round-trip-cc1-args.c
+++ b/clang/test/Frontend/round-trip-cc1-args.c
@@ -4,4 +4,4 @@
// CHECK-WITHOUT-ROUND-TRIP-NOT: remark:
// CHECK-ROUND-TRIP-WITHOUT-REMARKS-NOT: remark:
-// CHECK-ROUND-TRIP-WITH-REMARKS: remark: Generated arguments {{.*}} in {{.*}} round-trip: {{.*}}
+// CHECK-ROUND-TRIP-WITH-REMARKS: remark: Generated arguments #{{.*}} in round-trip: {{.*}}
More information about the cfe-commits
mailing list