[clang] 17e5c99 - [clang][cli] Generate and round-trip DependencyOutput options
Jan Svoboda via cfe-commits
cfe-commits at lists.llvm.org
Wed Feb 10 03:21:00 PST 2021
Author: Jan Svoboda
Date: 2021-02-10T12:20:51+01:00
New Revision: 17e5c99d5128f33158103c260714b6e02dbe35d5
URL: https://github.com/llvm/llvm-project/commit/17e5c99d5128f33158103c260714b6e02dbe35d5
DIFF: https://github.com/llvm/llvm-project/commit/17e5c99d5128f33158103c260714b6e02dbe35d5.diff
LOG: [clang][cli] Generate and round-trip DependencyOutput options
This patch implements generation of remaining dependency output options and tests it by performing parse-generate-parse round trip.
Reviewed By: dexonsmith
Differential Revision: https://reviews.llvm.org/D96273
Added:
Modified:
clang/include/clang/Driver/Options.td
clang/include/clang/Frontend/DependencyOutputOptions.h
clang/lib/Frontend/CompilerInvocation.cpp
clang/lib/Frontend/DependencyFile.cpp
clang/lib/Frontend/HeaderIncludeGen.cpp
Removed:
################################################################################
diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
index f35c9ec553d9..563c85588af3 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -252,7 +252,7 @@ class FrontendOpts<string base>
class PreprocessorOutputOpts<string base>
: KeyPathAndMacro<"PreprocessorOutputOpts.", base, "PREPROCESSOR_OUTPUT_"> {}
class DependencyOutputOpts<string base>
- : KeyPathAndMacro<"DependencyOutputOpts.", base> {}
+ : KeyPathAndMacro<"DependencyOutputOpts.", base, "DEPENDENCY_OUTPUT_"> {}
class CodeGenOpts<string base>
: KeyPathAndMacro<"CodeGenOpts.", base, "CODEGEN_"> {}
class HeaderSearchOpts<string base>
diff --git a/clang/include/clang/Frontend/DependencyOutputOptions.h b/clang/include/clang/Frontend/DependencyOutputOptions.h
index 7a4f3337936f..433e3ede11c5 100644
--- a/clang/include/clang/Frontend/DependencyOutputOptions.h
+++ b/clang/include/clang/Frontend/DependencyOutputOptions.h
@@ -20,6 +20,14 @@ enum class ShowIncludesDestination { None, Stdout, Stderr };
/// DependencyOutputFormat - Format for the compiler dependency file.
enum class DependencyOutputFormat { Make, NMake };
+/// ExtraDepKind - The kind of extra dependency file.
+enum ExtraDepKind {
+ EDK_SanitizeBlacklist,
+ EDK_ProfileList,
+ EDK_ModuleFile,
+ EDK_DepFileEntry,
+};
+
/// DependencyOutputOptions - Options for controlling the compiler dependency
/// file generation.
class DependencyOutputOptions {
@@ -51,8 +59,9 @@ class DependencyOutputOptions {
/// must contain at least one entry.
std::vector<std::string> Targets;
- /// A list of filenames to be used as extra dependencies for every target.
- std::vector<std::string> ExtraDeps;
+ /// A list of extra dependencies (filename and kind) to be used for every
+ /// target.
+ std::vector<std::pair<std::string, ExtraDepKind>> ExtraDeps;
/// In /showIncludes mode, pretend the main TU is a header with this name.
std::string ShowIncludesPretendHeader;
diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp
index a2bb857cf033..3fa2331e2598 100644
--- a/clang/lib/Frontend/CompilerInvocation.cpp
+++ b/clang/lib/Frontend/CompilerInvocation.cpp
@@ -1947,19 +1947,76 @@ bool CompilerInvocation::ParseCodeGenArgs(
Res, Args, Diags, "CodeGenOptions");
}
-static void ParseDependencyOutputArgs(DependencyOutputOptions &Opts,
- ArgList &Args) {
+static void
+GenerateDependencyOutputArgs(const DependencyOutputOptions &Opts,
+ SmallVectorImpl<const char *> &Args,
+ CompilerInvocation::StringAllocator SA) {
+ const DependencyOutputOptions &DependencyOutputOpts = Opts;
+#define DEPENDENCY_OUTPUT_OPTION_WITH_MARSHALLING( \
+ PREFIX_TYPE, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
+ HELPTEXT, METAVAR, VALUES, SPELLING, SHOULD_PARSE, ALWAYS_EMIT, KEYPATH, \
+ DEFAULT_VALUE, IMPLIED_CHECK, IMPLIED_VALUE, NORMALIZER, DENORMALIZER, \
+ MERGER, EXTRACTOR, TABLE_INDEX) \
+ GENERATE_OPTION_WITH_MARSHALLING( \
+ Args, SA, KIND, FLAGS, SPELLING, ALWAYS_EMIT, KEYPATH, DEFAULT_VALUE, \
+ IMPLIED_CHECK, IMPLIED_VALUE, DENORMALIZER, EXTRACTOR, TABLE_INDEX)
+#include "clang/Driver/Options.inc"
+#undef DEPENDENCY_OUTPUT_OPTION_WITH_MARSHALLING
+
+ if (Opts.ShowIncludesDest != ShowIncludesDestination::None)
+ GenerateArg(Args, OPT_show_includes, SA);
+
+ for (const auto &Dep : Opts.ExtraDeps) {
+ switch (Dep.second) {
+ case EDK_SanitizeBlacklist:
+ // Sanitizer blacklist arguments are generated from LanguageOptions.
+ continue;
+ case EDK_ModuleFile:
+ // Module file arguments are generated from FrontendOptions and
+ // HeaderSearchOptions.
+ continue;
+ case EDK_ProfileList:
+ GenerateArg(Args, OPT_fprofile_list_EQ, Dep.first, SA);
+ break;
+ case EDK_DepFileEntry:
+ GenerateArg(Args, OPT_fdepfile_entry, Dep.first, SA);
+ break;
+ }
+ }
+}
+
+static bool ParseDependencyOutputArgsImpl(
+ DependencyOutputOptions &Opts, ArgList &Args,
+ DiagnosticsEngine &Diags,
+ frontend::ActionKind Action, bool ShowLineMarkers) {
+ unsigned NumErrorsBefore = Diags.getNumErrors();
+ bool Success = true;
+
+ DependencyOutputOptions &DependencyOutputOpts = Opts;
+#define DEPENDENCY_OUTPUT_OPTION_WITH_MARSHALLING( \
+ PREFIX_TYPE, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
+ HELPTEXT, METAVAR, VALUES, SPELLING, SHOULD_PARSE, ALWAYS_EMIT, KEYPATH, \
+ DEFAULT_VALUE, IMPLIED_CHECK, IMPLIED_VALUE, NORMALIZER, DENORMALIZER, \
+ MERGER, EXTRACTOR, TABLE_INDEX) \
+ PARSE_OPTION_WITH_MARSHALLING(Args, Diags, Success, ID, FLAGS, PARAM, \
+ SHOULD_PARSE, KEYPATH, DEFAULT_VALUE, \
+ IMPLIED_CHECK, IMPLIED_VALUE, NORMALIZER, \
+ MERGER, TABLE_INDEX)
+#include "clang/Driver/Options.inc"
+#undef DEPENDENCY_OUTPUT_OPTION_WITH_MARSHALLING
+
if (Args.hasArg(OPT_show_includes)) {
// Writing both /showIncludes and preprocessor output to stdout
// would produce interleaved output, so use stderr for /showIncludes.
// This behaves the same as cl.exe, when /E, /EP or /P are passed.
- if (Args.hasArg(options::OPT_E) || Args.hasArg(options::OPT_P))
+ if (Action == frontend::PrintPreprocessedInput || !ShowLineMarkers)
Opts.ShowIncludesDest = ShowIncludesDestination::Stderr;
else
Opts.ShowIncludesDest = ShowIncludesDestination::Stdout;
} else {
Opts.ShowIncludesDest = ShowIncludesDestination::None;
}
+
// Add sanitizer blacklists as extra dependencies.
// They won't be discovered by the regular preprocessor, so
// we let make / ninja to know about this implicit dependency.
@@ -1967,32 +2024,84 @@ static void ParseDependencyOutputArgs(DependencyOutputOptions &Opts,
for (const auto *A : Args.filtered(OPT_fsanitize_blacklist)) {
StringRef Val = A->getValue();
if (Val.find('=') == StringRef::npos)
- Opts.ExtraDeps.push_back(std::string(Val));
+ Opts.ExtraDeps.emplace_back(std::string(Val), EDK_SanitizeBlacklist);
}
if (Opts.IncludeSystemHeaders) {
for (const auto *A : Args.filtered(OPT_fsanitize_system_blacklist)) {
StringRef Val = A->getValue();
if (Val.find('=') == StringRef::npos)
- Opts.ExtraDeps.push_back(std::string(Val));
+ Opts.ExtraDeps.emplace_back(std::string(Val), EDK_SanitizeBlacklist);
}
}
}
// -fprofile-list= dependencies.
for (const auto &Filename : Args.getAllArgValues(OPT_fprofile_list_EQ))
- Opts.ExtraDeps.push_back(Filename);
+ Opts.ExtraDeps.emplace_back(Filename, EDK_ProfileList);
// Propagate the extra dependencies.
- for (const auto *A : Args.filtered(OPT_fdepfile_entry)) {
- Opts.ExtraDeps.push_back(A->getValue());
- }
+ for (const auto *A : Args.filtered(OPT_fdepfile_entry))
+ Opts.ExtraDeps.emplace_back(A->getValue(), EDK_DepFileEntry);
// Only the -fmodule-file=<file> form.
for (const auto *A : Args.filtered(OPT_fmodule_file)) {
StringRef Val = A->getValue();
if (Val.find('=') == StringRef::npos)
- Opts.ExtraDeps.push_back(std::string(Val));
+ Opts.ExtraDeps.emplace_back(std::string(Val), EDK_ModuleFile);
}
+
+ return Success && Diags.getNumErrors() == NumErrorsBefore;
+}
+
+static bool ParseDependencyOutputArgs(CompilerInvocation &Res,
+ DependencyOutputOptions &Opts,
+ 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");
}
static bool parseShowColorsArgs(const ArgList &Args, bool DefaultColor) {
@@ -4284,12 +4393,6 @@ bool CompilerInvocation::CreateFromArgs(CompilerInvocation &Res,
Success &= Res.parseSimpleArgs(Args, Diags);
Success &= ParseAnalyzerArgs(Res, *Res.getAnalyzerOpts(), Args, Diags);
- ParseDependencyOutputArgs(Res.getDependencyOutputOpts(), Args);
- if (!Res.getDependencyOutputOpts().OutputFile.empty() &&
- Res.getDependencyOutputOpts().Targets.empty()) {
- Diags.Report(diag::err_fe_dependency_file_requires_MT);
- Success = false;
- }
Success &= ParseDiagnosticArgs(Res.getDiagnosticOpts(), Args, &Diags,
/*DefaultDiagColor=*/false);
Success &= ParseFrontendArgs(Res, Res.getFrontendOpts(), Args, Diags,
@@ -4357,6 +4460,15 @@ bool CompilerInvocation::CreateFromArgs(CompilerInvocation &Res,
ParsePreprocessorOutputArgs(Res, Res.getPreprocessorOutputOpts(), Args, Diags,
Res.getFrontendOpts().ProgramAction);
+ ParseDependencyOutputArgs(Res, Res.getDependencyOutputOpts(), Args, Diags,
+ Res.getFrontendOpts().ProgramAction,
+ Res.getPreprocessorOutputOpts().ShowLineMarkers);
+ if (!Res.getDependencyOutputOpts().OutputFile.empty() &&
+ Res.getDependencyOutputOpts().Targets.empty()) {
+ Diags.Report(diag::err_fe_dependency_file_requires_MT);
+ Success = false;
+ }
+
// Turn on -Wspir-compat for SPIR target.
if (T.isSPIR())
Res.getDiagnosticOpts().Warnings.push_back("spir-compat");
@@ -4522,6 +4634,7 @@ void CompilerInvocation::generateCC1CommandLine(
CodeGenOpts);
GeneratePreprocessorOutputArgs(PreprocessorOutputOpts, Args, SA,
FrontendOpts.ProgramAction);
+ GenerateDependencyOutputArgs(DependencyOutputOpts, Args, SA);
}
IntrusiveRefCntPtr<llvm::vfs::FileSystem>
diff --git a/clang/lib/Frontend/DependencyFile.cpp b/clang/lib/Frontend/DependencyFile.cpp
index fe8ab7197400..8bdda0c134c8 100644
--- a/clang/lib/Frontend/DependencyFile.cpp
+++ b/clang/lib/Frontend/DependencyFile.cpp
@@ -182,7 +182,7 @@ DependencyFileGenerator::DependencyFileGenerator(
IncludeModuleFiles(Opts.IncludeModuleFiles),
OutputFormat(Opts.OutputFormat), InputFileIndex(0) {
for (const auto &ExtraDep : Opts.ExtraDeps) {
- if (addDependency(ExtraDep))
+ if (addDependency(ExtraDep.first))
++InputFileIndex;
}
}
diff --git a/clang/lib/Frontend/HeaderIncludeGen.cpp b/clang/lib/Frontend/HeaderIncludeGen.cpp
index 97fac8a26fae..cc2989a31df8 100644
--- a/clang/lib/Frontend/HeaderIncludeGen.cpp
+++ b/clang/lib/Frontend/HeaderIncludeGen.cpp
@@ -119,7 +119,7 @@ void clang::AttachHeaderIncludeGen(Preprocessor &PP,
// as sanitizer blacklists. It's only important for cl.exe compatibility,
// the GNU way to generate rules is -M / -MM / -MD / -MMD.
for (const auto &Header : DepOpts.ExtraDeps)
- PrintHeaderInfo(OutputFile, Header, ShowDepth, 2, MSStyle);
+ PrintHeaderInfo(OutputFile, Header.first, ShowDepth, 2, MSStyle);
PP.addPPCallbacks(std::make_unique<HeaderIncludesCallback>(
&PP, ShowAllHeaders, OutputFile, DepOpts, OwnsOutputFile, ShowDepth,
MSStyle));
More information about the cfe-commits
mailing list