clang-cl: implement /fallback mode

When this flag is enabled, clang-cl falls back to cl.exe if it
cannot compile the code itself for some reason.

The idea is to use this to help build projects that almost compile
with clang-cl, except for some files that can then be built with
the fallback mechanism.

Differential Revision: http://llvm-reviews.chandlerc.com/D1711

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@191034 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Driver/Job.cpp b/lib/Driver/Job.cpp
index 7df46d3..ee68e6f 100644
--- a/lib/Driver/Job.cpp
+++ b/lib/Driver/Job.cpp
@@ -126,6 +126,43 @@
                                    /*memoryLimit*/ 0, ErrMsg, ExecutionFailed);
 }
 
+FallbackCommand::FallbackCommand(const Action &Source_, const Tool &Creator_,
+                                 const char *Executable_,
+                                 const ArgStringList &Arguments_,
+                                 Command *Fallback_)
+    : Command(Source_, Creator_, Executable_, Arguments_), Fallback(Fallback_) {
+}
+
+void FallbackCommand::Print(raw_ostream &OS, const char *Terminator,
+                            bool Quote, bool CrashReport) const {
+  Command::Print(OS, "", Quote, CrashReport);
+  OS << " ||";
+  Fallback->Print(OS, Terminator, Quote, CrashReport);
+}
+
+static bool ShouldFallback(int ExitCode) {
+  // FIXME: We really just want to fall back for internal errors, such
+  // as when some symbol cannot be mangled, when we should be able to
+  // parse something but can't, etc.
+  return ExitCode != 0;
+}
+
+int FallbackCommand::Execute(const StringRef **Redirects, std::string *ErrMsg,
+                             bool *ExecutionFailed) const {
+  int PrimaryStatus = Command::Execute(Redirects, ErrMsg, ExecutionFailed);
+  if (!ShouldFallback(PrimaryStatus))
+    return PrimaryStatus;
+
+  // Clear ExecutionFailed and ErrMsg before falling back.
+  if (ErrMsg)
+    ErrMsg->clear();
+  if (ExecutionFailed)
+    *ExecutionFailed = false;
+
+  int SecondaryStatus = Fallback->Execute(Redirects, ErrMsg, ExecutionFailed);
+  return SecondaryStatus;
+}
+
 JobList::JobList() : Job(JobListClass) {}
 
 JobList::~JobList() {