Revert r167567, restoring the ability of clang to run gcc in cases where it
can't handle the input file type. This resulted in PR14338.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@168024 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp
index 9ab35ff..b1e450d 100644
--- a/lib/Driver/Tools.cpp
+++ b/lib/Driver/Tools.cpp
@@ -257,7 +257,7 @@
                A->getOption().matches(options::OPT_MM)) {
       DepFile = "-";
     } else {
-      DepFile = getDependencyFileName(Args, Inputs);
+      DepFile = darwin::CC1::getDependencyFileName(Args, Inputs);
       C.addFailureResultFile(DepFile);
     }
     CmdArgs.push_back("-dependency-file");
@@ -1713,10 +1713,10 @@
   // Set the main file name, so that debug info works even with
   // -save-temps.
   CmdArgs.push_back("-main-file-name");
-  CmdArgs.push_back(getBaseInputName(Args, Inputs));
+  CmdArgs.push_back(darwin::CC1::getBaseInputName(Args, Inputs));
 
   // Some flags which affect the language (via preprocessor
-  // defines).
+  // defines). See darwin::CC1::AddCPPArgs.
   if (Args.hasArg(options::OPT_static))
     CmdArgs.push_back("-static-define");
 
@@ -3636,14 +3636,38 @@
     .Default(llvm::Triple::UnknownArch);
 }
 
-const char *Clang::getBaseInputName(const ArgList &Args,
-                                    const InputInfoList &Inputs) {
+const char *darwin::CC1::getCC1Name(types::ID Type) const {
+  switch (Type) {
+  default:
+    llvm_unreachable("Unexpected type for Darwin CC1 tool.");
+  case types::TY_Asm:
+  case types::TY_C: case types::TY_CHeader:
+  case types::TY_PP_C: case types::TY_PP_CHeader:
+    return "cc1";
+  case types::TY_ObjC: case types::TY_ObjCHeader:
+  case types::TY_PP_ObjC: case types::TY_PP_ObjC_Alias:
+  case types::TY_PP_ObjCHeader:
+    return "cc1obj";
+  case types::TY_CXX: case types::TY_CXXHeader:
+  case types::TY_PP_CXX: case types::TY_PP_CXXHeader:
+    return "cc1plus";
+  case types::TY_ObjCXX: case types::TY_ObjCXXHeader:
+  case types::TY_PP_ObjCXX: case types::TY_PP_ObjCXX_Alias:
+  case types::TY_PP_ObjCXXHeader:
+    return "cc1objplus";
+  }
+}
+
+void darwin::CC1::anchor() {}
+
+const char *darwin::CC1::getBaseInputName(const ArgList &Args,
+                                          const InputInfoList &Inputs) {
   return Args.MakeArgString(
     llvm::sys::path::filename(Inputs[0].getBaseInput()));
 }
 
-const char *Clang::getBaseInputStem(const ArgList &Args,
-                                    const InputInfoList &Inputs) {
+const char *darwin::CC1::getBaseInputStem(const ArgList &Args,
+                                          const InputInfoList &Inputs) {
   const char *Str = getBaseInputName(Args, Inputs);
 
   if (const char *End = strrchr(Str, '.'))
@@ -3652,8 +3676,9 @@
   return Str;
 }
 
-const char *Clang::getDependencyFileName(const ArgList &Args,
-                                         const InputInfoList &Inputs) {
+const char *
+darwin::CC1::getDependencyFileName(const ArgList &Args,
+                                   const InputInfoList &Inputs) {
   // FIXME: Think about this more.
   std::string Res;
 
@@ -3661,11 +3686,588 @@
     std::string Str(OutputOpt->getValue());
     Res = Str.substr(0, Str.rfind('.'));
   } else {
-    Res = getBaseInputStem(Args, Inputs);
+    Res = darwin::CC1::getBaseInputStem(Args, Inputs);
   }
   return Args.MakeArgString(Res + ".d");
 }
 
+void darwin::CC1::RemoveCC1UnsupportedArgs(ArgStringList &CmdArgs) const {
+  for (ArgStringList::iterator it = CmdArgs.begin(), ie = CmdArgs.end();
+       it != ie;) {
+
+    StringRef Option = *it;
+    bool RemoveOption = false;
+
+    // Erase both -fmodule-cache-path and its argument.
+    if (Option.equals("-fmodule-cache-path") && it+2 != ie) {
+      it = CmdArgs.erase(it, it+2);
+      ie = CmdArgs.end();
+      continue;
+    }
+
+    // Remove unsupported -f options.
+    if (Option.startswith("-f")) {
+      // Remove -f/-fno- to reduce the number of cases.
+      if (Option.startswith("-fno-"))
+        Option = Option.substr(5);
+      else
+        Option = Option.substr(2);
+      RemoveOption = llvm::StringSwitch<bool>(Option)
+        .Case("altivec", true)
+        .Case("modules", true)
+        .Case("diagnostics-show-note-include-stack", true)
+        .Default(false);
+    }
+
+    // Handle machine specific options.
+    if (Option.startswith("-m")) {
+      RemoveOption = llvm::StringSwitch<bool>(Option)
+        .Case("-mthumb", true)
+        .Case("-mno-thumb", true)
+        .Case("-mno-fused-madd", true)
+        .Case("-mlong-branch", true)
+        .Case("-mlongcall", true)
+        .Case("-mcpu=G4", true)
+        .Case("-mcpu=G5", true)
+        .Default(false);
+    }
+    
+    // Handle warning options.
+    if (Option.startswith("-W")) {
+      // Remove -W/-Wno- to reduce the number of cases.
+      if (Option.startswith("-Wno-"))
+        Option = Option.substr(5);
+      else
+        Option = Option.substr(2);
+      
+      RemoveOption = llvm::StringSwitch<bool>(Option)
+        .Case("address-of-temporary", true)
+        .Case("ambiguous-member-template", true)
+        .Case("analyzer-incompatible-plugin", true)
+        .Case("array-bounds", true)
+        .Case("array-bounds-pointer-arithmetic", true)
+        .Case("bind-to-temporary-copy", true)
+        .Case("bitwise-op-parentheses", true)
+        .Case("bool-conversions", true)
+        .Case("builtin-macro-redefined", true)
+        .Case("c++-hex-floats", true)
+        .Case("c++0x-compat", true)
+        .Case("c++0x-extensions", true)
+        .Case("c++0x-narrowing", true)
+        .Case("c++11-compat", true)
+        .Case("c++11-extensions", true)
+        .Case("c++11-narrowing", true)
+        .Case("conditional-uninitialized", true)
+        .Case("constant-conversion", true)
+        .Case("conversion-null", true)
+        .Case("CFString-literal", true)
+        .Case("constant-logical-operand", true)
+        .Case("custom-atomic-properties", true)
+        .Case("default-arg-special-member", true)
+        .Case("delegating-ctor-cycles", true)
+        .Case("delete-non-virtual-dtor", true)
+        .Case("deprecated-implementations", true)
+        .Case("deprecated-writable-strings", true)
+        .Case("distributed-object-modifiers", true)
+        .Case("duplicate-method-arg", true)
+        .Case("dynamic-class-memaccess", true)
+        .Case("enum-compare", true)
+        .Case("enum-conversion", true)
+        .Case("exit-time-destructors", true)
+        .Case("gnu", true)
+        .Case("gnu-designator", true)
+        .Case("header-hygiene", true)
+        .Case("idiomatic-parentheses", true)
+        .Case("ignored-qualifiers", true)
+        .Case("implicit-atomic-properties", true)
+        .Case("incompatible-pointer-types", true)
+        .Case("incomplete-implementation", true)
+        .Case("int-conversion", true)
+        .Case("initializer-overrides", true)
+        .Case("invalid-noreturn", true)
+        .Case("invalid-token-paste", true)
+        .Case("language-extension-token", true)
+        .Case("literal-conversion", true)
+        .Case("literal-range", true)
+        .Case("local-type-template-args", true)
+        .Case("logical-op-parentheses", true)
+        .Case("method-signatures", true)
+        .Case("microsoft", true)
+        .Case("mismatched-tags", true)
+        .Case("missing-method-return-type", true)
+        .Case("non-pod-varargs", true)
+        .Case("nonfragile-abi2", true)
+        .Case("null-arithmetic", true)
+        .Case("null-dereference", true)
+        .Case("out-of-line-declaration", true)
+        .Case("overriding-method-mismatch", true)
+        .Case("readonly-setter-attrs", true)
+        .Case("return-stack-address", true)
+        .Case("self-assign", true)
+        .Case("semicolon-before-method-body", true)
+        .Case("sentinel", true)
+        .Case("shift-overflow", true)
+        .Case("shift-sign-overflow", true)
+        .Case("sign-conversion", true)
+        .Case("sizeof-array-argument", true)
+        .Case("sizeof-pointer-memaccess", true)
+        .Case("string-compare", true)
+        .Case("super-class-method-mismatch", true)
+        .Case("tautological-compare", true)
+        .Case("typedef-redefinition", true)
+        .Case("typename-missing", true)
+        .Case("undefined-reinterpret-cast", true)
+        .Case("unknown-warning-option", true)
+        .Case("unnamed-type-template-args", true)
+        .Case("unneeded-internal-declaration", true)
+        .Case("unneeded-member-function", true)
+        .Case("unused-comparison", true)
+        .Case("unused-exception-parameter", true)
+        .Case("unused-member-function", true)
+        .Case("unused-result", true)
+        .Case("vector-conversions", true)
+        .Case("vla", true)
+        .Case("used-but-marked-unused", true)
+        .Case("weak-vtables", true)
+        .Default(false);
+    } // if (Option.startswith("-W"))
+    if (RemoveOption) {
+      it = CmdArgs.erase(it);
+      ie = CmdArgs.end();
+    } else {
+      ++it;
+    }
+  }
+}
+
+void darwin::CC1::AddCC1Args(const ArgList &Args,
+                             ArgStringList &CmdArgs) const {
+  const Driver &D = getToolChain().getDriver();
+
+  CheckCodeGenerationOptions(D, Args);
+
+  // Derived from cc1 spec.
+  if ((!Args.hasArg(options::OPT_mkernel) ||
+       (getDarwinToolChain().isTargetIPhoneOS() &&
+        !getDarwinToolChain().isIPhoneOSVersionLT(6, 0))) &&
+      !Args.hasArg(options::OPT_static) &&
+      !Args.hasArg(options::OPT_mdynamic_no_pic))
+    CmdArgs.push_back("-fPIC");
+
+  if (getToolChain().getTriple().getArch() == llvm::Triple::arm ||
+      getToolChain().getTriple().getArch() == llvm::Triple::thumb) {
+    if (!Args.hasArg(options::OPT_fbuiltin_strcat))
+      CmdArgs.push_back("-fno-builtin-strcat");
+    if (!Args.hasArg(options::OPT_fbuiltin_strcpy))
+      CmdArgs.push_back("-fno-builtin-strcpy");
+  }
+
+  if (Args.hasArg(options::OPT_g_Flag) &&
+      !Args.hasArg(options::OPT_fno_eliminate_unused_debug_symbols))
+    CmdArgs.push_back("-feliminate-unused-debug-symbols");
+}
+
+void darwin::CC1::AddCC1OptionsArgs(const ArgList &Args, ArgStringList &CmdArgs,
+                                    const InputInfoList &Inputs,
+                                    const ArgStringList &OutputArgs) const {
+  const Driver &D = getToolChain().getDriver();
+
+  // Derived from cc1_options spec.
+  if (Args.hasArg(options::OPT_fast) ||
+      Args.hasArg(options::OPT_fastf) ||
+      Args.hasArg(options::OPT_fastcp))
+    CmdArgs.push_back("-O3");
+
+  if (Arg *A = Args.getLastArg(options::OPT_pg))
+    if (Args.hasArg(options::OPT_fomit_frame_pointer))
+      D.Diag(diag::err_drv_argument_not_allowed_with)
+        << A->getAsString(Args) << "-fomit-frame-pointer";
+
+  AddCC1Args(Args, CmdArgs);
+
+  if (!Args.hasArg(options::OPT_Q))
+    CmdArgs.push_back("-quiet");
+
+  CmdArgs.push_back("-dumpbase");
+  CmdArgs.push_back(darwin::CC1::getBaseInputName(Args, Inputs));
+
+  Args.AddAllArgs(CmdArgs, options::OPT_d_Group);
+
+  Args.AddAllArgs(CmdArgs, options::OPT_m_Group);
+  Args.AddAllArgs(CmdArgs, options::OPT_a_Group);
+
+  // FIXME: The goal is to use the user provided -o if that is our
+  // final output, otherwise to drive from the original input
+  // name. Find a clean way to go about this.
+  if ((Args.hasArg(options::OPT_c) || Args.hasArg(options::OPT_S)) &&
+      Args.hasArg(options::OPT_o)) {
+    Arg *OutputOpt = Args.getLastArg(options::OPT_o);
+    CmdArgs.push_back("-auxbase-strip");
+    CmdArgs.push_back(OutputOpt->getValue());
+  } else {
+    CmdArgs.push_back("-auxbase");
+    CmdArgs.push_back(darwin::CC1::getBaseInputStem(Args, Inputs));
+  }
+
+  Args.AddAllArgs(CmdArgs, options::OPT_g_Group);
+
+  Args.AddAllArgs(CmdArgs, options::OPT_O);
+  // FIXME: -Wall is getting some special treatment. Investigate.
+  Args.AddAllArgs(CmdArgs, options::OPT_W_Group, options::OPT_pedantic_Group);
+  Args.AddLastArg(CmdArgs, options::OPT_w);
+  Args.AddAllArgs(CmdArgs, options::OPT_std_EQ, options::OPT_ansi,
+                  options::OPT_trigraphs);
+  if (!Args.getLastArg(options::OPT_std_EQ, options::OPT_ansi)) {
+    // Honor -std-default.
+    Args.AddAllArgsTranslated(CmdArgs, options::OPT_std_default_EQ,
+                              "-std=", /*Joined=*/true);
+  }
+
+  if (Args.hasArg(options::OPT_v))
+    CmdArgs.push_back("-version");
+  if (Args.hasArg(options::OPT_pg) &&
+      getToolChain().SupportsProfiling())
+    CmdArgs.push_back("-p");
+  Args.AddLastArg(CmdArgs, options::OPT_p);
+
+  // The driver treats -fsyntax-only specially.
+  if (getToolChain().getTriple().getArch() == llvm::Triple::arm ||
+      getToolChain().getTriple().getArch() == llvm::Triple::thumb) {
+    // Removes -fbuiltin-str{cat,cpy}; these aren't recognized by cc1 but are
+    // used to inhibit the default -fno-builtin-str{cat,cpy}.
+    //
+    // FIXME: Should we grow a better way to deal with "removing" args?
+    for (arg_iterator it = Args.filtered_begin(options::OPT_f_Group,
+                                               options::OPT_fsyntax_only),
+           ie = Args.filtered_end(); it != ie; ++it) {
+      if (!(*it)->getOption().matches(options::OPT_fbuiltin_strcat) &&
+          !(*it)->getOption().matches(options::OPT_fbuiltin_strcpy)) {
+        (*it)->claim();
+        (*it)->render(Args, CmdArgs);
+      }
+    }
+  } else
+    Args.AddAllArgs(CmdArgs, options::OPT_f_Group, options::OPT_fsyntax_only);
+
+  // Claim Clang only -f options, they aren't worth warning about.
+  Args.ClaimAllArgs(options::OPT_f_clang_Group);
+
+  Args.AddAllArgs(CmdArgs, options::OPT_undef);
+  if (Args.hasArg(options::OPT_Qn))
+    CmdArgs.push_back("-fno-ident");
+
+  // FIXME: This isn't correct.
+  //Args.AddLastArg(CmdArgs, options::OPT__help)
+  //Args.AddLastArg(CmdArgs, options::OPT__targetHelp)
+
+  CmdArgs.append(OutputArgs.begin(), OutputArgs.end());
+
+  // FIXME: Still don't get what is happening here. Investigate.
+  Args.AddAllArgs(CmdArgs, options::OPT__param);
+
+  if (Args.hasArg(options::OPT_fmudflap) ||
+      Args.hasArg(options::OPT_fmudflapth)) {
+    CmdArgs.push_back("-fno-builtin");
+    CmdArgs.push_back("-fno-merge-constants");
+  }
+
+  if (Args.hasArg(options::OPT_coverage)) {
+    CmdArgs.push_back("-fprofile-arcs");
+    CmdArgs.push_back("-ftest-coverage");
+  }
+
+  if (types::isCXX(Inputs[0].getType()))
+    CmdArgs.push_back("-D__private_extern__=extern");
+}
+
+void darwin::CC1::AddCPPOptionsArgs(const ArgList &Args, ArgStringList &CmdArgs,
+                                    const InputInfoList &Inputs,
+                                    const ArgStringList &OutputArgs) const {
+  // Derived from cpp_options
+  AddCPPUniqueOptionsArgs(Args, CmdArgs, Inputs);
+
+  CmdArgs.append(OutputArgs.begin(), OutputArgs.end());
+
+  AddCC1Args(Args, CmdArgs);
+
+  // NOTE: The code below has some commonality with cpp_options, but
+  // in classic gcc style ends up sending things in different
+  // orders. This may be a good merge candidate once we drop pedantic
+  // compatibility.
+
+  Args.AddAllArgs(CmdArgs, options::OPT_m_Group);
+  Args.AddAllArgs(CmdArgs, options::OPT_std_EQ, options::OPT_ansi,
+                  options::OPT_trigraphs);
+  if (!Args.getLastArg(options::OPT_std_EQ, options::OPT_ansi)) {
+    // Honor -std-default.
+    Args.AddAllArgsTranslated(CmdArgs, options::OPT_std_default_EQ,
+                              "-std=", /*Joined=*/true);
+  }
+  Args.AddAllArgs(CmdArgs, options::OPT_W_Group, options::OPT_pedantic_Group);
+  Args.AddLastArg(CmdArgs, options::OPT_w);
+
+  // The driver treats -fsyntax-only specially.
+  Args.AddAllArgs(CmdArgs, options::OPT_f_Group, options::OPT_fsyntax_only);
+
+  // Claim Clang only -f options, they aren't worth warning about.
+  Args.ClaimAllArgs(options::OPT_f_clang_Group);
+
+  if (Args.hasArg(options::OPT_g_Group) && !Args.hasArg(options::OPT_g0) &&
+      !Args.hasArg(options::OPT_fno_working_directory))
+    CmdArgs.push_back("-fworking-directory");
+
+  Args.AddAllArgs(CmdArgs, options::OPT_O);
+  Args.AddAllArgs(CmdArgs, options::OPT_undef);
+  if (Args.hasArg(options::OPT_save_temps))
+    CmdArgs.push_back("-fpch-preprocess");
+}
+
+void darwin::CC1::AddCPPUniqueOptionsArgs(const ArgList &Args,
+                                          ArgStringList &CmdArgs,
+                                          const InputInfoList &Inputs) const {
+  const Driver &D = getToolChain().getDriver();
+
+  CheckPreprocessingOptions(D, Args);
+
+  // Derived from cpp_unique_options.
+  // -{C,CC} only with -E is checked in CheckPreprocessingOptions().
+  Args.AddLastArg(CmdArgs, options::OPT_C);
+  Args.AddLastArg(CmdArgs, options::OPT_CC);
+  if (!Args.hasArg(options::OPT_Q))
+    CmdArgs.push_back("-quiet");
+  Args.AddAllArgs(CmdArgs, options::OPT_nostdinc);
+  Args.AddAllArgs(CmdArgs, options::OPT_nostdincxx);
+  Args.AddLastArg(CmdArgs, options::OPT_v);
+  Args.AddAllArgs(CmdArgs, options::OPT_I_Group, options::OPT_F);
+  Args.AddLastArg(CmdArgs, options::OPT_P);
+
+  // FIXME: Handle %I properly.
+  if (getToolChain().getArch() == llvm::Triple::x86_64) {
+    CmdArgs.push_back("-imultilib");
+    CmdArgs.push_back("x86_64");
+  }
+
+  if (Args.hasArg(options::OPT_MD)) {
+    CmdArgs.push_back("-MD");
+    CmdArgs.push_back(darwin::CC1::getDependencyFileName(Args, Inputs));
+  }
+
+  if (Args.hasArg(options::OPT_MMD)) {
+    CmdArgs.push_back("-MMD");
+    CmdArgs.push_back(darwin::CC1::getDependencyFileName(Args, Inputs));
+  }
+
+  Args.AddLastArg(CmdArgs, options::OPT_M);
+  Args.AddLastArg(CmdArgs, options::OPT_MM);
+  Args.AddAllArgs(CmdArgs, options::OPT_MF);
+  Args.AddLastArg(CmdArgs, options::OPT_MG);
+  Args.AddLastArg(CmdArgs, options::OPT_MP);
+  Args.AddAllArgs(CmdArgs, options::OPT_MQ);
+  Args.AddAllArgs(CmdArgs, options::OPT_MT);
+  if (!Args.hasArg(options::OPT_M) && !Args.hasArg(options::OPT_MM) &&
+      (Args.hasArg(options::OPT_MD) || Args.hasArg(options::OPT_MMD))) {
+    if (Arg *OutputOpt = Args.getLastArg(options::OPT_o)) {
+      CmdArgs.push_back("-MQ");
+      CmdArgs.push_back(OutputOpt->getValue());
+    }
+  }
+
+  Args.AddLastArg(CmdArgs, options::OPT_remap);
+  if (Args.hasArg(options::OPT_g3))
+    CmdArgs.push_back("-dD");
+  Args.AddLastArg(CmdArgs, options::OPT_H);
+
+  AddCPPArgs(Args, CmdArgs);
+
+  Args.AddAllArgs(CmdArgs, options::OPT_D, options::OPT_U, options::OPT_A);
+  Args.AddAllArgs(CmdArgs, options::OPT_i_Group);
+
+  for (InputInfoList::const_iterator
+         it = Inputs.begin(), ie = Inputs.end(); it != ie; ++it) {
+    const InputInfo &II = *it;
+
+    CmdArgs.push_back(II.getFilename());
+  }
+
+  Args.AddAllArgValues(CmdArgs, options::OPT_Wp_COMMA,
+                       options::OPT_Xpreprocessor);
+
+  if (Args.hasArg(options::OPT_fmudflap)) {
+    CmdArgs.push_back("-D_MUDFLAP");
+    CmdArgs.push_back("-include");
+    CmdArgs.push_back("mf-runtime.h");
+  }
+
+  if (Args.hasArg(options::OPT_fmudflapth)) {
+    CmdArgs.push_back("-D_MUDFLAP");
+    CmdArgs.push_back("-D_MUDFLAPTH");
+    CmdArgs.push_back("-include");
+    CmdArgs.push_back("mf-runtime.h");
+  }
+}
+
+void darwin::CC1::AddCPPArgs(const ArgList &Args,
+                             ArgStringList &CmdArgs) const {
+  // Derived from cpp spec.
+
+  if (Args.hasArg(options::OPT_static)) {
+    // The gcc spec is broken here, it refers to dynamic but
+    // that has been translated. Start by being bug compatible.
+
+    // if (!Args.hasArg(arglist.parser.dynamicOption))
+    CmdArgs.push_back("-D__STATIC__");
+  } else
+    CmdArgs.push_back("-D__DYNAMIC__");
+
+  if (Args.hasArg(options::OPT_pthread))
+    CmdArgs.push_back("-D_REENTRANT");
+}
+
+void darwin::Preprocess::ConstructJob(Compilation &C, const JobAction &JA,
+                                      const InputInfo &Output,
+                                      const InputInfoList &Inputs,
+                                      const ArgList &Args,
+                                      const char *LinkingOutput) const {
+  ArgStringList CmdArgs;
+
+  assert(Inputs.size() == 1 && "Unexpected number of inputs!");
+
+  CmdArgs.push_back("-E");
+
+  if (Args.hasArg(options::OPT_traditional) ||
+      Args.hasArg(options::OPT_traditional_cpp))
+    CmdArgs.push_back("-traditional-cpp");
+
+  ArgStringList OutputArgs;
+  assert(Output.isFilename() && "Unexpected CC1 output.");
+  OutputArgs.push_back("-o");
+  OutputArgs.push_back(Output.getFilename());
+
+  if (Args.hasArg(options::OPT_E) || getToolChain().getDriver().CCCIsCPP) {
+    AddCPPOptionsArgs(Args, CmdArgs, Inputs, OutputArgs);
+  } else {
+    AddCPPOptionsArgs(Args, CmdArgs, Inputs, ArgStringList());
+    CmdArgs.append(OutputArgs.begin(), OutputArgs.end());
+  }
+
+  Args.AddAllArgs(CmdArgs, options::OPT_d_Group);
+
+  RemoveCC1UnsupportedArgs(CmdArgs);
+
+  const char *CC1Name = getCC1Name(Inputs[0].getType());
+  const char *Exec =
+    Args.MakeArgString(getToolChain().GetProgramPath(CC1Name));
+  C.addCommand(new Command(JA, *this, Exec, CmdArgs));
+}
+
+void darwin::Compile::ConstructJob(Compilation &C, const JobAction &JA,
+                                   const InputInfo &Output,
+                                   const InputInfoList &Inputs,
+                                   const ArgList &Args,
+                                   const char *LinkingOutput) const {
+  const Driver &D = getToolChain().getDriver();
+  ArgStringList CmdArgs;
+
+  assert(Inputs.size() == 1 && "Unexpected number of inputs!");
+
+  // Silence warning about unused --serialize-diagnostics
+  Args.ClaimAllArgs(options::OPT__serialize_diags);
+
+  types::ID InputType = Inputs[0].getType();
+  if (const Arg *A = Args.getLastArg(options::OPT_traditional))
+    D.Diag(diag::err_drv_argument_only_allowed_with)
+      << A->getAsString(Args) << "-E";
+
+  if (JA.getType() == types::TY_LLVM_IR ||
+      JA.getType() == types::TY_LTO_IR)
+    CmdArgs.push_back("-emit-llvm");
+  else if (JA.getType() == types::TY_LLVM_BC ||
+           JA.getType() == types::TY_LTO_BC)
+    CmdArgs.push_back("-emit-llvm-bc");
+  else if (Output.getType() == types::TY_AST)
+    D.Diag(diag::err_drv_no_ast_support)
+      << getToolChain().getTripleString();
+  else if (JA.getType() != types::TY_PP_Asm &&
+           JA.getType() != types::TY_PCH)
+    D.Diag(diag::err_drv_invalid_gcc_output_type)
+      << getTypeName(JA.getType());
+
+  ArgStringList OutputArgs;
+  if (Output.getType() != types::TY_PCH) {
+    OutputArgs.push_back("-o");
+    if (Output.isNothing())
+      OutputArgs.push_back("/dev/null");
+    else
+      OutputArgs.push_back(Output.getFilename());
+  }
+
+  // There is no need for this level of compatibility, but it makes
+  // diffing easier.
+  bool OutputArgsEarly = (Args.hasArg(options::OPT_fsyntax_only) ||
+                          Args.hasArg(options::OPT_S));
+
+  if (types::getPreprocessedType(InputType) != types::TY_INVALID) {
+    AddCPPUniqueOptionsArgs(Args, CmdArgs, Inputs);
+    if (OutputArgsEarly) {
+      AddCC1OptionsArgs(Args, CmdArgs, Inputs, OutputArgs);
+    } else {
+      AddCC1OptionsArgs(Args, CmdArgs, Inputs, ArgStringList());
+      CmdArgs.append(OutputArgs.begin(), OutputArgs.end());
+    }
+  } else {
+    CmdArgs.push_back("-fpreprocessed");
+
+    for (InputInfoList::const_iterator
+           it = Inputs.begin(), ie = Inputs.end(); it != ie; ++it) {
+      const InputInfo &II = *it;
+
+      // Reject AST inputs.
+      if (II.getType() == types::TY_AST) {
+        D.Diag(diag::err_drv_no_ast_support)
+          << getToolChain().getTripleString();
+        return;
+      }
+
+      CmdArgs.push_back(II.getFilename());
+    }
+
+    if (OutputArgsEarly) {
+      AddCC1OptionsArgs(Args, CmdArgs, Inputs, OutputArgs);
+    } else {
+      AddCC1OptionsArgs(Args, CmdArgs, Inputs, ArgStringList());
+      CmdArgs.append(OutputArgs.begin(), OutputArgs.end());
+    }
+  }
+
+  if (Output.getType() == types::TY_PCH) {
+    assert(Output.isFilename() && "Invalid PCH output.");
+
+    CmdArgs.push_back("-o");
+    // NOTE: gcc uses a temp .s file for this, but there doesn't seem
+    // to be a good reason.
+    const char *TmpPath = C.getArgs().MakeArgString(
+      D.GetTemporaryPath("cc", "s"));
+    C.addTempFile(TmpPath);
+    CmdArgs.push_back(TmpPath);
+
+    // If we're emitting a pch file with the last 4 characters of ".pth"
+    // and falling back to llvm-gcc we want to use ".gch" instead.
+    std::string OutputFile(Output.getFilename());
+    size_t loc = OutputFile.rfind(".pth");
+    if (loc != std::string::npos)
+      OutputFile.replace(loc, 4, ".gch");
+    const char *Tmp = C.getArgs().MakeArgString("--output-pch="+OutputFile);
+    CmdArgs.push_back(Tmp);
+  }
+
+  RemoveCC1UnsupportedArgs(CmdArgs);
+
+  const char *CC1Name = getCC1Name(Inputs[0].getType());
+  const char *Exec =
+    Args.MakeArgString(getToolChain().GetProgramPath(CC1Name));
+  C.addCommand(new Command(JA, *this, Exec, CmdArgs));
+}
+
 void darwin::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
                                     const InputInfo &Output,
                                     const InputInfoList &Inputs,