Index: docs/UsersManual.rst =================================================================== --- docs/UsersManual.rst +++ docs/UsersManual.rst @@ -2849,6 +2849,7 @@ /arch: 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: Pass to the clang driver /C Don't discard comments when preprocessing /c Compile only /d1PP Retain macro definitions in /E mode @@ -3084,6 +3085,17 @@ -W Enable the specified warning -Xclang Pass to the clang compiler +The /clang: Option +^^^^^^^^^^^^^^^^^^ + +When clang-cl is run with a set of ``/clang:`` options, it will gather all +of the ```` 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 ^^^^^^^^^^^^^^^^^^^^ Index: include/clang/Driver/CLCompatOptions.td =================================================================== --- include/clang/Driver/CLCompatOptions.td +++ include/clang/Driver/CLCompatOptions.td @@ -321,6 +321,8 @@ 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 to the clang driver">, MetaVarName<"">; def _SLASH_Zl : CLFlag<"Zl">, HelpText<"Don't mention any default libraries in the object file">; Index: include/clang/Driver/Driver.h =================================================================== --- include/clang/Driver/Driver.h +++ include/clang/Driver/Driver.h @@ -362,6 +362,7 @@ /// ParseArgStrings - Parse the given list of strings into an /// ArgList. llvm::opt::InputArgList ParseArgStrings(ArrayRef Args, + bool IsClCompatMode, bool &ContainsError); /// BuildInputs - Construct the list of inputs and their types from @@ -552,7 +553,7 @@ /// Get bitmasks for which option flags to include and exclude based on /// the driver mode. - std::pair getIncludeExcludeOptionFlagMasks() const; + std::pair 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 Index: lib/Driver/Driver.cpp =================================================================== --- lib/Driver/Driver.cpp +++ lib/Driver/Driver.cpp @@ -166,6 +166,7 @@ } InputArgList Driver::ParseArgStrings(ArrayRef ArgStrings, + bool IsClCompatMode, bool &ContainsError) { llvm::PrettyStackTraceString CrashInfo("Command line argument parsing"); ContainsError = false; @@ -173,7 +174,7 @@ unsigned IncludedFlagsBitmask; unsigned ExcludedFlagsBitmask; std::tie(IncludedFlagsBitmask, ExcludedFlagsBitmask) = - getIncludeExcludeOptionFlagMasks(); + getIncludeExcludeOptionFlagMasks(IsClCompatMode); unsigned MissingArgIndex, MissingArgCount; InputArgList Args = @@ -730,7 +731,7 @@ ConfigFile = CfgFileName.str(); bool ContainErrors; CfgOptions = llvm::make_unique( - ParseArgStrings(NewCfgArgs, ContainErrors)); + ParseArgStrings(NewCfgArgs, IsCLMode(), ContainErrors)); if (ContainErrors) { CfgOptions.reset(); return true; @@ -924,7 +925,7 @@ // Arguments specified in command line. bool ContainsError; CLOptions = llvm::make_unique( - ParseArgStrings(ArgList.slice(1), ContainsError)); + ParseArgStrings(ArgList.slice(1), IsCLMode(), ContainsError)); // Try parsing configuration file. if (!ContainsError) @@ -934,21 +935,47 @@ // 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 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( + 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; @@ -1452,7 +1479,7 @@ unsigned IncludedFlagsBitmask; unsigned ExcludedFlagsBitmask; std::tie(IncludedFlagsBitmask, ExcludedFlagsBitmask) = - getIncludeExcludeOptionFlagMasks(); + getIncludeExcludeOptionFlagMasks(IsCLMode()); ExcludedFlagsBitmask |= options::NoDriverOption; if (!ShowHidden) @@ -4661,11 +4688,11 @@ return false; } -std::pair Driver::getIncludeExcludeOptionFlagMasks() const { +std::pair 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; Index: test/Driver/cl-options.c =================================================================== --- test/Driver/cl-options.c +++ test/Driver/cl-options.c @@ -614,5 +614,17 @@ // RUN: --version \ // RUN: -Werror /Zs -- %s 2>&1 +// Accept clang options under the /clang: 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() { }