Rebase & update the patch according to rnk's and rafael's suggestions on D4896.

http://reviews.llvm.org/D4897

Files:
  include/clang/Driver/Compilation.h
  include/clang/Driver/Job.h
  include/clang/Driver/Tool.h
  lib/Driver/Compilation.cpp
  lib/Driver/Job.cpp
  lib/Driver/Tools.cpp
  lib/Driver/Tools.h
  test/Driver/response-file.c
Index: include/clang/Driver/Compilation.h
===================================================================
--- include/clang/Driver/Compilation.h
+++ include/clang/Driver/Compilation.h
@@ -94,7 +94,7 @@
   JobList &getJobs() { return Jobs; }
   const JobList &getJobs() const { return Jobs; }
 
-  void addCommand(Command *C) { Jobs.addJob(C); }
+  void addCommand(Command *C);
 
   const llvm::opt::ArgStringList &getTempFiles() const { return TempFiles; }
 
Index: include/clang/Driver/Job.h
===================================================================
--- include/clang/Driver/Job.h
+++ include/clang/Driver/Job.h
@@ -72,13 +72,33 @@
   /// argument, which will be the executable).
   llvm::opt::ArgStringList Arguments;
 
+  /// Whether this job will need to write its arguments to a disk file
+  const bool needsResponseFile;
+
+  /// Response file name
+  const char *ResponseFile;
+
+  /// The input file list in case we need to emit a file list instead of a
+  /// proper response file
+  llvm::opt::ArgStringList InputFileList;
+
+  /// Helps Command::Print to precisely describe the contents of a reponse
+  /// file, when it is used.
+  void PrintArgsWithRespFile(llvm::raw_ostream &OS,
+                             const char *Terminator, bool Quote,
+                             bool CrashReport) const;
+
 public:
   Command(const Action &_Source, const Tool &_Creator, const char *_Executable,
           const llvm::opt::ArgStringList &_Arguments);
 
   void Print(llvm::raw_ostream &OS, const char *Terminator, bool Quote,
              bool CrashReport = false) const override;
 
+  /// Checks whether the given command line arguments fit within system
+  /// limits (the maximum command line length).
+  bool NeedsResponseFile() const { return needsResponseFile; }
+
   virtual int Execute(const StringRef **Redirects, std::string *ErrMsg,
                       bool *ExecutionFailed) const;
 
@@ -88,6 +108,9 @@
   /// getCreator - Return the Tool which caused the creation of this job.
   const Tool &getCreator() const { return Creator; }
 
+  void setResponseFile(const char *FileName) { ResponseFile = FileName; }
+  void setInputFileList(llvm::opt::ArgStringList List) { InputFileList = List; }
+
   const char *getExecutable() const { return Executable; }
 
   const llvm::opt::ArgStringList &getArguments() const { return Arguments; }
Index: include/clang/Driver/Tool.h
===================================================================
--- include/clang/Driver/Tool.h
+++ include/clang/Driver/Tool.h
@@ -11,6 +11,7 @@
 #define LLVM_CLANG_DRIVER_TOOL_H
 
 #include "clang/Basic/LLVM.h"
+#include "llvm/Support/Program.h"
 
 namespace llvm {
 namespace opt {
@@ -31,6 +32,24 @@
 
 /// Tool - Information on a specific compilation tool.
 class Tool {
+public:
+  // Documents the level of support for response files in this tool.
+  // Response files are necessary if the command line gets too large,
+  // requiring the arguments to be transfered to a file.
+  enum ResponseFileSupport {
+    // Provides full support for response files, which means we can transfer
+    // all tool input arguments to a file. E.g.: clang, gcc, binutils and MSVC
+    // tools.
+    RF_Full,
+    // Input file names can live in a file, but flags can't. E.g.: ld64 (Mac
+    // OS X linker).
+    RF_FileList,
+    // Does not support response files: all arguments must be passed via
+    // command line.
+    RF_None
+  };
+
+private:
   /// The tool name (for debugging).
   const char *Name;
 
@@ -57,6 +76,29 @@
   virtual bool hasIntegratedCPP() const = 0;
   virtual bool isLinkJob() const { return false; }
   virtual bool isDsymutilJob() const { return false; }
+  /// \brief Returns the level of support for response files of this tool,
+  /// whether it accepts arguments to be passed via a file on disk.
+  virtual ResponseFileSupport getResponseFilesSupport() const {
+    return RF_None;
+  }
+  /// \brief Returns which encoding the response file should use. This is only
+  /// relevant on Windows platforms where there are different encodings being
+  /// accepted for different tools. On UNIX, UTF8 is universal.
+  ///
+  /// Windows use cases: - GCC and Binutils on mingw only accept ANSI response
+  /// files encoded with the system current code page.
+  /// - MSVC's CL.exe and LINK.exe accept UTF16 on Windows.
+  /// - Clang accepts both UTF8 and UTF16.
+  ///
+  /// FIXME: When GNU tools learn how to parse UTF16 on Windows, we should
+  /// always use UTF16 for Windows, which is the Windows official encoding for
+  /// international characters.
+  virtual llvm::sys::EncodingMethod getResponseFileEncoding() const {
+    return llvm::sys::EM_UTF8;
+  }
+  /// \brief Returns which prefix to use when passing the name of a response
+  /// file as a parameter to this tool.
+  virtual const char *getResponseFileFlag() const { return "@"; }
 
   /// \brief Does this tool have "good" standardized diagnostics, or should the
   /// driver add an additional "command failed" diagnostic on failures.
Index: lib/Driver/Compilation.cpp
===================================================================
--- lib/Driver/Compilation.cpp
+++ lib/Driver/Compilation.cpp
@@ -52,6 +52,15 @@
   }
 }
 
+void Compilation::addCommand(Command *C) {
+  Jobs.addJob(C);
+  // Verify if we need a response file
+  if (C->NeedsResponseFile()) {
+    std::string TmpName = TheDriver.GetTemporaryPath("response", "txt");
+    C->setResponseFile(addTempFile(getArgs().MakeArgString(TmpName.c_str())));
+  }
+}
+
 const DerivedArgList &Compilation::getArgsForToolChain(const ToolChain *TC,
                                                        const char *BoundArch) {
   if (!TC)
@@ -88,7 +97,7 @@
     // Failure is only failure if the file exists and is "regular". We checked
     // for it being regular before, and llvm::sys::fs::remove ignores ENOENT,
     // so we don't need to check again.
-    
+
     if (IssueErrors)
       getDriver().Diag(clang::diag::err_drv_unable_to_remove_file)
         << EC.message();
Index: lib/Driver/Job.cpp
===================================================================
--- lib/Driver/Job.cpp
+++ lib/Driver/Job.cpp
@@ -28,7 +28,11 @@
                  const char *_Executable,
                  const ArgStringList &_Arguments)
     : Job(CommandClass), Source(_Source), Creator(_Creator),
-      Executable(_Executable), Arguments(_Arguments) {}
+      Executable(_Executable), Arguments(_Arguments),
+      needsResponseFile(
+          !llvm::sys::argumentsFitWithinSystemLimits(_Arguments) &&
+          Creator.getResponseFilesSupport() != Tool::RF_None),
+      ResponseFile(nullptr) {}
 
 static int skipArgs(const char *Flag) {
   // These flags are all of the form -Flag <Arg> and are treated as two
@@ -93,12 +97,185 @@
   OS << '"';
 }
 
+/// ArgNeedsQuotes - Check whether argument needs to be quoted when serializing
+/// it to a response file.
+static bool ArgNeedsQuotes(const char *Str) {
+  return Str[0] == '\0' || strpbrk(Str, "\t \"&\'()*<>\\`^|") != 0;
+}
+
+/// Returns the number of backslashes and quotes in this string. These
+/// characters need to be escaped in the response files of some tools, but
+/// others do not care. Thus, we escape for all response files.
+static unsigned int CountBackslashesAndQuotes(const char *Start) {
+  unsigned int Count = 0;
+  while (*Start != '\0') {
+    if (*Start == '\\' || *Start == '\"')
+      ++Count;
+    ++Start;
+  }
+  return Count;
+}
+
+/// Encodes the array of C strings into a single string separated by whitespace.
+/// This function will also put in quotes arguments that have whitespaces and
+/// will escape the regular backslashes (used in Windows paths) and quotes.
+static std::unique_ptr<char[]> FlattenArgs(const char **args) {
+  // First, determine the length of the command line.
+  unsigned len = 0;
+  for (unsigned i = 0; args[i]; i++) {
+    bool Quoted = ArgNeedsQuotes(args[i]);
+    len += Quoted ? 2 : 0;
+    len += CountBackslashesAndQuotes(args[i]) + strlen(args[i]) + 1;
+  }
+
+  // Now build the command line.
+  std::unique_ptr<char[]> command(new char[len + 1]);
+  char *p = command.get();
+
+  for (unsigned i = 0; args[i]; i++) {
+    const char *arg = args[i];
+
+    bool needsQuoting = ArgNeedsQuotes(arg);
+    if (needsQuoting)
+      *p++ = '"';
+
+    while (*arg != '\0') {
+      if (*arg == '\"' || *arg == '\\') {
+        *p++ = '\\';
+      }
+      *p++ = *arg++;
+    }
+
+    if (needsQuoting) {
+      *p++ = '"';
+    }
+    *p++ = ' ';
+  }
+
+  *p = 0;
+  return command;
+}
+
+/// Read the list of input files in Inputs and adjusts Argv accordingly,
+/// removing the elements of Inputs from Argv (since they will be passed via a
+/// response file). This function will also Insert the response file name in
+/// argv. Finally, it returns a C string with the contents of the response
+/// file (the input file list separated by newlines).
+static std::unique_ptr<char[]>
+FlattenFileList(const llvm::SmallVectorImpl<const char *> &Inputs,
+                llvm::SmallVectorImpl<const char *> &Argv,
+                const char *ResponseFlag, const char *ResponseFile) {
+  llvm::SmallVector<const char *, 128> NewArgv;
+  unsigned len = 0;
+  for (auto Input : Inputs) {
+    len += strlen(Input) + 1;
+  }
+  bool FirstInput = true;
+  for (auto Arg : Argv) {
+    if (Arg == nullptr) {
+      NewArgv.push_back(Arg);
+      break;
+    }
+    bool found = false;
+    for (auto InputName : Inputs) {
+      if (strcmp(Arg, InputName) == 0) {
+        found = true;
+        break;
+      }
+    }
+    if (!found) {
+      NewArgv.push_back(Arg);
+    } else if (FirstInput) {
+      FirstInput = false;
+      NewArgv.push_back(ResponseFlag);
+      NewArgv.push_back(ResponseFile);
+    }
+  }
+  Argv = NewArgv;
+  // Now build the file list.
+  std::unique_ptr<char[]> command(new char[len + 1]);
+  char *p = command.get();
+  for (auto Arg : Inputs) {
+    const char *src = Arg;
+    while (*src != '\0')
+      *p++ = *src++;
+    *p++ = '\n';
+  }
+  *p = 0;
+  return command;
+}
+
+void Command::PrintArgsWithRespFile(raw_ostream &OS,
+                                    const char *Terminator, bool Quote,
+                                    bool CrashReport) const {
+  std::string ResponseFlag = Creator.getResponseFileFlag();
+  ResponseFlag += ResponseFile;
+  OS << ' ';
+
+  llvm::opt::ArgStringList Argv = Arguments;
+  Argv.push_back(nullptr);
+  std::unique_ptr<char[]> FlattenedArgs;
+  Tool::ResponseFileSupport RespFileSup = Creator.getResponseFilesSupport();
+  if (RespFileSup == Tool::RF_FileList) {
+    FlattenedArgs = FlattenFileList(InputFileList, Argv,
+                                    Creator.getResponseFileFlag(),
+                                    ResponseFile);
+  } else {
+    FlattenedArgs = FlattenArgs(Argv.data());
+    Argv.clear();
+  }
+
+  // Print args that are not in the FileList (if it is a proper response file
+  // rather than a file list, all arguments go into the response file and Argv
+  // is empty).
+  for (size_t i = 0, e = Argv.size(); i < e; ++i) {
+    const char *const Arg = Argv[i];
+    if (Arg == nullptr)
+      break;
+
+    if (CrashReport) {
+      if (int Skip = skipArgs(Arg)) {
+        i += Skip - 1;
+        continue;
+      }
+    }
+
+    OS << ' ';
+    PrintArg(OS, Arg, Quote);
+
+    if (CrashReport && quoteNextArg(Arg) && i + 1 < e) {
+      OS << ' ';
+      PrintArg(OS, Arguments[++i], true);
+    }
+  }
+  // Now print our response file flag and print the contents that we will put in
+  // a response file. If it is a FileList, FlattenFileList() already put the
+  // flag in Argv and there is no need to print it again.
+  if (RespFileSup != Tool::RF_FileList) {
+    PrintArg(OS, ResponseFlag.c_str(), Quote);
+  }
+  OS << "\n Arguments passed via response file:\n";
+  OS << FlattenedArgs.get();
+  // Avoiding duplicated newline terminator, since FileLists are
+  // newline-separated.
+  if (RespFileSup != Tool::RF_FileList) {
+    OS << "\n";
+  }
+  OS << " (end of response file)";
+  OS << Terminator;
+}
+
 void Command::Print(raw_ostream &OS, const char *Terminator, bool Quote,
                     bool CrashReport) const {
   // Always quote the exe.
   OS << ' ';
   PrintArg(OS, Executable, /*Quote=*/true);
 
+  if (needsResponseFile && ResponseFile != nullptr) {
+    PrintArgsWithRespFile(OS, Terminator, Quote, CrashReport);
+    return;
+  }
+
   for (size_t i = 0, e = Arguments.size(); i < e; ++i) {
     const char *const Arg = Arguments[i];
 
@@ -128,6 +305,44 @@
     Argv.push_back(Arguments[i]);
   Argv.push_back(nullptr);
 
+  if (ResponseFile == nullptr || !needsResponseFile) {
+    return llvm::sys::ExecuteAndWait(Executable, Argv.data(), /*env*/ nullptr,
+                                     Redirects, /*secondsToWait*/ 0,
+                                     /*memoryLimit*/ 0, ErrMsg,
+                                     ExecutionFailed);
+  }
+
+  // We need to put arguments in a response file (command is too large)
+  std::string ResponseFlag;
+  std::unique_ptr<char[]> FlattenedArgs;
+  Tool::ResponseFileSupport RespFileSup = Creator.getResponseFilesSupport();
+  ResponseFlag = Creator.getResponseFileFlag();
+  ResponseFlag += ResponseFile;
+  if (RespFileSup == Tool::RF_FileList)
+    FlattenedArgs = FlattenFileList(InputFileList, Argv,
+                                    Creator.getResponseFileFlag(),
+                                    ResponseFile);
+  else
+    FlattenedArgs = FlattenArgs(Argv.data() + 1 /* Skip exec name */);
+
+  if (llvm::sys::writeFileWithEncoding(ResponseFile, FlattenedArgs.get(),
+                                       ErrMsg,
+                                       Creator.getResponseFileEncoding())) {
+    if (ExecutionFailed)
+      *ExecutionFailed = true;
+    return -1;
+  }
+
+  // Substitute the argument vector with a single argument to supply the
+  // response file. In case of a FileList, FlattenFileList() already prepared
+  // Argv with the correct arguments.
+  if (RespFileSup != Tool::RF_FileList) {
+    Argv.clear();
+    Argv.push_back(Executable);
+    Argv.push_back(ResponseFlag.c_str());
+    Argv.push_back(nullptr);
+  }
+
   return llvm::sys::ExecuteAndWait(Executable, Argv.data(), /*env*/ nullptr,
                                    Redirects, /*secondsToWait*/ 0,
                                    /*memoryLimit*/ 0, ErrMsg, ExecutionFailed);
Index: lib/Driver/Tools.cpp
===================================================================
--- lib/Driver/Tools.cpp
+++ lib/Driver/Tools.cpp
@@ -506,7 +506,7 @@
   } else
     D.Diag(diag::err_drv_clang_unsupported) << A->getAsString(Args);
 }
- 
+
 // Handle -mfpu=.
 //
 // FIXME: Centralize feature selection, defaulting shouldn't be also in the
@@ -815,7 +815,7 @@
     }
   }
 
-  // Setting -mno-global-merge disables the codegen global merge pass. Setting 
+  // Setting -mno-global-merge disables the codegen global merge pass. Setting
   // -mglobal-merge has no effect as the pass is enabled by default.
   if (Arg *A = Args.getLastArg(options::OPT_mglobal_merge,
                                options::OPT_mno_global_merge)) {
@@ -2507,7 +2507,7 @@
 
   // Select the appropriate action.
   RewriteKind rewriteKind = RK_None;
-  
+
   if (isa<AnalyzeJobAction>(JA)) {
     assert(JA.getType() == types::TY_Plist && "Invalid output type.");
     CmdArgs.push_back("-analyze");
@@ -2609,18 +2609,18 @@
 
       if (getToolChain().getTriple().getVendor() == llvm::Triple::Apple)
         CmdArgs.push_back("-analyzer-checker=osx");
-      
+
       CmdArgs.push_back("-analyzer-checker=deadcode");
-      
+
       if (types::isCXX(Inputs[0].getType()))
         CmdArgs.push_back("-analyzer-checker=cplusplus");
 
       // Enable the following experimental checkers for testing.
       CmdArgs.push_back(
           "-analyzer-checker=security.insecureAPI.UncheckedReturn");
       CmdArgs.push_back("-analyzer-checker=security.insecureAPI.getpw");
       CmdArgs.push_back("-analyzer-checker=security.insecureAPI.gets");
-      CmdArgs.push_back("-analyzer-checker=security.insecureAPI.mktemp");      
+      CmdArgs.push_back("-analyzer-checker=security.insecureAPI.mktemp");
       CmdArgs.push_back("-analyzer-checker=security.insecureAPI.mkstemp");
       CmdArgs.push_back("-analyzer-checker=security.insecureAPI.vfork");
     }
@@ -2845,7 +2845,7 @@
   // This alias option is being used to simplify the getLastArg logic.
   OptSpecifier FastMathAliasOption = OFastEnabled ? options::OPT_Ofast :
     options::OPT_ffast_math;
-  
+
   // Handle various floating point optimization flags, mapping them to the
   // appropriate LLVM code generation flags. The pattern for all of these is to
   // default off the codegen optimizations, and if any flag enables them and no
@@ -2944,7 +2944,7 @@
     CmdArgs.push_back("-menable-unsafe-fp-math");
 
 
-  // Validate and pass through -fp-contract option. 
+  // Validate and pass through -fp-contract option.
   if (Arg *A = Args.getLastArg(options::OPT_ffast_math, FastMathAliasOption,
                                options::OPT_fno_fast_math,
                                options::OPT_ffp_contract)) {
@@ -3590,7 +3590,7 @@
   Args.AddLastArg(CmdArgs, options::OPT_fno_standalone_debug);
   Args.AddLastArg(CmdArgs, options::OPT_fno_operator_names);
   // AltiVec language extensions aren't relevant for assembling.
-  if (!isa<PreprocessJobAction>(JA) || 
+  if (!isa<PreprocessJobAction>(JA) ||
       Output.getType() != types::TY_PP_Asm)
     Args.AddLastArg(CmdArgs, options::OPT_faltivec);
   Args.AddLastArg(CmdArgs, options::OPT_fdiagnostics_show_template_tree);
@@ -3776,7 +3776,7 @@
          !Args.hasArg(options::OPT_fno_blocks))) {
     CmdArgs.push_back("-fblocks");
 
-    if (!Args.hasArg(options::OPT_fgnu_runtime) && 
+    if (!Args.hasArg(options::OPT_fgnu_runtime) &&
         !getToolChain().hasBlocksRuntime())
       CmdArgs.push_back("-fblocks-runtime-optional");
   }
@@ -3786,8 +3786,8 @@
   // modules implementation is solid for C++/Objective-C++ programs as well.
   bool HaveModules = false;
   if (Args.hasFlag(options::OPT_fmodules, options::OPT_fno_modules, false)) {
-    bool AllowedInCXX = Args.hasFlag(options::OPT_fcxx_modules, 
-                                     options::OPT_fno_cxx_modules, 
+    bool AllowedInCXX = Args.hasFlag(options::OPT_fcxx_modules,
+                                     options::OPT_fno_cxx_modules,
                                      false);
     if (AllowedInCXX || !types::isCXX(InputType)) {
       CmdArgs.push_back("-fmodules");
@@ -3957,7 +3957,7 @@
     CmdArgs.push_back("-fms-extensions");
 
   // -fms-compatibility=0 is default.
-  if (Args.hasFlag(options::OPT_fms_compatibility, 
+  if (Args.hasFlag(options::OPT_fms_compatibility,
                    options::OPT_fno_ms_compatibility,
                    (IsWindowsMSVC && Args.hasFlag(options::OPT_fms_extensions,
                                                   options::OPT_fno_ms_extensions,
@@ -4044,12 +4044,12 @@
       objcRuntime.getKind() == ObjCRuntime::FragileMacOSX &&
       objcRuntime.isNeXTFamily())
     CmdArgs.push_back("-fobjc-subscripting-legacy-runtime");
-  
+
   // -fencode-extended-block-signature=1 is default.
   if (getToolChain().IsEncodeExtendedBlockSignatureDefault()) {
     CmdArgs.push_back("-fencode-extended-block-signature");
   }
-  
+
   // Allow -fno-objc-arr to trump -fobjc-arr/-fobjc-arc.
   // NOTE: This logic is duplicated in ToolChains.cpp.
   bool ARC = isObjCAutoRefCount(Args);
@@ -4343,7 +4343,7 @@
                    options::OPT_fno_apple_pragma_pack, false))
     CmdArgs.push_back("-fapple-pragma-pack");
 
-  // le32-specific flags: 
+  // le32-specific flags:
   //  -fno-math-builtin: clang should not convert math builtins to intrinsics
   //                     by default.
   if (getToolChain().getArch() == llvm::Triple::le32) {
@@ -4384,7 +4384,7 @@
 
   Args.AddLastArg(CmdArgs, options::OPT_dM);
   Args.AddLastArg(CmdArgs, options::OPT_dD);
-  
+
   // Handle serialized diagnostics.
   if (Arg *A = Args.getLastArg(options::OPT__serialize_diags)) {
     CmdArgs.push_back("-serialize-diagnostic-file");
@@ -4550,8 +4550,8 @@
         << value;
   } else {
     // Otherwise, determine if we are using the non-fragile ABI.
-    bool nonFragileABIIsDefault = 
-      (rewriteKind == RK_NonFragile || 
+    bool nonFragileABIIsDefault =
+      (rewriteKind == RK_NonFragile ||
        (rewriteKind == RK_None &&
         getToolChain().IsObjCNonFragileABIDefault()));
     if (args.hasFlag(options::OPT_fobjc_nonfragile_abi,
@@ -4804,7 +4804,7 @@
 
   // Add the "effective" target triple.
   CmdArgs.push_back("-triple");
-  std::string TripleStr = 
+  std::string TripleStr =
     getToolChain().ComputeEffectiveClangTriple(Args, Input.getType());
   CmdArgs.push_back(Args.MakeArgString(TripleStr));
 
@@ -5780,6 +5780,12 @@
                                 const char *LinkingOutput) const {
   assert(Output.getType() == types::TY_Image && "Invalid linker output type.");
 
+  // If the number of arguments surpasses the system limits, we will encode the
+  // input files in a separate file, shortening the command line. To this end,
+  // build a list of input file names that can be passed via a file with the
+  // -filelist linker option.
+  llvm::opt::ArgStringList InputFileList;
+
   // The logic here is derived from gcc's behavior; most of which
   // comes from specs (starting with link_command). Consult gcc for
   // more information.
@@ -5848,7 +5854,21 @@
   }
 
   AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs);
-  
+  // Build the input file for -filelist (list of linker input files) in case we
+  // need it later
+  for (const auto &II : Inputs) {
+    if (II.isFilename()) {
+      InputFileList.push_back(II.getFilename());
+      continue;
+    }
+
+    // This is a linker input argument.
+    // We cannot mix input arguments and file names in a -filelist input, thus
+    // we prematurely stop our list (remaining files shall be passed as
+    // arguments).
+    break;
+  }
+
   if (isObjCRuntimeLinked(Args) &&
       !Args.hasArg(options::OPT_nostdlib) &&
       !Args.hasArg(options::OPT_nodefaultlibs)) {
@@ -5891,7 +5911,10 @@
 
   const char *Exec =
     Args.MakeArgString(getToolChain().GetLinkerPath());
-  C.addCommand(new Command(JA, *this, Exec, CmdArgs));
+  Command *Cmd = new Command(JA, *this, Exec, CmdArgs);
+  if (Cmd->NeedsResponseFile())
+    Cmd->setInputFileList(InputFileList);
+  C.addCommand(Cmd);
 }
 
 void darwin::Lipo::ConstructJob(Compilation &C, const JobAction &JA,
@@ -6209,7 +6232,7 @@
   if (!Args.hasArg(options::OPT_nostdlib) &&
       !Args.hasArg(options::OPT_nostartfiles)) {
     if (!Args.hasArg(options::OPT_shared)) {
-      if (Args.hasArg(options::OPT_pg))  
+      if (Args.hasArg(options::OPT_pg))
         CmdArgs.push_back(Args.MakeArgString(
                                 getToolChain().GetFilePath("gcrt0.o")));
       else
@@ -6243,7 +6266,7 @@
       !Args.hasArg(options::OPT_nodefaultlibs)) {
     if (D.CCCIsCXX()) {
       getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs);
-      if (Args.hasArg(options::OPT_pg)) 
+      if (Args.hasArg(options::OPT_pg))
         CmdArgs.push_back("-lm_p");
       else
         CmdArgs.push_back("-lm");
@@ -6508,7 +6531,7 @@
                                  const InputInfoList &Inputs,
                                  const ArgList &Args,
                                  const char *LinkingOutput) const {
-  const toolchains::FreeBSD& ToolChain = 
+  const toolchains::FreeBSD& ToolChain =
     static_cast<const toolchains::FreeBSD&>(getToolChain());
   const Driver &D = ToolChain.getDriver();
   const bool IsPIE =
@@ -6744,7 +6767,7 @@
     break;
 
   default:
-    break;  
+    break;
   }
 
   Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA,
Index: lib/Driver/Tools.h
===================================================================
--- lib/Driver/Tools.h
+++ lib/Driver/Tools.h
@@ -95,6 +95,12 @@
     bool hasGoodDiagnostics() const override { return true; }
     bool hasIntegratedAssembler() const override { return true; }
     bool hasIntegratedCPP() const override { return true; }
+    ResponseFileSupport getResponseFilesSupport() const override {
+      return RF_Full;
+    }
+    llvm::sys::EncodingMethod getResponseFileEncoding() const override {
+      return llvm::sys::EM_UTF8;
+    }
 
     void ConstructJob(Compilation &C, const JobAction &JA,
                       const InputInfo &Output, const InputInfoList &Inputs,
@@ -111,6 +117,12 @@
     bool hasGoodDiagnostics() const override { return true; }
     bool hasIntegratedAssembler() const override { return false; }
     bool hasIntegratedCPP() const override { return false; }
+    ResponseFileSupport getResponseFilesSupport() const override {
+      return RF_Full;
+    }
+    llvm::sys::EncodingMethod getResponseFileEncoding() const override {
+      return llvm::sys::EM_UTF8;
+    }
 
     void ConstructJob(Compilation &C, const JobAction &JA,
                       const InputInfo &Output, const InputInfoList &Inputs,
@@ -130,6 +142,16 @@
                       const InputInfoList &Inputs,
                       const llvm::opt::ArgList &TCArgs,
                       const char *LinkingOutput) const override;
+    ResponseFileSupport getResponseFilesSupport() const override {
+      return RF_Full;
+    }
+    llvm::sys::EncodingMethod getResponseFileEncoding() const override {
+#if defined(LLVM_ON_WIN32)
+      return llvm::sys::EM_CurrentCodePage;
+#else
+      return llvm::sys::EM_UTF8;
+#endif
+    }
 
     /// RenderExtraToolArgs - Render any arguments necessary to force
     /// the particular tool mode.
@@ -191,6 +213,16 @@
                       const InputInfo &Output, const InputInfoList &Inputs,
                       const llvm::opt::ArgList &TCArgs,
                       const char *LinkingOutput) const override;
+    ResponseFileSupport getResponseFilesSupport() const override {
+      return RF_Full;
+    }
+    llvm::sys::EncodingMethod getResponseFileEncoding() const override {
+#if defined(LLVM_ON_WIN32)
+      return llvm::sys::EM_CurrentCodePage;
+#else
+      return llvm::sys::EM_UTF8;
+#endif
+    }
   };
 
   class LLVM_LIBRARY_VISIBILITY Link : public Tool {
@@ -207,6 +239,16 @@
                       const InputInfo &Output, const InputInfoList &Inputs,
                       const llvm::opt::ArgList &TCArgs,
                       const char *LinkingOutput) const override;
+    ResponseFileSupport getResponseFilesSupport() const override {
+      return RF_Full;
+    }
+    llvm::sys::EncodingMethod getResponseFileEncoding() const override {
+#if defined(LLVM_ON_WIN32)
+      return llvm::sys::EM_CurrentCodePage;
+#else
+      return llvm::sys::EM_UTF8;
+#endif
+    }
   };
 } // end namespace hexagon.
 
@@ -276,6 +318,12 @@
 
     bool hasIntegratedCPP() const override { return false; }
     bool isLinkJob() const override { return true; }
+    ResponseFileSupport getResponseFilesSupport() const override {
+      return RF_FileList;
+    }
+    virtual const char *getResponseFileFlag() const override {
+      return "-filelist";
+    }
 
     void ConstructJob(Compilation &C, const JobAction &JA,
                       const InputInfo &Output, const InputInfoList &Inputs,
@@ -339,6 +387,17 @@
                       const InputInfoList &Inputs,
                       const llvm::opt::ArgList &TCArgs,
                       const char *LinkingOutput) const override;
+
+    ResponseFileSupport getResponseFilesSupport() const override {
+      return RF_Full;
+    }
+    llvm::sys::EncodingMethod getResponseFileEncoding() const override {
+#if defined(LLVM_ON_WIN32)
+      return llvm::sys::EM_CurrentCodePage;
+#else
+      return llvm::sys::EM_UTF8;
+#endif
+    }
   };
   class LLVM_LIBRARY_VISIBILITY Link : public Tool  {
   public:
@@ -351,6 +410,17 @@
                       const InputInfo &Output, const InputInfoList &Inputs,
                       const llvm::opt::ArgList &TCArgs,
                       const char *LinkingOutput) const override;
+
+    ResponseFileSupport getResponseFilesSupport() const override {
+      return RF_Full;
+    }
+    llvm::sys::EncodingMethod getResponseFileEncoding() const override {
+#if defined(LLVM_ON_WIN32)
+      return llvm::sys::EM_CurrentCodePage;
+#else
+      return llvm::sys::EM_UTF8;
+#endif
+    }
   };
 } // end namespace openbsd
 
@@ -367,6 +437,17 @@
                       const InputInfo &Output, const InputInfoList &Inputs,
                       const llvm::opt::ArgList &TCArgs,
                       const char *LinkingOutput) const override;
+
+    ResponseFileSupport getResponseFilesSupport() const override {
+      return RF_Full;
+    }
+    llvm::sys::EncodingMethod getResponseFileEncoding() const override {
+#if defined(LLVM_ON_WIN32)
+      return llvm::sys::EM_CurrentCodePage;
+#else
+      return llvm::sys::EM_UTF8;
+#endif
+    }
   };
   class LLVM_LIBRARY_VISIBILITY Link : public Tool  {
   public:
@@ -379,6 +460,17 @@
                       const InputInfo &Output, const InputInfoList &Inputs,
                       const llvm::opt::ArgList &TCArgs,
                       const char *LinkingOutput) const override;
+
+    ResponseFileSupport getResponseFilesSupport() const override {
+      return RF_Full;
+    }
+    llvm::sys::EncodingMethod getResponseFileEncoding() const override {
+#if defined(LLVM_ON_WIN32)
+      return llvm::sys::EM_CurrentCodePage;
+#else
+      return llvm::sys::EM_UTF8;
+#endif
+    }
   };
 } // end namespace bitrig
 
@@ -395,6 +487,17 @@
                       const InputInfo &Output, const InputInfoList &Inputs,
                       const llvm::opt::ArgList &TCArgs,
                       const char *LinkingOutput) const override;
+
+    ResponseFileSupport getResponseFilesSupport() const override {
+      return RF_Full;
+    }
+    llvm::sys::EncodingMethod getResponseFileEncoding() const override {
+#if defined(LLVM_ON_WIN32)
+      return llvm::sys::EM_CurrentCodePage;
+#else
+      return llvm::sys::EM_UTF8;
+#endif
+    }
   };
   class LLVM_LIBRARY_VISIBILITY Link : public Tool  {
   public:
@@ -407,6 +510,17 @@
                       const InputInfo &Output, const InputInfoList &Inputs,
                       const llvm::opt::ArgList &TCArgs,
                       const char *LinkingOutput) const override;
+
+    ResponseFileSupport getResponseFilesSupport() const override {
+      return RF_Full;
+    }
+    llvm::sys::EncodingMethod getResponseFileEncoding() const override {
+#if defined(LLVM_ON_WIN32)
+      return llvm::sys::EM_CurrentCodePage;
+#else
+      return llvm::sys::EM_UTF8;
+#endif
+    }
   };
 } // end namespace freebsd
 
@@ -424,6 +538,17 @@
                       const InputInfo &Output, const InputInfoList &Inputs,
                       const llvm::opt::ArgList &TCArgs,
                       const char *LinkingOutput) const override;
+
+    ResponseFileSupport getResponseFilesSupport() const override {
+      return RF_Full;
+    }
+    llvm::sys::EncodingMethod getResponseFileEncoding() const override {
+#if defined(LLVM_ON_WIN32)
+      return llvm::sys::EM_CurrentCodePage;
+#else
+      return llvm::sys::EM_UTF8;
+#endif
+    }
   };
   class LLVM_LIBRARY_VISIBILITY Link : public Tool  {
 
@@ -438,6 +563,17 @@
                       const InputInfo &Output, const InputInfoList &Inputs,
                       const llvm::opt::ArgList &TCArgs,
                       const char *LinkingOutput) const override;
+
+    ResponseFileSupport getResponseFilesSupport() const override {
+      return RF_Full;
+    }
+    llvm::sys::EncodingMethod getResponseFileEncoding() const override {
+#if defined(LLVM_ON_WIN32)
+      return llvm::sys::EM_CurrentCodePage;
+#else
+      return llvm::sys::EM_UTF8;
+#endif
+    }
   };
 } // end namespace netbsd
 
@@ -454,13 +590,34 @@
                       const InputInfoList &Inputs,
                       const llvm::opt::ArgList &TCArgs,
                       const char *LinkingOutput) const override;
+
+    ResponseFileSupport getResponseFilesSupport() const override {
+      return RF_Full;
+    }
+    llvm::sys::EncodingMethod getResponseFileEncoding() const override {
+#if defined(LLVM_ON_WIN32)
+      return llvm::sys::EM_CurrentCodePage;
+#else
+      return llvm::sys::EM_UTF8;
+#endif
+    }
   };
   class LLVM_LIBRARY_VISIBILITY Link : public Tool  {
   public:
     Link(const ToolChain &TC) : Tool("GNU::Link", "linker", TC) {}
 
     bool hasIntegratedCPP() const override { return false; }
     bool isLinkJob() const override { return true; }
+    ResponseFileSupport getResponseFilesSupport() const override {
+      return RF_Full;
+    }
+    llvm::sys::EncodingMethod getResponseFileEncoding() const override {
+#if defined(LLVM_ON_WIN32)
+      return llvm::sys::EM_CurrentCodePage;
+#else
+      return llvm::sys::EM_UTF8;
+#endif
+    }
 
     void ConstructJob(Compilation &C, const JobAction &JA,
                       const InputInfo &Output,
@@ -483,6 +640,17 @@
                       const InputInfoList &Inputs,
                       const llvm::opt::ArgList &TCArgs,
                       const char *LinkingOutput) const override;
+
+    ResponseFileSupport getResponseFilesSupport() const override {
+      return RF_Full;
+    }
+    llvm::sys::EncodingMethod getResponseFileEncoding() const override {
+#if defined(LLVM_ON_WIN32)
+      return llvm::sys::EM_CurrentCodePage;
+#else
+      return llvm::sys::EM_UTF8;
+#endif
+    }
   };
   class LLVM_LIBRARY_VISIBILITY Link : public Tool  {
   public:
@@ -496,6 +664,17 @@
                       const InputInfoList &Inputs,
                       const llvm::opt::ArgList &TCArgs,
                       const char *LinkingOutput) const override;
+
+    ResponseFileSupport getResponseFilesSupport() const override {
+      return RF_Full;
+    }
+    llvm::sys::EncodingMethod getResponseFileEncoding() const override {
+#if defined(LLVM_ON_WIN32)
+      return llvm::sys::EM_CurrentCodePage;
+#else
+      return llvm::sys::EM_UTF8;
+#endif
+    }
   };
 } // end namespace minix
 
@@ -540,6 +719,17 @@
                       const InputInfo &Output, const InputInfoList &Inputs,
                       const llvm::opt::ArgList &TCArgs,
                       const char *LinkingOutput) const override;
+
+    ResponseFileSupport getResponseFilesSupport() const override {
+      return RF_Full;
+    }
+    llvm::sys::EncodingMethod getResponseFileEncoding() const override {
+#if defined(LLVM_ON_WIN32)
+      return llvm::sys::EM_CurrentCodePage;
+#else
+      return llvm::sys::EM_UTF8;
+#endif
+    }
   };
   class LLVM_LIBRARY_VISIBILITY Link : public Tool  {
   public:
@@ -553,6 +743,17 @@
                       const InputInfoList &Inputs,
                       const llvm::opt::ArgList &TCArgs,
                       const char *LinkingOutput) const override;
+
+    ResponseFileSupport getResponseFilesSupport() const override {
+      return RF_Full;
+    }
+    llvm::sys::EncodingMethod getResponseFileEncoding() const override {
+#if defined(LLVM_ON_WIN32)
+      return llvm::sys::EM_CurrentCodePage;
+#else
+      return llvm::sys::EM_UTF8;
+#endif
+    }
   };
 } // end namespace dragonfly
 
@@ -564,6 +765,12 @@
 
     bool hasIntegratedCPP() const override { return false; }
     bool isLinkJob() const override { return true; }
+    ResponseFileSupport getResponseFilesSupport() const override {
+      return RF_Full;
+    }
+    llvm::sys::EncodingMethod getResponseFileEncoding() const override {
+      return llvm::sys::EM_UTF16;
+    }
 
     void ConstructJob(Compilation &C, const JobAction &JA,
                       const InputInfo &Output, const InputInfoList &Inputs,
@@ -578,6 +785,12 @@
     bool hasIntegratedAssembler() const override { return true; }
     bool hasIntegratedCPP() const override { return true; }
     bool isLinkJob() const override { return false; }
+    ResponseFileSupport getResponseFilesSupport() const override {
+      return RF_Full;
+    }
+    llvm::sys::EncodingMethod getResponseFileEncoding() const override {
+      return llvm::sys::EM_UTF16;
+    }
 
     void ConstructJob(Compilation &C, const JobAction &JA,
                       const InputInfo &Output, const InputInfoList &Inputs,
Index: test/Driver/response-file.c
===================================================================
--- /dev/null
+++ test/Driver/response-file.c
@@ -0,0 +1,26 @@
+// REQUIRES: long_tests
+
+// Check that clang is able to process short response files
+// Since this is a short response file, clang must not use a response file
+// to pass its parameters to other tools. This is only necessary for a large
+// number of parameters.
+// RUN: echo "-DTEST" >> %t.0.txt
+// RUN: %clang -E @%t.0.txt %s -v 2>&1 | FileCheck %s -check-prefix=SHORT
+// SHORT-NOT: Arguments passed via response file
+// SHORT: -D TEST
+// SHORT: extern int it_works;
+
+// Check that clang is able to process long response files, routing a long
+// sequence of arguments to other tools by using response files as well.
+// We generate a 2MB response file to be big enough to surpass any system
+// limit.
+// RUN: awk "BEGIN { while (count++<300000) string=string \"-DTEST \";\
+// RUN:     print string }" > %t.1.txt
+// RUN: %clang -E @%t.1.txt %s -v 2>&1 | FileCheck %s -check-prefix=LONG
+// LONG: Arguments passed via response file
+// LONG: -D TEST
+// LONG: extern int it_works;
+
+#ifdef TEST
+extern int it_works;
+#endif
_______________________________________________
cfe-commits mailing list
cfe-commits@cs.uiuc.edu
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to