Hi hans,

This isn't 100% compatible with MSVC, but it's close enough.  MSVC's /EH
flag doesn't really control exceptions so much as how to clean up after
an exception is thrown.  The upshot is that cl.exe /EHs- will compile
try, throw, and catch statements with a warning, but clang-cl will
reject such constructs with a hard error.  We can't compile such EH
constructs anyway, but this may matter to consumers of the AST.

http://reviews.llvm.org/D4317

Files:
  include/clang/Driver/CLCompatOptions.td
  lib/Driver/Tools.cpp
  test/Driver/cl-eh.cpp
Index: include/clang/Driver/CLCompatOptions.td
===================================================================
--- include/clang/Driver/CLCompatOptions.td
+++ include/clang/Driver/CLCompatOptions.td
@@ -140,6 +140,7 @@
 
 def _SLASH_M_Group : OptionGroup<"</M group>">, Group<cl_compile_Group>;
 
+def _SLASH_EH : CLJoined<"EH">, HelpText<"Exception handling model">;
 def _SLASH_EP : CLFlag<"EP">,
   HelpText<"Disable linemarker output and preprocess to stdout">;
 def _SLASH_FA : CLFlag<"FA">,
@@ -209,7 +210,6 @@
 def _SLASH_clr : CLJoined<"clr">;
 def _SLASH_d2Zi_PLUS : CLFlag<"d2Zi+">;
 def _SLASH_doc : CLJoined<"doc">;
-def _SLASH_EH : CLJoined<"EH">;
 def _SLASH_FA_joined : CLJoined<"FA">;
 def _SLASH_favor : CLJoined<"favor">;
 def _SLASH_FC : CLFlag<"FC">;
Index: lib/Driver/Tools.cpp
===================================================================
--- lib/Driver/Tools.cpp
+++ lib/Driver/Tools.cpp
@@ -3844,9 +3844,10 @@
     }
   }
 
-  // Add exception args.
-  addExceptionArgs(Args, InputType, getToolChain().getTriple(),
-                   KernelOrKext, objcRuntime, CmdArgs);
+  // Handle GCC-style exception args.
+  if (!C.getDriver().IsCLMode())
+    addExceptionArgs(Args, InputType, getToolChain().getTriple(), KernelOrKext,
+                     objcRuntime, CmdArgs);
 
   if (getToolChain().UseSjLjExceptions())
     CmdArgs.push_back("-fsjlj-exceptions");
@@ -4352,6 +4353,8 @@
 }
 
 void Clang::AddClangCLArgs(const ArgList &Args, ArgStringList &CmdArgs) const {
+  const Driver &D = getToolChain().getDriver();
+
   unsigned RTOptionID = options::OPT__SLASH_MT;
 
   if (Args.hasArg(options::OPT__SLASH_LDd))
@@ -4403,13 +4406,47 @@
   if (!Args.hasArg(options::OPT_frtti, options::OPT_fno_rtti))
     CmdArgs.push_back("-fno-rtti");
 
+  // /EH controls the whether to run destructor cleanups when exceptions are
+  // thrown.  There are three modifiers:
+  // - s: Cleanup after "synchronous" exceptions, aka C++ exceptions.
+  // - a: Cleanup after "asynchronous" exceptions, aka structured exceptions.
+  //      The 'a' modifier is unimplemented and fundamentally hard in LLVM IR.
+  // - c: Assume that extern "C" functions are implicitly noexcept.  This
+  //      modifier is an optimization, so we ignore it for now.
+  // The default is /EHs-c-, meaning cleanups are disabled.
+  bool SynchEH = false;
+  bool AsynchEH = false;
+  bool NoExceptC = false;
+  std::vector<std::string> EHArgs = Args.getAllArgValues(options::OPT__SLASH_EH);
+  auto maybeConsumeDash = [](const std::string &EH, size_t &I) {
+    bool HaveDash = (I + 1 < EH.size() && EH[I + 1] == '-');
+    I += HaveDash;
+    return !HaveDash;
+  };
+  for (auto EH : EHArgs) {
+    for (size_t I = 0, E = EH.size(); I != E; ++I) {
+      switch (EH[I]) {
+      case 'a': AsynchEH = maybeConsumeDash(EH, I); continue;
+      case 'c': NoExceptC = maybeConsumeDash(EH, I); continue;
+      case 's': SynchEH = maybeConsumeDash(EH, I); continue;
+      default: break;
+      }
+      D.Diag(clang::diag::err_drv_invalid_value) << "/EH" << EH;
+      break;
+    }
+  }
+  (void)NoExceptC; // FIXME: Do something with the 'c' modifier.
+  if (SynchEH || AsynchEH) {
+    CmdArgs.push_back("-fexceptions");
+    CmdArgs.push_back("-fcxx-exceptions");
+  }
+
   // /EP should expand to -E -P.
   if (Args.hasArg(options::OPT__SLASH_EP)) {
     CmdArgs.push_back("-E");
     CmdArgs.push_back("-P");
   }
 
-  const Driver &D = getToolChain().getDriver();
   Arg *MostGeneralArg = Args.getLastArg(options::OPT__SLASH_vmg);
   Arg *BestCaseArg = Args.getLastArg(options::OPT__SLASH_vmb);
   if (MostGeneralArg && BestCaseArg)
Index: test/Driver/cl-eh.cpp
===================================================================
--- /dev/null
+++ test/Driver/cl-eh.cpp
@@ -0,0 +1,24 @@
+// Don't attempt slash switches on msys bash.
+// REQUIRES: shell-preserves-root
+
+// Note: %s must be preceded by --, otherwise it may be interpreted as a
+// command-line option, e.g. on Mac where %s is commonly under /Users.
+
+// RUN: %clang_cl /c /EHsc -### -- %s 2>&1 | FileCheck -check-prefix=EHsc %s
+// EHsc: "-fexceptions"
+
+// RUN: %clang_cl /c /EHs-c- -### -- %s 2>&1 | FileCheck -check-prefix=EHs_c_ %s
+// EHs_c_-NOT: "-fexceptions"
+
+// RUN: %clang_cl /c /EHs- /EHc- -### -- %s 2>&1 | FileCheck -check-prefix=EHs_EHc_ %s
+// EHs_EHc_-NOT: "-fexceptions"
+
+// RUN: %clang_cl /c /EHs- /EHs -### -- %s 2>&1 | FileCheck -check-prefix=EHs_EHs %s
+// EHs_EHs: "-fexceptions"
+
+// RUN: %clang_cl /c /EHs- /EHsa -### -- %s 2>&1 | FileCheck -check-prefix=EHs_EHa %s
+// EHs_EHa: "-fexceptions"
+
+// RUN: %clang_cl /c /EHinvalid -### -- %s 2>&1 | FileCheck -check-prefix=EHinvalid %s
+// EHinvalid: error: invalid value 'invalid' in '/EH'
+// EHinvalid-NOT: error:
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to