summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIvan Donchevskii <ivan.donchevskii@qt.io>2019-01-11 15:26:39 +0100
committerIvan Donchevskii <ivan.donchevskii@qt.io>2019-01-15 07:48:11 +0000
commitd1408d8177f7553097d1efd9d62c75868340266b (patch)
tree976a72d1756a0bee9ee6be201bbcffa0eba9c9f0
parentf633806b0f86da7a66420e32eb5cf72c16526c00 (diff)
[backported/clang-8] clang-cl: Add "/clang:" pass-through arg support
-------------------------------------------------------------------------- * https://reviews.llvm.org/D53457 -------------------------------------------------------------------------- The clang-cl driver disables access to command line options outside of the "Core" and "CLOption" sets of command line arguments. This filtering makes it impossible to pass arguments that are interpreted by the clang driver and not by either 'cc1' (the frontend) or one of the other tools invoked by the driver. An example driver-level flag is the '-fno-slp-vectorize' flag, which is processed by the driver in Clang::ConstructJob and used to set the cc1 flag "-vectorize-slp". There is no negative cc1 flag or -mllvm flag, so it is not currently possible to disable the SLP vectorizer from the clang-cl driver. This change introduces the "/clang:" argument that is available when the driver mode is set to CL compatibility. This option works similarly to the "-Xclang" option, except that the option values are processed by the clang driver rather than by 'cc1'. An example usage is: clang-cl /clang:-fno-slp-vectorize /O2 test.c Another example shows how "/clang:" can be used to pass a flag where there is a conflict between a clang-cl compat option and an overlapping clang driver option: clang-cl /MD /clang:-MD /clang:-MF /clang:test_dep_file.dep test.c In the previous example, the unprefixed /MD selects the DLL version of the msvc CRT, while the prefixed -MD flag and the -MF flags are used to create a make dependency file for included headers. One note about flag ordering: the /clang: flags are concatenated to the end of the argument list, so in cases where the last flag wins, the /clang: flags will be chosen regardless of their order relative to other flags on the driver command line. Patch by Neeraj K. Singh! Change-Id: Ie8139773f28ade2dccb8b732780dccbdac668ed8 Reviewed-by: Nikolai Kosjar <nikolai.kosjar@qt.io>
-rw-r--r--docs/UsersManual.rst12
-rw-r--r--include/clang/Driver/CLCompatOptions.td2
-rw-r--r--include/clang/Driver/Driver.h3
-rw-r--r--lib/Driver/Driver.cpp53
-rw-r--r--test/Driver/cl-options.c14
5 files changed, 70 insertions, 14 deletions
diff --git a/docs/UsersManual.rst b/docs/UsersManual.rst
index e0dc31f432..abf7f3a87d 100644
--- a/docs/UsersManual.rst
+++ b/docs/UsersManual.rst
@@ -2777,6 +2777,7 @@ Execute ``clang-cl /?`` to see a list of supported options:
/arch:<value> Set architecture for code generation
/Brepro- Emit an object file which cannot be reproduced over time
/Brepro Emit an object file which can be reproduced over time
+ /clang:<arg> Pass <arg> to the clang driver
/C Don't discard comments when preprocessing
/c Compile only
/d1PP Retain macro definitions in /E mode
@@ -3012,6 +3013,17 @@ Execute ``clang-cl /?`` to see a list of supported options:
-W<warning> Enable the specified warning
-Xclang <arg> Pass <arg> to the clang compiler
+The /clang: Option
+^^^^^^^^^^^^^^^^^^
+
+When clang-cl is run with a set of ``/clang:<arg>`` options, it will gather all
+of the ``<arg>`` arguments and process them as if they were passed to the clang
+driver. This mechanism allows you to pass flags that are not exposed in the
+clang-cl options or flags that have a different meaning when passed to the clang
+driver. Regardless of where they appear in the command line, the ``/clang:``
+arguments are treated as if they were passed at the end of the clang-cl command
+line.
+
The /fallback Option
^^^^^^^^^^^^^^^^^^^^
diff --git a/include/clang/Driver/CLCompatOptions.td b/include/clang/Driver/CLCompatOptions.td
index 78667851ca..a51e53c59e 100644
--- a/include/clang/Driver/CLCompatOptions.td
+++ b/include/clang/Driver/CLCompatOptions.td
@@ -289,6 +289,8 @@ def _SLASH_vmv : CLFlag<"vmv">,
def _SLASH_volatile_ms : Option<["/", "-"], "volatile:ms", KIND_FLAG>,
Group<_SLASH_volatile_Group>, Flags<[CLOption, DriverOption]>,
HelpText<"Volatile loads and stores have acquire and release semantics">;
+def _SLASH_clang : CLJoined<"clang:">,
+ HelpText<"Pass <arg> to the clang driver">, MetaVarName<"<arg>">;
def _SLASH_Zl : CLFlag<"Zl">,
HelpText<"Don't mention any default libraries in the object file">;
diff --git a/include/clang/Driver/Driver.h b/include/clang/Driver/Driver.h
index b7b8022211..ec712585e8 100644
--- a/include/clang/Driver/Driver.h
+++ b/include/clang/Driver/Driver.h
@@ -363,6 +363,7 @@ public:
/// ParseArgStrings - Parse the given list of strings into an
/// ArgList.
llvm::opt::InputArgList ParseArgStrings(ArrayRef<const char *> Args,
+ bool IsClCompatMode,
bool &ContainsError);
/// BuildInputs - Construct the list of inputs and their types from
@@ -553,7 +554,7 @@ private:
/// Get bitmasks for which option flags to include and exclude based on
/// the driver mode.
- std::pair<unsigned, unsigned> getIncludeExcludeOptionFlagMasks() const;
+ std::pair<unsigned, unsigned> getIncludeExcludeOptionFlagMasks(bool IsClCompatMode) const;
/// Helper used in BuildJobsForAction. Doesn't use the cache when building
/// jobs specifically for the given action, but will use the cache when
diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp
index 952a716cb6..1a2455d198 100644
--- a/lib/Driver/Driver.cpp
+++ b/lib/Driver/Driver.cpp
@@ -164,6 +164,7 @@ void Driver::setDriverModeFromOption(StringRef Opt) {
}
InputArgList Driver::ParseArgStrings(ArrayRef<const char *> ArgStrings,
+ bool IsClCompatMode,
bool &ContainsError) {
llvm::PrettyStackTraceString CrashInfo("Command line argument parsing");
ContainsError = false;
@@ -171,7 +172,7 @@ InputArgList Driver::ParseArgStrings(ArrayRef<const char *> ArgStrings,
unsigned IncludedFlagsBitmask;
unsigned ExcludedFlagsBitmask;
std::tie(IncludedFlagsBitmask, ExcludedFlagsBitmask) =
- getIncludeExcludeOptionFlagMasks();
+ getIncludeExcludeOptionFlagMasks(IsClCompatMode);
unsigned MissingArgIndex, MissingArgCount;
InputArgList Args =
@@ -705,7 +706,7 @@ bool Driver::readConfigFile(StringRef FileName) {
ConfigFile = CfgFileName.str();
bool ContainErrors;
CfgOptions = llvm::make_unique<InputArgList>(
- ParseArgStrings(NewCfgArgs, ContainErrors));
+ ParseArgStrings(NewCfgArgs, IsCLMode(), ContainErrors));
if (ContainErrors) {
CfgOptions.reset();
return true;
@@ -899,7 +900,7 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) {
// Arguments specified in command line.
bool ContainsError;
CLOptions = llvm::make_unique<InputArgList>(
- ParseArgStrings(ArgList.slice(1), ContainsError));
+ ParseArgStrings(ArgList.slice(1), IsCLMode(), ContainsError));
// Try parsing configuration file.
if (!ContainsError)
@@ -909,21 +910,47 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) {
// All arguments, from both config file and command line.
InputArgList Args = std::move(HasConfigFile ? std::move(*CfgOptions)
: std::move(*CLOptions));
- if (HasConfigFile)
- for (auto *Opt : *CLOptions) {
- if (Opt->getOption().matches(options::OPT_config))
- continue;
+
+ auto appendOneArg = [&Args](const Arg *Opt, const Arg *BaseArg) {
unsigned Index = Args.MakeIndex(Opt->getSpelling());
- const Arg *BaseArg = &Opt->getBaseArg();
- if (BaseArg == Opt)
- BaseArg = nullptr;
Arg *Copy = new llvm::opt::Arg(Opt->getOption(), Opt->getSpelling(),
Index, BaseArg);
Copy->getValues() = Opt->getValues();
if (Opt->isClaimed())
Copy->claim();
Args.append(Copy);
+ };
+
+ if (HasConfigFile)
+ for (auto *Opt : *CLOptions) {
+ if (Opt->getOption().matches(options::OPT_config))
+ continue;
+ const Arg *BaseArg = &Opt->getBaseArg();
+ if (BaseArg == Opt)
+ BaseArg = nullptr;
+ appendOneArg(Opt, BaseArg);
+ }
+
+ // In CL mode, look for any pass-through arguments
+ if (IsCLMode() && !ContainsError) {
+ SmallVector<const char *, 16> CLModePassThroughArgList;
+ for (const auto *A : Args.filtered(options::OPT__SLASH_clang)) {
+ A->claim();
+ CLModePassThroughArgList.push_back(A->getValue());
+ }
+
+ if (!CLModePassThroughArgList.empty()) {
+ // Parse any pass through args using default clang processing rather
+ // than clang-cl processing.
+ auto CLModePassThroughOptions = llvm::make_unique<InputArgList>(
+ ParseArgStrings(CLModePassThroughArgList, false, ContainsError));
+
+ if (!ContainsError)
+ for (auto *Opt : *CLModePassThroughOptions) {
+ appendOneArg(Opt, nullptr);
+ }
}
+ }
// FIXME: This stuff needs to go into the Compilation, not the driver.
bool CCCPrintPhases;
@@ -1417,7 +1444,7 @@ void Driver::PrintHelp(bool ShowHidden) const {
unsigned IncludedFlagsBitmask;
unsigned ExcludedFlagsBitmask;
std::tie(IncludedFlagsBitmask, ExcludedFlagsBitmask) =
- getIncludeExcludeOptionFlagMasks();
+ getIncludeExcludeOptionFlagMasks(IsCLMode());
ExcludedFlagsBitmask |= options::NoDriverOption;
if (!ShowHidden)
@@ -4508,11 +4535,11 @@ bool Driver::GetReleaseVersion(StringRef Str,
return false;
}
-std::pair<unsigned, unsigned> Driver::getIncludeExcludeOptionFlagMasks() const {
+std::pair<unsigned, unsigned> Driver::getIncludeExcludeOptionFlagMasks(bool IsClCompatMode) const {
unsigned IncludedFlagsBitmask = 0;
unsigned ExcludedFlagsBitmask = options::NoDriverOption;
- if (Mode == CLMode) {
+ if (IsClCompatMode) {
// Include CL and Core options.
IncludedFlagsBitmask |= options::CLOption;
IncludedFlagsBitmask |= options::CoreOption;
diff --git a/test/Driver/cl-options.c b/test/Driver/cl-options.c
index 9aa6ced349..eb606afed8 100644
--- a/test/Driver/cl-options.c
+++ b/test/Driver/cl-options.c
@@ -600,5 +600,19 @@
// RUN: --version \
// RUN: -Werror /Zs -- %s 2>&1
+// Accept clang options under the /clang: flag.
+// The first test case ensures that the SLP vectorizer is on by default and that
+// it's being turned off by the /clang:-fno-slp-vectorize flag.
+
+// RUN: %clang_cl -O2 -### -- %s 2>&1 | FileCheck -check-prefix=NOCLANG %s
+// NOCLANG: "--dependent-lib=libcmt"
+// NOCLANG-SAME: "-vectorize-slp"
+// NOCLANG-NOT: "--dependent-lib=msvcrt"
+
+// RUN: %clang_cl -O2 -MD /clang:-fno-slp-vectorize /clang:-MD /clang:-MF /clang:my_dependency_file.dep -### -- %s 2>&1 | FileCheck -check-prefix=CLANG %s
+// CLANG: "--dependent-lib=msvcrt"
+// CLANG-SAME: "-dependency-file" "my_dependency_file.dep"
+// CLANG-NOT: "--dependent-lib=libcmt"
+// CLANG-NOT: "-vectorize-slp"
void f() { }