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">,
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">;
}
}
- // 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");
return runtime;
}
+static bool maybeConsumeDash(const std::string &EH, size_t &I) {
+ bool HaveDash = (I + 1 < EH.size() && EH[I + 1] == '-');
+ I += HaveDash;
+ return !HaveDash;
+};
+
+struct EHFlags {
+ EHFlags() : Synch(false), Asynch(false), NoExceptC(false) {}
+ bool Synch;
+ bool Asynch;
+ bool NoExceptC;
+};
+
+/// /EH controls 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.
+static EHFlags parseClangCLEHFlags(const Driver &D, const ArgList &Args) {
+ EHFlags EH;
+ std::vector<std::string> EHArgs = Args.getAllArgValues(options::OPT__SLASH_EH);
+ for (auto EHVal : EHArgs) {
+ for (size_t I = 0, E = EHVal.size(); I != E; ++I) {
+ switch (EHVal[I]) {
+ case 'a': EH.Asynch = maybeConsumeDash(EHVal, I); continue;
+ case 'c': EH.NoExceptC = maybeConsumeDash(EHVal, I); continue;
+ case 's': EH.Synch = maybeConsumeDash(EHVal, I); continue;
+ default: break;
+ }
+ D.Diag(clang::diag::err_drv_invalid_value) << "/EH" << EHVal;
+ break;
+ }
+ }
+ return EH;
+}
+
void Clang::AddClangCLArgs(const ArgList &Args, ArgStringList &CmdArgs) const {
unsigned RTOptionID = options::OPT__SLASH_MT;
if (!Args.hasArg(options::OPT_frtti, options::OPT_fno_rtti))
CmdArgs.push_back("-fno-rtti");
+ const Driver &D = getToolChain().getDriver();
+ EHFlags EH = parseClangCLEHFlags(D, Args);
+ // FIXME: Do something with NoExceptC.
+ if (EH.Synch || EH.Asynch) {
+ 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)
// Flags that can simply be passed through.
Args.AddAllArgs(CmdArgs, options::OPT__SLASH_LD);
Args.AddAllArgs(CmdArgs, options::OPT__SLASH_LDd);
+ Args.AddAllArgs(CmdArgs, options::OPT__SLASH_EH);
// The order of these flags is relevant, so pick the last one.
if (Arg *A = Args.getLastArg(options::OPT__SLASH_MD, options::OPT__SLASH_MDd,
--- /dev/null
+// 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: