Add a -fcxx-exceptions flag to the frontend, which can be used to enable
C++ exceptions, even when exceptions have been turned off using -fno-exceptions.
Make the -fobjc-exceptions flag do the same thing, but for Objective-C exceptions.

C++ and Objective-C exceptions can also be disabled using -fno-cxx-excptions and
-fno-objc-exceptions.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@126630 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp
index 43ff90d..475b904 100644
--- a/lib/Driver/Tools.cpp
+++ b/lib/Driver/Tools.cpp
@@ -780,25 +780,84 @@
            Triple.getArch() == llvm::Triple::arm));  
 }
 
-static bool needsExceptions(const ArgList &Args,  types::ID InputType,
-                            const llvm::Triple &Triple) {
-  // Handle -fno-exceptions.
+/// addExceptionArgs - Adds exception related arguments to the driver command
+/// arguments. There's a master flag, -fexceptions and also language specific
+/// flags to enable/disable C++ and Objective-C exceptions.
+/// This makes it possible to for example disable C++ exceptions but enable
+/// Objective-C exceptions.
+static void addExceptionArgs(const ArgList &Args, types::ID InputType,
+                             const llvm::Triple &Triple,
+                             bool KernelOrKext, bool IsRewriter,
+                             ArgStringList &CmdArgs) {
+  if (KernelOrKext)
+    return;
+
+  // Exceptions are enabled by default.
+  bool ExceptionsEnabled = true;
+
+  // This keeps track of whether exceptions were explicitly turned on or off.
+  bool DidHaveExplicitExceptionFlag = false;
+
   if (Arg *A = Args.getLastArg(options::OPT_fexceptions,
                                options::OPT_fno_exceptions)) {
     if (A->getOption().matches(options::OPT_fexceptions))
-      return true;
-    else
-      return false;
+      ExceptionsEnabled = true;
+    else 
+      ExceptionsEnabled = false;
+
+    DidHaveExplicitExceptionFlag = true;
   }
 
-  // Otherwise, C++ inputs use exceptions.
-  if (types::isCXX(InputType))
-    return true;
+  bool ShouldUseExceptionTables = false;
 
-  if (types::isObjC(InputType))
-    return shouldUseExceptionTablesForObjCExceptions(Args, Triple);
+  // Exception tables and cleanups can be enabled with -fexceptions even if the
+  // language itself doesn't support exceptions.
+  if (ExceptionsEnabled && DidHaveExplicitExceptionFlag)
+    ShouldUseExceptionTables = true;
 
-  return false;
+  if (types::isObjC(InputType)) {
+    bool ObjCExceptionsEnabled = ExceptionsEnabled;
+
+    if (Arg *A = Args.getLastArg(options::OPT_fobjc_exceptions, 
+                                 options::OPT_fno_objc_exceptions,
+                                 options::OPT_fexceptions,
+                                 options::OPT_fno_exceptions)) {
+      if (A->getOption().matches(options::OPT_fobjc_exceptions))
+        ObjCExceptionsEnabled = true;
+      else if (A->getOption().matches(options::OPT_fno_objc_exceptions))
+        ObjCExceptionsEnabled = false;
+    }
+
+    if (ObjCExceptionsEnabled) {
+      CmdArgs.push_back("-fobjc-exceptions");
+
+      ShouldUseExceptionTables |= 
+        shouldUseExceptionTablesForObjCExceptions(Args, Triple);
+    }
+  }
+
+  if (types::isCXX(InputType)) {
+    bool CXXExceptionsEnabled = ExceptionsEnabled;
+
+    if (Arg *A = Args.getLastArg(options::OPT_fcxx_exceptions, 
+                                 options::OPT_fno_cxx_exceptions, 
+                                 options::OPT_fexceptions,
+                                 options::OPT_fno_exceptions)) {
+      if (A->getOption().matches(options::OPT_fcxx_exceptions))
+        CXXExceptionsEnabled = true;
+      else
+        CXXExceptionsEnabled = false;
+    }
+
+    if (CXXExceptionsEnabled) {
+      CmdArgs.push_back("-fcxx-exceptions");
+
+      ShouldUseExceptionTables = true;
+    }
+  }
+
+  if (ShouldUseExceptionTables)
+    CmdArgs.push_back("-fexceptions");
 }
 
 void Clang::ConstructJob(Compilation &C, const JobAction &JA,
@@ -1416,10 +1475,9 @@
                    false))
     CmdArgs.push_back("-fno-elide-constructors");
 
-  // -fexceptions=0 is default.
-  if (!KernelOrKext &&
-      needsExceptions(Args, InputType, getToolChain().getTriple()))
-    CmdArgs.push_back("-fexceptions");
+  // Add exception args.
+  addExceptionArgs(Args, InputType, getToolChain().getTriple(),
+                   KernelOrKext, IsRewriter, CmdArgs);
 
   if (getToolChain().UseSjLjExceptions())
     CmdArgs.push_back("-fsjlj-exceptions");
@@ -1556,11 +1614,6 @@
                      getToolChain().IsObjCDefaultSynthPropertiesDefault())) {
       CmdArgs.push_back("-fobjc-default-synthesize-properties");
     }
-
-    // -fno-objc-exceptions is default.
-    if (IsRewriter || Args.hasFlag(options::OPT_fobjc_exceptions, 
-                                   options::OPT_fno_objc_exceptions))
-      CmdArgs.push_back("-fobjc-exceptions");
   }
 
   if (!Args.hasFlag(options::OPT_fassume_sane_operator_new,