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;
}
}
-InputArgList *Driver::ParseArgStrings(ArrayRef<const char *> ArgList) {
+InputArgList *Driver::ParseArgStrings(ArrayRef<const char *> ArgStrings) {
llvm::PrettyStackTraceString CrashInfo("Command line argument parsing");
unsigned IncludedFlagsBitmask;
getIncludeExcludeOptionFlagMasks();
unsigned MissingArgIndex, MissingArgCount;
- InputArgList *Args = getOpts().ParseArgs(ArgList.begin(), ArgList.end(),
+ InputArgList *Args = getOpts().ParseArgs(ArgStrings.begin(), ArgStrings.end(),
MissingArgIndex, MissingArgCount,
IncludedFlagsBitmask,
ExcludedFlagsBitmask);
--- /dev/null
+// 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
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]) {
} 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' ||
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;