diff --git a/llvm/include/llvm/Support/CommandLine.h b/llvm/include/llvm/Support/CommandLine.h --- a/llvm/include/llvm/Support/CommandLine.h +++ b/llvm/include/llvm/Support/CommandLine.h @@ -2111,6 +2111,29 @@ bool RelativeNames, llvm::Optional CurrentDir, llvm::vfs::FileSystem &FS); +/// Expand response files on a command line recursively using the given +/// StringSaver and tokenization strategy. Argv should contain the command line +/// before expansion and will be modified in place. If requested, Argv will +/// also be populated with nullptrs indicating where each response file line +/// ends, which is useful for the "/link" argument that needs to consume all +/// remaining arguments only until the next end of line, when in a response +/// file. +/// +/// \param [in] Saver Delegates back to the caller for saving parsed strings. +/// \param [in] Tokenizer Tokenization strategy. Typically Unix or Windows. +/// \param [in,out] Argv Command line into which to expand response files. +/// \param [in] MarkEOLs Mark end of lines and the end of the response file +/// with nullptrs in the Argv vector. +/// \param [in] RelativeNames true if names of nested response files must be +/// resolved relative to including file. +/// \param [in] FS File system used for all file access when running the tool. +/// \param [in] CurrentDir Path used to resolve relative rsp files. If set to +/// None, process' cwd is used instead. +/// \return success if all @files were expanded successfully or there were none. +llvm::Error ExpandResponseFilesWithError( + StringSaver &Saver, TokenizerCallback Tokenizer, + SmallVectorImpl &Argv, bool MarkEOLs, bool RelativeNames, + llvm::Optional CurrentDir, llvm::vfs::FileSystem &FS); /// An overload of ExpandResponseFiles() that uses /// llvm::vfs::getRealFileSystem(). diff --git a/llvm/lib/Support/CommandLine.cpp b/llvm/lib/Support/CommandLine.cpp --- a/llvm/lib/Support/CommandLine.cpp +++ b/llvm/lib/Support/CommandLine.cpp @@ -1136,11 +1136,11 @@ /// Expand response files on a command line recursively using the given /// StringSaver and tokenization strategy. -bool cl::ExpandResponseFiles(StringSaver &Saver, TokenizerCallback Tokenizer, - SmallVectorImpl &Argv, bool MarkEOLs, - bool RelativeNames, - llvm::Optional CurrentDir, - llvm::vfs::FileSystem &FS) { +llvm::Error cl::ExpandResponseFilesWithError( + StringSaver &Saver, TokenizerCallback Tokenizer, + SmallVectorImpl &Argv, bool MarkEOLs, bool RelativeNames, + llvm::Optional CurrentDir, llvm::vfs::FileSystem &FS) { + llvm::Error FirstError = llvm::Error::success(); bool AllExpanded = true; struct ResponseFileRecord { std::string File; @@ -1188,20 +1188,28 @@ llvm::sys::path::append(CurrDir, FName); FName = CurrDir.c_str(); } - auto IsEquivalent = [FName, &FS](const ResponseFileRecord &RFile) { + + auto IsEquivalent = [FName, &FS, + &FirstError](const ResponseFileRecord &RFile) { llvm::ErrorOr LHS = FS.status(FName); if (!LHS) { - // TODO: The error should be propagated up the stack. - llvm::consumeError(llvm::errorCodeToError(LHS.getError())); + if (!FirstError) + FirstError = llvm::errorCodeToError(LHS.getError()); return false; } llvm::ErrorOr RHS = FS.status(RFile.File); if (!RHS) { - // TODO: The error should be propagated up the stack. - llvm::consumeError(llvm::errorCodeToError(RHS.getError())); + if (!FirstError) + FirstError = llvm::errorCodeToError(RHS.getError()); + return false; + } + if (!LHS->equivalent(*RHS)) { + if (!FirstError) + FirstError = createStringError( + std::make_error_code(std::errc::invalid_argument), "RHS != LHS"); return false; } - return LHS->equivalent(*RHS); + return true; }; // Check for recursive response files. @@ -1221,8 +1229,8 @@ RelativeNames, FS)) { // We couldn't read this file, so we leave it in the argument stream and // move on. - // TODO: The error should be propagated up the stack. - llvm::consumeError(std::move(Err)); + if (!FirstError) + FirstError = std::move(Err); AllExpanded = false; ++I; continue; @@ -1245,9 +1253,23 @@ // don't have a chance to pop the stack when encountering recursive files at // the end of the stream, so seeing that doesn't indicate a bug. assert(FileStack.size() > 0 && Argv.size() == FileStack.back().End); - return AllExpanded; + assert(AllExpanded == !FirstError); + return FirstError; } +/// Expand response files on a command line recursively using the given +/// StringSaver and tokenization strategy. +bool cl::ExpandResponseFiles(StringSaver &Saver, TokenizerCallback Tokenizer, + SmallVectorImpl &Argv, bool MarkEOLs, + bool RelativeNames, + llvm::Optional CurrentDir, + llvm::vfs::FileSystem &FS) { + if (ExpandResponseFilesWithError(Saver, std::move(Tokenizer), Argv, MarkEOLs, + RelativeNames, std::move(CurrentDir), + *vfs::getRealFileSystem())) + return false; + return true; +} bool cl::ExpandResponseFiles(StringSaver &Saver, TokenizerCallback Tokenizer, SmallVectorImpl &Argv, bool MarkEOLs, bool RelativeNames,