diff options
-rw-r--r-- | clang/lib/Driver/Driver.cpp | 7 | ||||
-rw-r--r-- | clang/test/Driver/Inputs/cc1-response.txt | 4 | ||||
-rw-r--r-- | clang/test/Driver/cc1-response-files.c | 2 | ||||
-rw-r--r-- | clang/test/Driver/cl-link-at-file.c | 22 | ||||
-rw-r--r-- | clang/tools/driver/driver.cpp | 29 |
5 files changed, 60 insertions, 4 deletions
diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp index f6a39a9ab7c..482f9cf1730 100644 --- a/clang/lib/Driver/Driver.cpp +++ b/clang/lib/Driver/Driver.cpp @@ -83,6 +83,9 @@ void Driver::ParseDriverMode(ArrayRef<const char *> Args) { getOpts().getOption(options::OPT_driver_mode).getPrefixedName(); for (size_t I = 0, E = Args.size(); I != E; ++I) { + // Ingore nullptrs, they are response file's EOL markers + if (Args[I] == nullptr) + continue; const StringRef Arg = Args[I]; if (!Arg.startswith(OptName)) continue; @@ -102,7 +105,7 @@ void Driver::ParseDriverMode(ArrayRef<const char *> Args) { } } -InputArgList *Driver::ParseArgStrings(ArrayRef<const char *> ArgList) { +InputArgList *Driver::ParseArgStrings(ArrayRef<const char *> ArgStrings) { llvm::PrettyStackTraceString CrashInfo("Command line argument parsing"); unsigned IncludedFlagsBitmask; @@ -111,7 +114,7 @@ InputArgList *Driver::ParseArgStrings(ArrayRef<const char *> ArgList) { getIncludeExcludeOptionFlagMasks(); unsigned MissingArgIndex, MissingArgCount; - InputArgList *Args = getOpts().ParseArgs(ArgList.begin(), ArgList.end(), + InputArgList *Args = getOpts().ParseArgs(ArgStrings.begin(), ArgStrings.end(), MissingArgIndex, MissingArgCount, IncludedFlagsBitmask, ExcludedFlagsBitmask); diff --git a/clang/test/Driver/Inputs/cc1-response.txt b/clang/test/Driver/Inputs/cc1-response.txt new file mode 100644 index 00000000000..0236fdc6aa3 --- /dev/null +++ b/clang/test/Driver/Inputs/cc1-response.txt @@ -0,0 +1,4 @@ + + +-cc1 +-triple i686-pc-windows-msvc diff --git a/clang/test/Driver/cc1-response-files.c b/clang/test/Driver/cc1-response-files.c new file mode 100644 index 00000000000..f47e6448a6c --- /dev/null +++ b/clang/test/Driver/cc1-response-files.c @@ -0,0 +1,2 @@ +// RUN: %clang @%S/Inputs/cc1-response.txt -fsyntax-only -disable-llvm-optzns +int main() {} diff --git a/clang/test/Driver/cl-link-at-file.c b/clang/test/Driver/cl-link-at-file.c new file mode 100644 index 00000000000..f817ce523ad --- /dev/null +++ b/clang/test/Driver/cl-link-at-file.c @@ -0,0 +1,22 @@ +// PR17239 - The /link option, when inside a response file, should only extend +// until the end of the response file (and not the entire command line) + +// Don't attempt slash switches on msys bash. +// REQUIRES: shell-preserves-root + +// Note: %s must be preceded by -- or bound to another option, otherwise it may +// be interpreted as a command-line option, e.g. on Mac where %s is commonly +// under /Users. + +// RUN: echo /link bar.lib baz.lib > %t.args +// RUN: touch %t.obj +// RUN: %clang_cl -### @%t.args -- %t.obj 2>&1 | FileCheck %s -check-prefix=ARGS +// If the "/link" option captures all remaining args beyond its response file, +// it will also capture "--" and our input argument. In this case, Clang will +// be clueless and will emit "argument unused" warnings. If PR17239 is properly +// fixed, this should not happen because the "/link" option is restricted to +// consume only remaining args in its response file. +// ARGS-NOT: warning +// ARGS-NOT: argument unused during compilation +// Identify the linker command +// ARGS: link.exe diff --git a/clang/tools/driver/driver.cpp b/clang/tools/driver/driver.cpp index 2533401082a..524ead29a7f 100644 --- a/clang/tools/driver/driver.cpp +++ b/clang/tools/driver/driver.cpp @@ -116,6 +116,9 @@ static void ApplyOneQAOverride(raw_ostream &OS, ReplPattern = ReplPattern.slice(0, ReplPattern.size()-1); for (unsigned i = 1, e = Args.size(); i != e; ++i) { + // Ignore end-of-line response file markers + if (Args[i] == nullptr) + continue; std::string Repl = llvm::Regex(MatchPattern).sub(ReplPattern, Args[i]); if (Repl != Args[i]) { @@ -142,6 +145,9 @@ static void ApplyOneQAOverride(raw_ostream &OS, } else if (Edit[0] == 'O') { for (unsigned i = 1; i < Args.size();) { const char *A = Args[i]; + // Ignore end-of-line response file markers + if (A == nullptr) + continue; if (A[0] == '-' && A[1] == 'O' && (A[2] == '\0' || (A[3] == '\0' && (A[2] == 's' || A[2] == 'z' || @@ -384,14 +390,33 @@ int main(int argc_, const char **argv_) { std::set<std::string> SavedStrings; StringSetSaver Saver(SavedStrings); - llvm::cl::ExpandResponseFiles(Saver, llvm::cl::TokenizeGNUCommandLine, argv); - // Handle -cc1 integrated tools. + // Determines whether we want nullptr markers in argv to indicate response + // files end-of-lines. We only use this for the /LINK driver argument. + bool MarkEOLs = true; if (argv.size() > 1 && StringRef(argv[1]).startswith("-cc1")) + MarkEOLs = false; + llvm::cl::ExpandResponseFiles(Saver, llvm::cl::TokenizeGNUCommandLine, argv, + MarkEOLs); + + // Handle -cc1 integrated tools, even if -cc1 was expanded from a response + // file. + auto FirstArg = std::find_if(argv.begin() + 1, argv.end(), + [](const char *A) { return A != nullptr; }); + if (FirstArg != argv.end() && StringRef(*FirstArg).startswith("-cc1")) { + // If -cc1 came from a response file, remove the EOL sentinels. + if (MarkEOLs) { + auto newEnd = std::remove(argv.begin(), argv.end(), nullptr); + argv.resize(newEnd - argv.begin()); + } return ExecuteCC1Tool(argv, argv[1] + 4); + } bool CanonicalPrefixes = true; for (int i = 1, size = argv.size(); i < size; ++i) { + // Skip end-of-line response file markers + if (argv[i] == nullptr) + continue; if (StringRef(argv[i]) == "-no-canonical-prefixes") { CanonicalPrefixes = false; break; |