Skip to content

Commit

Permalink
clang-cl: Map /EHs- to -fno-exceptions
Browse files Browse the repository at this point in the history
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.

Reviewers: hans

Differential Revision: http://reviews.llvm.org/D4317

llvm-svn: 211909
  • Loading branch information
rnk committed Jun 27, 2014
1 parent 4632e1e commit c542d37
Show file tree
Hide file tree
Showing 4 changed files with 80 additions and 6 deletions.
2 changes: 1 addition & 1 deletion clang/include/clang/Driver/CLCompatOptions.td
Expand Up @@ -140,6 +140,7 @@ def _SLASH_Zs : CLFlag<"Zs">, HelpText<"Syntax-check only">,

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">,
Expand Down Expand Up @@ -209,7 +210,6 @@ def _SLASH_bigobj : CLFlag<"bigobj">;
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">;
Expand Down
56 changes: 52 additions & 4 deletions clang/lib/Driver/Tools.cpp
Expand Up @@ -3846,9 +3846,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
}
}

// 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");
Expand Down Expand Up @@ -4352,6 +4353,45 @@ ObjCRuntime Clang::AddObjCRuntimeArgs(const ArgList &args,
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;

Expand Down Expand Up @@ -4404,13 +4444,20 @@ void Clang::AddClangCLArgs(const ArgList &Args, ArgStringList &CmdArgs) const {
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)
Expand Down Expand Up @@ -7692,6 +7739,7 @@ Command *visualstudio::Compile::GetCommand(Compilation &C, const JobAction &JA,
// 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,
Expand Down
24 changes: 24 additions & 0 deletions clang/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:
4 changes: 3 additions & 1 deletion clang/test/Driver/cl-fallback.c
Expand Up @@ -5,7 +5,7 @@
// command-line option, e.g. on Mac where %s is commonly under /Users.

// RUN: %clang_cl /fallback /Dfoo=bar /Ubaz /Ifoo /O0 /Ox /GR /GR- /Gy /Gy- \
// RUN: /Gw /Gw- /LD /LDd /MD /MDd /MTd /MT /FImyheader.h /Zi \
// RUN: /Gw /Gw- /LD /LDd /EHs /EHs- /MD /MDd /MTd /MT /FImyheader.h /Zi \
// RUN: -### -- %s 2>&1 \
// RUN: | FileCheck %s
// CHECK: "-fdiagnostics-format" "msvc-fallback"
Expand All @@ -25,6 +25,8 @@
// CHECK: "/FImyheader.h"
// CHECK: "/LD"
// CHECK: "/LDd"
// CHECK: "/EHs"
// CHECK: "/EHs-"
// CHECK: "/MT"
// CHECK: "/Tc" "{{.*cl-fallback.c}}"
// CHECK: "/Fo{{.*cl-fallback.*.obj}}"
Expand Down

0 comments on commit c542d37

Please sign in to comment.