<div dir="ltr">Would've been good to land the move separately from the behavior change…</div><div class="gmail_extra"><br><div class="gmail_quote">On Tue, Mar 3, 2015 at 11:21 AM, Reid Kleckner <span dir="ltr"><<a href="mailto:reid@kleckner.net" target="_blank">reid@kleckner.net</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Author: rnk<br>
Date: Tue Mar 3 13:21:04 2015<br>
New Revision: 231105<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=231105&view=rev" target="_blank">http://llvm.org/viewvc/llvm-project?rev=231105&view=rev</a><br>
Log:<br>
Split catch IRgen into ItaniumCXXABI and MicrosoftCXXABI<br>
<br>
Use llvm.eh.begincatch for Microsoft-style catches.<br>
<br>
This moves lots of CGException code into ItaniumCXXABI. Sorry for the<br>
blame pain.<br>
<br>
Added:<br>
cfe/trunk/test/CodeGenCXX/microsoft-abi-eh-catch.cpp<br>
cfe/trunk/test/CodeGenCXX/microsoft-abi-eh-cleanups.cpp<br>
- copied, changed from r231098, cfe/trunk/test/CodeGenCXX/microsoft-abi-exceptions.cpp<br>
Removed:<br>
cfe/trunk/test/CodeGenCXX/microsoft-abi-exceptions.cpp<br>
Modified:<br>
cfe/trunk/lib/CodeGen/CGCXXABI.cpp<br>
cfe/trunk/lib/CodeGen/CGCXXABI.h<br>
cfe/trunk/lib/CodeGen/CGException.cpp<br>
cfe/trunk/lib/CodeGen/CodeGenModule.h<br>
cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp<br>
cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp<br>
cfe/trunk/test/CodeGenCXX/microsoft-abi-try-throw.cpp<br>
<br>
Modified: cfe/trunk/lib/CodeGen/CGCXXABI.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGCXXABI.cpp?rev=231105&r1=231104&r2=231105&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGCXXABI.cpp?rev=231105&r1=231104&r2=231105&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/CodeGen/CGCXXABI.cpp (original)<br>
+++ cfe/trunk/lib/CodeGen/CGCXXABI.cpp Tue Mar 3 13:21:04 2015<br>
@@ -302,3 +302,10 @@ CGCXXABI::EmitCtorCompleteObjectHandler(<br>
bool CGCXXABI::NeedsVTTParameter(GlobalDecl GD) {<br>
return false;<br>
}<br>
+<br>
+llvm::CallInst *<br>
+CGCXXABI::emitTerminateForUnexpectedException(CodeGenFunction &CGF,<br>
+ llvm::Value *Exn) {<br>
+ // Just call std::terminate and ignore the violating exception.<br>
+ return CGF.EmitNounwindRuntimeCall(CGF.CGM.getTerminateFn());<br>
+}<br>
<br>
Modified: cfe/trunk/lib/CodeGen/CGCXXABI.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGCXXABI.h?rev=231105&r1=231104&r2=231105&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGCXXABI.h?rev=231105&r1=231104&r2=231105&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/CodeGen/CGCXXABI.h (original)<br>
+++ cfe/trunk/lib/CodeGen/CGCXXABI.h Tue Mar 3 13:21:04 2015<br>
@@ -22,6 +22,7 @@ namespace llvm {<br>
class Constant;<br>
class Type;<br>
class Value;<br>
+class CallInst;<br>
}<br>
<br>
namespace clang {<br>
@@ -215,6 +216,12 @@ public:<br>
const CXXDestructorDecl *Dtor) = 0;<br>
virtual void emitRethrow(CodeGenFunction &CGF, bool isNoReturn) = 0;<br>
<br>
+ virtual void emitBeginCatch(CodeGenFunction &CGF, const CXXCatchStmt *C) = 0;<br>
+<br>
+ virtual llvm::CallInst *<br>
+ emitTerminateForUnexpectedException(CodeGenFunction &CGF,<br>
+ llvm::Value *Exn);<br>
+<br>
virtual llvm::Constant *getAddrOfRTTIDescriptor(QualType Ty) = 0;<br>
<br>
virtual bool shouldTypeidBeNullChecked(bool IsDeref,<br>
<br>
Modified: cfe/trunk/lib/CodeGen/CGException.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGException.cpp?rev=231105&r1=231104&r2=231105&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGException.cpp?rev=231105&r1=231104&r2=231105&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/CodeGen/CGException.cpp (original)<br>
+++ cfe/trunk/lib/CodeGen/CGException.cpp Tue Mar 3 13:21:04 2015<br>
@@ -54,39 +54,6 @@ static llvm::Constant *getThrowFn(CodeGe<br>
return CGM.CreateRuntimeFunction(FTy, "__cxa_throw");<br>
}<br>
<br>
-static llvm::Constant *getGetExceptionPtrFn(CodeGenModule &CGM) {<br>
- // void *__cxa_get_exception_ptr(void*);<br>
-<br>
- llvm::FunctionType *FTy =<br>
- llvm::FunctionType::get(CGM.Int8PtrTy, CGM.Int8PtrTy, /*IsVarArgs=*/false);<br>
-<br>
- return CGM.CreateRuntimeFunction(FTy, "__cxa_get_exception_ptr");<br>
-}<br>
-<br>
-static llvm::Constant *getBeginCatchFn(CodeGenModule &CGM) {<br>
- if (CGM.getTarget().getCXXABI().isMicrosoft())<br>
- return CGM.getIntrinsic(llvm::Intrinsic::eh_begincatch);<br>
-<br>
- // void *__cxa_begin_catch(void*);<br>
-<br>
- llvm::FunctionType *FTy =<br>
- llvm::FunctionType::get(CGM.Int8PtrTy, CGM.Int8PtrTy, /*IsVarArgs=*/false);<br>
-<br>
- return CGM.CreateRuntimeFunction(FTy, "__cxa_begin_catch");<br>
-}<br>
-<br>
-static llvm::Constant *getEndCatchFn(CodeGenModule &CGM) {<br>
- if (CGM.getTarget().getCXXABI().isMicrosoft())<br>
- return CGM.getIntrinsic(llvm::Intrinsic::eh_endcatch);<br>
-<br>
- // void __cxa_end_catch();<br>
-<br>
- llvm::FunctionType *FTy =<br>
- llvm::FunctionType::get(CGM.VoidTy, /*IsVarArgs=*/false);<br>
-<br>
- return CGM.CreateRuntimeFunction(FTy, "__cxa_end_catch");<br>
-}<br>
-<br>
static llvm::Constant *getUnexpectedFn(CodeGenModule &CGM) {<br>
// void __cxa_call_unexpected(void *thrown_exception);<br>
<br>
@@ -96,27 +63,27 @@ static llvm::Constant *getUnexpectedFn(C<br>
return CGM.CreateRuntimeFunction(FTy, "__cxa_call_unexpected");<br>
}<br>
<br>
-static llvm::Constant *getTerminateFn(CodeGenModule &CGM) {<br>
+llvm::Constant *CodeGenModule::getTerminateFn() {<br>
// void __terminate();<br>
<br>
llvm::FunctionType *FTy =<br>
- llvm::FunctionType::get(CGM.VoidTy, /*IsVarArgs=*/false);<br>
+ llvm::FunctionType::get(VoidTy, /*IsVarArgs=*/false);<br>
<br>
StringRef name;<br>
<br>
// In C++, use std::terminate().<br>
- if (CGM.getLangOpts().CPlusPlus &&<br>
- CGM.getTarget().getCXXABI().isItaniumFamily()) {<br>
+ if (getLangOpts().CPlusPlus &&<br>
+ getTarget().getCXXABI().isItaniumFamily()) {<br>
name = "_ZSt9terminatev";<br>
- } else if (CGM.getLangOpts().CPlusPlus &&<br>
- CGM.getTarget().getCXXABI().isMicrosoft()) {<br>
+ } else if (getLangOpts().CPlusPlus &&<br>
+ getTarget().getCXXABI().isMicrosoft()) {<br>
name = "\01?terminate@@YAXXZ";<br>
- } else if (CGM.getLangOpts().ObjC1 &&<br>
- CGM.getLangOpts().ObjCRuntime.hasTerminate())<br>
+ } else if (getLangOpts().ObjC1 &&<br>
+ getLangOpts().ObjCRuntime.hasTerminate())<br>
name = "objc_terminate";<br>
else<br>
name = "abort";<br>
- return CGM.CreateRuntimeFunction(FTy, name);<br>
+ return CreateRuntimeFunction(FTy, name);<br>
}<br>
<br>
static llvm::Constant *getCatchallRethrowFn(CodeGenModule &CGM,<br>
@@ -482,7 +449,7 @@ void CodeGenFunction::EmitCXXThrowExpr(c<br>
<br>
if (CGM.getTarget().getTriple().isKnownWindowsMSVCEnvironment()) {<br>
// Call std::terminate().<br>
- llvm::CallInst *TermCall = EmitNounwindRuntimeCall(getTerminateFn(CGM));<br>
+ llvm::CallInst *TermCall = EmitNounwindRuntimeCall(CGM.getTerminateFn());<br>
TermCall->setDoesNotReturn();<br>
<br>
// throw is an expression, and the expression emitters expect us<br>
@@ -920,263 +887,6 @@ llvm::BasicBlock *CodeGenFunction::EmitL<br>
return lpad;<br>
}<br>
<br>
-namespace {<br>
- /// A cleanup to call __cxa_end_catch. In many cases, the caught<br>
- /// exception type lets us state definitively that the thrown exception<br>
- /// type does not have a destructor. In particular:<br>
- /// - Catch-alls tell us nothing, so we have to conservatively<br>
- /// assume that the thrown exception might have a destructor.<br>
- /// - Catches by reference behave according to their base types.<br>
- /// - Catches of non-record types will only trigger for exceptions<br>
- /// of non-record types, which never have destructors.<br>
- /// - Catches of record types can trigger for arbitrary subclasses<br>
- /// of the caught type, so we have to assume the actual thrown<br>
- /// exception type might have a throwing destructor, even if the<br>
- /// caught type's destructor is trivial or nothrow.<br>
- struct CallEndCatch : EHScopeStack::Cleanup {<br>
- CallEndCatch(bool MightThrow) : MightThrow(MightThrow) {}<br>
- bool MightThrow;<br>
-<br>
- void Emit(CodeGenFunction &CGF, Flags flags) override {<br>
- if (!MightThrow) {<br>
- CGF.EmitNounwindRuntimeCall(getEndCatchFn(CGF.CGM));<br>
- return;<br>
- }<br>
-<br>
- CGF.EmitRuntimeCallOrInvoke(getEndCatchFn(CGF.CGM));<br>
- }<br>
- };<br>
-}<br>
-<br>
-/// Emits a call to __cxa_begin_catch and enters a cleanup to call<br>
-/// __cxa_end_catch.<br>
-///<br>
-/// \param EndMightThrow - true if __cxa_end_catch might throw<br>
-static llvm::Value *CallBeginCatch(CodeGenFunction &CGF,<br>
- llvm::Value *Exn,<br>
- bool EndMightThrow) {<br>
- llvm::CallInst *call =<br>
- CGF.EmitNounwindRuntimeCall(getBeginCatchFn(CGF.CGM), Exn);<br>
-<br>
- CGF.EHStack.pushCleanup<CallEndCatch>(NormalAndEHCleanup, EndMightThrow);<br>
-<br>
- return call;<br>
-}<br>
-<br>
-/// A "special initializer" callback for initializing a catch<br>
-/// parameter during catch initialization.<br>
-static void InitCatchParam(CodeGenFunction &CGF,<br>
- const VarDecl &CatchParam,<br>
- llvm::Value *ParamAddr,<br>
- SourceLocation Loc) {<br>
- // Load the exception from where the landing pad saved it.<br>
- llvm::Value *Exn = CGF.getExceptionFromSlot();<br>
-<br>
- CanQualType CatchType =<br>
- CGF.CGM.getContext().getCanonicalType(CatchParam.getType());<br>
- llvm::Type *LLVMCatchTy = CGF.ConvertTypeForMem(CatchType);<br>
-<br>
- // If we're catching by reference, we can just cast the object<br>
- // pointer to the appropriate pointer.<br>
- if (isa<ReferenceType>(CatchType)) {<br>
- QualType CaughtType = cast<ReferenceType>(CatchType)->getPointeeType();<br>
- bool EndCatchMightThrow = CaughtType->isRecordType();<br>
-<br>
- // __cxa_begin_catch returns the adjusted object pointer.<br>
- llvm::Value *AdjustedExn = CallBeginCatch(CGF, Exn, EndCatchMightThrow);<br>
-<br>
- // We have no way to tell the personality function that we're<br>
- // catching by reference, so if we're catching a pointer,<br>
- // __cxa_begin_catch will actually return that pointer by value.<br>
- if (const PointerType *PT = dyn_cast<PointerType>(CaughtType)) {<br>
- QualType PointeeType = PT->getPointeeType();<br>
-<br>
- // When catching by reference, generally we should just ignore<br>
- // this by-value pointer and use the exception object instead.<br>
- if (!PointeeType->isRecordType()) {<br>
-<br>
- // Exn points to the struct _Unwind_Exception header, which<br>
- // we have to skip past in order to reach the exception data.<br>
- unsigned HeaderSize =<br>
- CGF.CGM.getTargetCodeGenInfo().getSizeOfUnwindException();<br>
- AdjustedExn = CGF.Builder.CreateConstGEP1_32(Exn, HeaderSize);<br>
-<br>
- // However, if we're catching a pointer-to-record type that won't<br>
- // work, because the personality function might have adjusted<br>
- // the pointer. There's actually no way for us to fully satisfy<br>
- // the language/ABI contract here: we can't use Exn because it<br>
- // might have the wrong adjustment, but we can't use the by-value<br>
- // pointer because it's off by a level of abstraction.<br>
- //<br>
- // The current solution is to dump the adjusted pointer into an<br>
- // alloca, which breaks language semantics (because changing the<br>
- // pointer doesn't change the exception) but at least works.<br>
- // The better solution would be to filter out non-exact matches<br>
- // and rethrow them, but this is tricky because the rethrow<br>
- // really needs to be catchable by other sites at this landing<br>
- // pad. The best solution is to fix the personality function.<br>
- } else {<br>
- // Pull the pointer for the reference type off.<br>
- llvm::Type *PtrTy =<br>
- cast<llvm::PointerType>(LLVMCatchTy)->getElementType();<br>
-<br>
- // Create the temporary and write the adjusted pointer into it.<br>
- llvm::Value *ExnPtrTmp = CGF.CreateTempAlloca(PtrTy, "exn.byref.tmp");<br>
- llvm::Value *Casted = CGF.Builder.CreateBitCast(AdjustedExn, PtrTy);<br>
- CGF.Builder.CreateStore(Casted, ExnPtrTmp);<br>
-<br>
- // Bind the reference to the temporary.<br>
- AdjustedExn = ExnPtrTmp;<br>
- }<br>
- }<br>
-<br>
- llvm::Value *ExnCast =<br>
- CGF.Builder.CreateBitCast(AdjustedExn, LLVMCatchTy, "exn.byref");<br>
- CGF.Builder.CreateStore(ExnCast, ParamAddr);<br>
- return;<br>
- }<br>
-<br>
- // Scalars and complexes.<br>
- TypeEvaluationKind TEK = CGF.getEvaluationKind(CatchType);<br>
- if (TEK != TEK_Aggregate) {<br>
- llvm::Value *AdjustedExn = CallBeginCatch(CGF, Exn, false);<br>
-<br>
- // If the catch type is a pointer type, __cxa_begin_catch returns<br>
- // the pointer by value.<br>
- if (CatchType->hasPointerRepresentation()) {<br>
- llvm::Value *CastExn =<br>
- CGF.Builder.CreateBitCast(AdjustedExn, LLVMCatchTy, "exn.casted");<br>
-<br>
- switch (CatchType.getQualifiers().getObjCLifetime()) {<br>
- case Qualifiers::OCL_Strong:<br>
- CastExn = CGF.EmitARCRetainNonBlock(CastExn);<br>
- // fallthrough<br>
-<br>
- case Qualifiers::OCL_None:<br>
- case Qualifiers::OCL_ExplicitNone:<br>
- case Qualifiers::OCL_Autoreleasing:<br>
- CGF.Builder.CreateStore(CastExn, ParamAddr);<br>
- return;<br>
-<br>
- case Qualifiers::OCL_Weak:<br>
- CGF.EmitARCInitWeak(ParamAddr, CastExn);<br>
- return;<br>
- }<br>
- llvm_unreachable("bad ownership qualifier!");<br>
- }<br>
-<br>
- // Otherwise, it returns a pointer into the exception object.<br>
-<br>
- llvm::Type *PtrTy = LLVMCatchTy->getPointerTo(0); // addrspace 0 ok<br>
- llvm::Value *Cast = CGF.Builder.CreateBitCast(AdjustedExn, PtrTy);<br>
-<br>
- LValue srcLV = CGF.MakeNaturalAlignAddrLValue(Cast, CatchType);<br>
- LValue destLV = CGF.MakeAddrLValue(ParamAddr, CatchType,<br>
- CGF.getContext().getDeclAlign(&CatchParam));<br>
- switch (TEK) {<br>
- case TEK_Complex:<br>
- CGF.EmitStoreOfComplex(CGF.EmitLoadOfComplex(srcLV, Loc), destLV,<br>
- /*init*/ true);<br>
- return;<br>
- case TEK_Scalar: {<br>
- llvm::Value *ExnLoad = CGF.EmitLoadOfScalar(srcLV, Loc);<br>
- CGF.EmitStoreOfScalar(ExnLoad, destLV, /*init*/ true);<br>
- return;<br>
- }<br>
- case TEK_Aggregate:<br>
- llvm_unreachable("evaluation kind filtered out!");<br>
- }<br>
- llvm_unreachable("bad evaluation kind");<br>
- }<br>
-<br>
- assert(isa<RecordType>(CatchType) && "unexpected catch type!");<br>
-<br>
- llvm::Type *PtrTy = LLVMCatchTy->getPointerTo(0); // addrspace 0 ok<br>
-<br>
- // Check for a copy expression. If we don't have a copy expression,<br>
- // that means a trivial copy is okay.<br>
- const Expr *copyExpr = CatchParam.getInit();<br>
- if (!copyExpr) {<br>
- llvm::Value *rawAdjustedExn = CallBeginCatch(CGF, Exn, true);<br>
- llvm::Value *adjustedExn = CGF.Builder.CreateBitCast(rawAdjustedExn, PtrTy);<br>
- CGF.EmitAggregateCopy(ParamAddr, adjustedExn, CatchType);<br>
- return;<br>
- }<br>
-<br>
- // We have to call __cxa_get_exception_ptr to get the adjusted<br>
- // pointer before copying.<br>
- llvm::CallInst *rawAdjustedExn =<br>
- CGF.EmitNounwindRuntimeCall(getGetExceptionPtrFn(CGF.CGM), Exn);<br>
-<br>
- // Cast that to the appropriate type.<br>
- llvm::Value *adjustedExn = CGF.Builder.CreateBitCast(rawAdjustedExn, PtrTy);<br>
-<br>
- // The copy expression is defined in terms of an OpaqueValueExpr.<br>
- // Find it and map it to the adjusted expression.<br>
- CodeGenFunction::OpaqueValueMapping<br>
- opaque(CGF, OpaqueValueExpr::findInCopyConstruct(copyExpr),<br>
- CGF.MakeAddrLValue(adjustedExn, CatchParam.getType()));<br>
-<br>
- // Call the copy ctor in a terminate scope.<br>
- CGF.EHStack.pushTerminate();<br>
-<br>
- // Perform the copy construction.<br>
- CharUnits Alignment = CGF.getContext().getDeclAlign(&CatchParam);<br>
- CGF.EmitAggExpr(copyExpr,<br>
- AggValueSlot::forAddr(ParamAddr, Alignment, Qualifiers(),<br>
- AggValueSlot::IsNotDestructed,<br>
- AggValueSlot::DoesNotNeedGCBarriers,<br>
- AggValueSlot::IsNotAliased));<br>
-<br>
- // Leave the terminate scope.<br>
- CGF.EHStack.popTerminate();<br>
-<br>
- // Undo the opaque value mapping.<br>
- opaque.pop();<br>
-<br>
- // Finally we can call __cxa_begin_catch.<br>
- CallBeginCatch(CGF, Exn, true);<br>
-}<br>
-<br>
-/// Begins a catch statement by initializing the catch variable and<br>
-/// calling __cxa_begin_catch.<br>
-static void BeginCatch(CodeGenFunction &CGF, const CXXCatchStmt *S) {<br>
- // We have to be very careful with the ordering of cleanups here:<br>
- // C++ [except.throw]p4:<br>
- // The destruction [of the exception temporary] occurs<br>
- // immediately after the destruction of the object declared in<br>
- // the exception-declaration in the handler.<br>
- //<br>
- // So the precise ordering is:<br>
- // 1. Construct catch variable.<br>
- // 2. __cxa_begin_catch<br>
- // 3. Enter __cxa_end_catch cleanup<br>
- // 4. Enter dtor cleanup<br>
- //<br>
- // We do this by using a slightly abnormal initialization process.<br>
- // Delegation sequence:<br>
- // - ExitCXXTryStmt opens a RunCleanupsScope<br>
- // - EmitAutoVarAlloca creates the variable and debug info<br>
- // - InitCatchParam initializes the variable from the exception<br>
- // - CallBeginCatch calls __cxa_begin_catch<br>
- // - CallBeginCatch enters the __cxa_end_catch cleanup<br>
- // - EmitAutoVarCleanups enters the variable destructor cleanup<br>
- // - EmitCXXTryStmt emits the code for the catch body<br>
- // - EmitCXXTryStmt close the RunCleanupsScope<br>
-<br>
- VarDecl *CatchParam = S->getExceptionDecl();<br>
- if (!CatchParam) {<br>
- llvm::Value *Exn = CGF.getExceptionFromSlot();<br>
- CallBeginCatch(CGF, Exn, true);<br>
- return;<br>
- }<br>
-<br>
- // Emit the local.<br>
- CodeGenFunction::AutoVarEmission var = CGF.EmitAutoVarAlloca(*CatchParam);<br>
- InitCatchParam(CGF, *CatchParam, var.getObjectAddress(CGF), S->getLocStart());<br>
- CGF.EmitAutoVarCleanups(var);<br>
-}<br>
-<br>
/// Emit the structure of the dispatch block for the given catch scope.<br>
/// It is an invariant that the dispatch block already exists.<br>
static void emitCatchDispatchBlock(CodeGenFunction &CGF,<br>
@@ -1315,7 +1025,7 @@ void CodeGenFunction::ExitCXXTryStmt(con<br>
RunCleanupsScope CatchScope(*this);<br>
<br>
// Initialize the catch variable and set up the cleanups.<br>
- BeginCatch(*this, C);<br>
+ CGM.getCXXABI().emitBeginCatch(*this, C);<br>
<br>
// Emit the PGO counter increment.<br>
RegionCounter CatchCnt = getPGORegionCounter(C);<br>
@@ -1543,70 +1253,6 @@ void CodeGenFunction::FinallyInfo::exit(<br>
CGF.PopCleanupBlock();<br>
}<br>
<br>
-/// In a terminate landing pad, should we use __clang__call_terminate<br>
-/// or just a naked call to std::terminate?<br>
-///<br>
-/// __clang_call_terminate calls __cxa_begin_catch, which then allows<br>
-/// std::terminate to usefully report something about the<br>
-/// violating exception.<br>
-static bool useClangCallTerminate(CodeGenModule &CGM) {<br>
- // Only do this for Itanium-family ABIs in C++ mode.<br>
- return (CGM.getLangOpts().CPlusPlus &&<br>
- CGM.getTarget().getCXXABI().isItaniumFamily());<br>
-}<br>
-<br>
-/// Get or define the following function:<br>
-/// void @__clang_call_terminate(i8* %exn) nounwind noreturn<br>
-/// This code is used only in C++.<br>
-static llvm::Constant *getClangCallTerminateFn(CodeGenModule &CGM) {<br>
- llvm::FunctionType *fnTy =<br>
- llvm::FunctionType::get(CGM.VoidTy, CGM.Int8PtrTy, /*IsVarArgs=*/false);<br>
- llvm::Constant *fnRef =<br>
- CGM.CreateRuntimeFunction(fnTy, "__clang_call_terminate");<br>
-<br>
- llvm::Function *fn = dyn_cast<llvm::Function>(fnRef);<br>
- if (fn && fn->empty()) {<br>
- fn->setDoesNotThrow();<br>
- fn->setDoesNotReturn();<br>
-<br>
- // What we really want is to massively penalize inlining without<br>
- // forbidding it completely. The difference between that and<br>
- // 'noinline' is negligible.<br>
- fn->addFnAttr(llvm::Attribute::NoInline);<br>
-<br>
- // Allow this function to be shared across translation units, but<br>
- // we don't want it to turn into an exported symbol.<br>
- fn->setLinkage(llvm::Function::LinkOnceODRLinkage);<br>
- fn->setVisibility(llvm::Function::HiddenVisibility);<br>
- if (CGM.supportsCOMDAT())<br>
- fn->setComdat(CGM.getModule().getOrInsertComdat(fn->getName()));<br>
-<br>
- // Set up the function.<br>
- llvm::BasicBlock *entry =<br>
- llvm::BasicBlock::Create(CGM.getLLVMContext(), "", fn);<br>
- CGBuilderTy builder(entry);<br>
-<br>
- // Pull the exception pointer out of the parameter list.<br>
- llvm::Value *exn = &*fn->arg_begin();<br>
-<br>
- // Call __cxa_begin_catch(exn).<br>
- llvm::CallInst *catchCall = builder.CreateCall(getBeginCatchFn(CGM), exn);<br>
- catchCall->setDoesNotThrow();<br>
- catchCall->setCallingConv(CGM.getRuntimeCC());<br>
-<br>
- // Call std::terminate().<br>
- llvm::CallInst *termCall = builder.CreateCall(getTerminateFn(CGM));<br>
- termCall->setDoesNotThrow();<br>
- termCall->setDoesNotReturn();<br>
- termCall->setCallingConv(CGM.getRuntimeCC());<br>
-<br>
- // std::terminate cannot return.<br>
- builder.CreateUnreachable();<br>
- }<br>
-<br>
- return fnRef;<br>
-}<br>
-<br>
llvm::BasicBlock *CodeGenFunction::getTerminateLandingPad() {<br>
if (TerminateLandingPad)<br>
return TerminateLandingPad;<br>
@@ -1624,14 +1270,11 @@ llvm::BasicBlock *CodeGenFunction::getTe<br>
getOpaquePersonalityFn(CGM, Personality), 0);<br>
LPadInst->addClause(getCatchAllValue(*this));<br>
<br>
- llvm::CallInst *terminateCall;<br>
- if (useClangCallTerminate(CGM)) {<br>
- // Extract out the exception pointer.<br>
- llvm::Value *exn = Builder.CreateExtractValue(LPadInst, 0);<br>
- terminateCall = EmitNounwindRuntimeCall(getClangCallTerminateFn(CGM), exn);<br>
- } else {<br>
- terminateCall = EmitNounwindRuntimeCall(getTerminateFn(CGM));<br>
- }<br>
+ llvm::Value *Exn = 0;<br>
+ if (getLangOpts().CPlusPlus)<br>
+ Exn = Builder.CreateExtractValue(LPadInst, 0);<br>
+ llvm::CallInst *terminateCall =<br>
+ CGM.getCXXABI().emitTerminateForUnexpectedException(*this, Exn);<br>
terminateCall->setDoesNotReturn();<br>
Builder.CreateUnreachable();<br>
<br>
@@ -1651,14 +1294,11 @@ llvm::BasicBlock *CodeGenFunction::getTe<br>
// end of the function by FinishFunction.<br>
TerminateHandler = createBasicBlock("terminate.handler");<br>
Builder.SetInsertPoint(TerminateHandler);<br>
- llvm::CallInst *terminateCall;<br>
- if (useClangCallTerminate(CGM)) {<br>
- // Load the exception pointer.<br>
- llvm::Value *exn = getExceptionFromSlot();<br>
- terminateCall = EmitNounwindRuntimeCall(getClangCallTerminateFn(CGM), exn);<br>
- } else {<br>
- terminateCall = EmitNounwindRuntimeCall(getTerminateFn(CGM));<br>
- }<br>
+ llvm::Value *Exn = 0;<br>
+ if (getLangOpts().CPlusPlus)<br>
+ Exn = getExceptionFromSlot();<br>
+ llvm::CallInst *terminateCall =<br>
+ CGM.getCXXABI().emitTerminateForUnexpectedException(*this, Exn);<br>
terminateCall->setDoesNotReturn();<br>
Builder.CreateUnreachable();<br>
<br>
<br>
Modified: cfe/trunk/lib/CodeGen/CodeGenModule.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenModule.h?rev=231105&r1=231104&r2=231105&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenModule.h?rev=231105&r1=231104&r2=231105&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/CodeGen/CodeGenModule.h (original)<br>
+++ cfe/trunk/lib/CodeGen/CodeGenModule.h Tue Mar 3 13:21:04 2015<br>
@@ -1108,6 +1108,9 @@ public:<br>
void EmitVTableBitSetEntries(llvm::GlobalVariable *VTable,<br>
const VTableLayout &VTLayout);<br>
<br>
+ /// \breif Get the declaration of std::terminate for the platform.<br>
+ llvm::Constant *getTerminateFn();<br>
+<br>
private:<br>
llvm::Constant *<br>
GetOrCreateLLVMFunction(StringRef MangledName, llvm::Type *Ty, GlobalDecl D,<br>
<br>
Modified: cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp?rev=231105&r1=231104&r2=231105&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp?rev=231105&r1=231104&r2=231105&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp (original)<br>
+++ cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp Tue Mar 3 13:21:04 2015<br>
@@ -19,14 +19,18 @@<br>
//===----------------------------------------------------------------------===//<br>
<br>
#include "CGCXXABI.h"<br>
+#include "CGCleanup.h"<br>
#include "CGRecordLayout.h"<br>
#include "CGVTables.h"<br>
#include "CodeGenFunction.h"<br>
#include "CodeGenModule.h"<br>
+#include "TargetInfo.h"<br>
#include "clang/AST/Mangle.h"<br>
#include "clang/AST/Type.h"<br>
+#include "clang/AST/StmtCXX.h"<br>
#include "llvm/IR/CallSite.h"<br>
#include "llvm/IR/DataLayout.h"<br>
+#include "llvm/IR/Instructions.h"<br>
#include "llvm/IR/Intrinsics.h"<br>
#include "llvm/IR/Value.h"<br>
<br>
@@ -112,6 +116,12 @@ public:<br>
<br>
void emitRethrow(CodeGenFunction &CGF, bool isNoReturn) override;<br>
<br>
+ void emitBeginCatch(CodeGenFunction &CGF, const CXXCatchStmt *C) override;<br>
+<br>
+ llvm::CallInst *<br>
+ emitTerminateForUnexpectedException(CodeGenFunction &CGF,<br>
+ llvm::Value *Exn) override;<br>
+<br>
void EmitFundamentalRTTIDescriptor(QualType Type);<br>
void EmitFundamentalRTTIDescriptors();<br>
llvm::Constant *getAddrOfRTTIDescriptor(QualType Ty) override;<br>
@@ -3220,3 +3230,348 @@ void ItaniumCXXABI::emitCXXStructor(cons<br>
CGM.maybeSetTrivialComdat(*MD, *Fn);<br>
}<br>
}<br>
+<br>
+static llvm::Constant *getBeginCatchFn(CodeGenModule &CGM) {<br>
+ // void *__cxa_begin_catch(void*);<br>
+ llvm::FunctionType *FTy = llvm::FunctionType::get(<br>
+ CGM.Int8PtrTy, CGM.Int8PtrTy, /*IsVarArgs=*/false);<br>
+<br>
+ return CGM.CreateRuntimeFunction(FTy, "__cxa_begin_catch");<br>
+}<br>
+<br>
+static llvm::Constant *getEndCatchFn(CodeGenModule &CGM) {<br>
+ // void __cxa_end_catch();<br>
+ llvm::FunctionType *FTy =<br>
+ llvm::FunctionType::get(CGM.VoidTy, /*IsVarArgs=*/false);<br>
+<br>
+ return CGM.CreateRuntimeFunction(FTy, "__cxa_end_catch");<br>
+}<br>
+<br>
+static llvm::Constant *getGetExceptionPtrFn(CodeGenModule &CGM) {<br>
+ // void *__cxa_get_exception_ptr(void*);<br>
+ llvm::FunctionType *FTy = llvm::FunctionType::get(<br>
+ CGM.Int8PtrTy, CGM.Int8PtrTy, /*IsVarArgs=*/false);<br>
+<br>
+ return CGM.CreateRuntimeFunction(FTy, "__cxa_get_exception_ptr");<br>
+}<br>
+<br>
+namespace {<br>
+ /// A cleanup to call __cxa_end_catch. In many cases, the caught<br>
+ /// exception type lets us state definitively that the thrown exception<br>
+ /// type does not have a destructor. In particular:<br>
+ /// - Catch-alls tell us nothing, so we have to conservatively<br>
+ /// assume that the thrown exception might have a destructor.<br>
+ /// - Catches by reference behave according to their base types.<br>
+ /// - Catches of non-record types will only trigger for exceptions<br>
+ /// of non-record types, which never have destructors.<br>
+ /// - Catches of record types can trigger for arbitrary subclasses<br>
+ /// of the caught type, so we have to assume the actual thrown<br>
+ /// exception type might have a throwing destructor, even if the<br>
+ /// caught type's destructor is trivial or nothrow.<br>
+ struct CallEndCatch : EHScopeStack::Cleanup {<br>
+ CallEndCatch(bool MightThrow) : MightThrow(MightThrow) {}<br>
+ bool MightThrow;<br>
+<br>
+ void Emit(CodeGenFunction &CGF, Flags flags) override {<br>
+ if (!MightThrow) {<br>
+ CGF.EmitNounwindRuntimeCall(getEndCatchFn(CGF.CGM));<br>
+ return;<br>
+ }<br>
+<br>
+ CGF.EmitRuntimeCallOrInvoke(getEndCatchFn(CGF.CGM));<br>
+ }<br>
+ };<br>
+}<br>
+<br>
+/// Emits a call to __cxa_begin_catch and enters a cleanup to call<br>
+/// __cxa_end_catch.<br>
+///<br>
+/// \param EndMightThrow - true if __cxa_end_catch might throw<br>
+static llvm::Value *CallBeginCatch(CodeGenFunction &CGF,<br>
+ llvm::Value *Exn,<br>
+ bool EndMightThrow) {<br>
+ llvm::CallInst *call =<br>
+ CGF.EmitNounwindRuntimeCall(getBeginCatchFn(CGF.CGM), Exn);<br>
+<br>
+ CGF.EHStack.pushCleanup<CallEndCatch>(NormalAndEHCleanup, EndMightThrow);<br>
+<br>
+ return call;<br>
+}<br>
+<br>
+/// A "special initializer" callback for initializing a catch<br>
+/// parameter during catch initialization.<br>
+static void InitCatchParam(CodeGenFunction &CGF,<br>
+ const VarDecl &CatchParam,<br>
+ llvm::Value *ParamAddr,<br>
+ SourceLocation Loc) {<br>
+ // Load the exception from where the landing pad saved it.<br>
+ llvm::Value *Exn = CGF.getExceptionFromSlot();<br>
+<br>
+ CanQualType CatchType =<br>
+ CGF.CGM.getContext().getCanonicalType(CatchParam.getType());<br>
+ llvm::Type *LLVMCatchTy = CGF.ConvertTypeForMem(CatchType);<br>
+<br>
+ // If we're catching by reference, we can just cast the object<br>
+ // pointer to the appropriate pointer.<br>
+ if (isa<ReferenceType>(CatchType)) {<br>
+ QualType CaughtType = cast<ReferenceType>(CatchType)->getPointeeType();<br>
+ bool EndCatchMightThrow = CaughtType->isRecordType();<br>
+<br>
+ // __cxa_begin_catch returns the adjusted object pointer.<br>
+ llvm::Value *AdjustedExn = CallBeginCatch(CGF, Exn, EndCatchMightThrow);<br>
+<br>
+ // We have no way to tell the personality function that we're<br>
+ // catching by reference, so if we're catching a pointer,<br>
+ // __cxa_begin_catch will actually return that pointer by value.<br>
+ if (const PointerType *PT = dyn_cast<PointerType>(CaughtType)) {<br>
+ QualType PointeeType = PT->getPointeeType();<br>
+<br>
+ // When catching by reference, generally we should just ignore<br>
+ // this by-value pointer and use the exception object instead.<br>
+ if (!PointeeType->isRecordType()) {<br>
+<br>
+ // Exn points to the struct _Unwind_Exception header, which<br>
+ // we have to skip past in order to reach the exception data.<br>
+ unsigned HeaderSize =<br>
+ CGF.CGM.getTargetCodeGenInfo().getSizeOfUnwindException();<br>
+ AdjustedExn = CGF.Builder.CreateConstGEP1_32(Exn, HeaderSize);<br>
+<br>
+ // However, if we're catching a pointer-to-record type that won't<br>
+ // work, because the personality function might have adjusted<br>
+ // the pointer. There's actually no way for us to fully satisfy<br>
+ // the language/ABI contract here: we can't use Exn because it<br>
+ // might have the wrong adjustment, but we can't use the by-value<br>
+ // pointer because it's off by a level of abstraction.<br>
+ //<br>
+ // The current solution is to dump the adjusted pointer into an<br>
+ // alloca, which breaks language semantics (because changing the<br>
+ // pointer doesn't change the exception) but at least works.<br>
+ // The better solution would be to filter out non-exact matches<br>
+ // and rethrow them, but this is tricky because the rethrow<br>
+ // really needs to be catchable by other sites at this landing<br>
+ // pad. The best solution is to fix the personality function.<br>
+ } else {<br>
+ // Pull the pointer for the reference type off.<br>
+ llvm::Type *PtrTy =<br>
+ cast<llvm::PointerType>(LLVMCatchTy)->getElementType();<br>
+<br>
+ // Create the temporary and write the adjusted pointer into it.<br>
+ llvm::Value *ExnPtrTmp = CGF.CreateTempAlloca(PtrTy, "exn.byref.tmp");<br>
+ llvm::Value *Casted = CGF.Builder.CreateBitCast(AdjustedExn, PtrTy);<br>
+ CGF.Builder.CreateStore(Casted, ExnPtrTmp);<br>
+<br>
+ // Bind the reference to the temporary.<br>
+ AdjustedExn = ExnPtrTmp;<br>
+ }<br>
+ }<br>
+<br>
+ llvm::Value *ExnCast =<br>
+ CGF.Builder.CreateBitCast(AdjustedExn, LLVMCatchTy, "exn.byref");<br>
+ CGF.Builder.CreateStore(ExnCast, ParamAddr);<br>
+ return;<br>
+ }<br>
+<br>
+ // Scalars and complexes.<br>
+ TypeEvaluationKind TEK = CGF.getEvaluationKind(CatchType);<br>
+ if (TEK != TEK_Aggregate) {<br>
+ llvm::Value *AdjustedExn = CallBeginCatch(CGF, Exn, false);<br>
+<br>
+ // If the catch type is a pointer type, __cxa_begin_catch returns<br>
+ // the pointer by value.<br>
+ if (CatchType->hasPointerRepresentation()) {<br>
+ llvm::Value *CastExn =<br>
+ CGF.Builder.CreateBitCast(AdjustedExn, LLVMCatchTy, "exn.casted");<br>
+<br>
+ switch (CatchType.getQualifiers().getObjCLifetime()) {<br>
+ case Qualifiers::OCL_Strong:<br>
+ CastExn = CGF.EmitARCRetainNonBlock(CastExn);<br>
+ // fallthrough<br>
+<br>
+ case Qualifiers::OCL_None:<br>
+ case Qualifiers::OCL_ExplicitNone:<br>
+ case Qualifiers::OCL_Autoreleasing:<br>
+ CGF.Builder.CreateStore(CastExn, ParamAddr);<br>
+ return;<br>
+<br>
+ case Qualifiers::OCL_Weak:<br>
+ CGF.EmitARCInitWeak(ParamAddr, CastExn);<br>
+ return;<br>
+ }<br>
+ llvm_unreachable("bad ownership qualifier!");<br>
+ }<br>
+<br>
+ // Otherwise, it returns a pointer into the exception object.<br>
+<br>
+ llvm::Type *PtrTy = LLVMCatchTy->getPointerTo(0); // addrspace 0 ok<br>
+ llvm::Value *Cast = CGF.Builder.CreateBitCast(AdjustedExn, PtrTy);<br>
+<br>
+ LValue srcLV = CGF.MakeNaturalAlignAddrLValue(Cast, CatchType);<br>
+ LValue destLV = CGF.MakeAddrLValue(ParamAddr, CatchType,<br>
+ CGF.getContext().getDeclAlign(&CatchParam));<br>
+ switch (TEK) {<br>
+ case TEK_Complex:<br>
+ CGF.EmitStoreOfComplex(CGF.EmitLoadOfComplex(srcLV, Loc), destLV,<br>
+ /*init*/ true);<br>
+ return;<br>
+ case TEK_Scalar: {<br>
+ llvm::Value *ExnLoad = CGF.EmitLoadOfScalar(srcLV, Loc);<br>
+ CGF.EmitStoreOfScalar(ExnLoad, destLV, /*init*/ true);<br>
+ return;<br>
+ }<br>
+ case TEK_Aggregate:<br>
+ llvm_unreachable("evaluation kind filtered out!");<br>
+ }<br>
+ llvm_unreachable("bad evaluation kind");<br>
+ }<br>
+<br>
+ assert(isa<RecordType>(CatchType) && "unexpected catch type!");<br>
+<br>
+ llvm::Type *PtrTy = LLVMCatchTy->getPointerTo(0); // addrspace 0 ok<br>
+<br>
+ // Check for a copy expression. If we don't have a copy expression,<br>
+ // that means a trivial copy is okay.<br>
+ const Expr *copyExpr = CatchParam.getInit();<br>
+ if (!copyExpr) {<br>
+ llvm::Value *rawAdjustedExn = CallBeginCatch(CGF, Exn, true);<br>
+ llvm::Value *adjustedExn = CGF.Builder.CreateBitCast(rawAdjustedExn, PtrTy);<br>
+ CGF.EmitAggregateCopy(ParamAddr, adjustedExn, CatchType);<br>
+ return;<br>
+ }<br>
+<br>
+ // We have to call __cxa_get_exception_ptr to get the adjusted<br>
+ // pointer before copying.<br>
+ llvm::CallInst *rawAdjustedExn =<br>
+ CGF.EmitNounwindRuntimeCall(getGetExceptionPtrFn(CGF.CGM), Exn);<br>
+<br>
+ // Cast that to the appropriate type.<br>
+ llvm::Value *adjustedExn = CGF.Builder.CreateBitCast(rawAdjustedExn, PtrTy);<br>
+<br>
+ // The copy expression is defined in terms of an OpaqueValueExpr.<br>
+ // Find it and map it to the adjusted expression.<br>
+ CodeGenFunction::OpaqueValueMapping<br>
+ opaque(CGF, OpaqueValueExpr::findInCopyConstruct(copyExpr),<br>
+ CGF.MakeAddrLValue(adjustedExn, CatchParam.getType()));<br>
+<br>
+ // Call the copy ctor in a terminate scope.<br>
+ CGF.EHStack.pushTerminate();<br>
+<br>
+ // Perform the copy construction.<br>
+ CharUnits Alignment = CGF.getContext().getDeclAlign(&CatchParam);<br>
+ CGF.EmitAggExpr(copyExpr,<br>
+ AggValueSlot::forAddr(ParamAddr, Alignment, Qualifiers(),<br>
+ AggValueSlot::IsNotDestructed,<br>
+ AggValueSlot::DoesNotNeedGCBarriers,<br>
+ AggValueSlot::IsNotAliased));<br>
+<br>
+ // Leave the terminate scope.<br>
+ CGF.EHStack.popTerminate();<br>
+<br>
+ // Undo the opaque value mapping.<br>
+ opaque.pop();<br>
+<br>
+ // Finally we can call __cxa_begin_catch.<br>
+ CallBeginCatch(CGF, Exn, true);<br>
+}<br>
+<br>
+/// Begins a catch statement by initializing the catch variable and<br>
+/// calling __cxa_begin_catch.<br>
+void ItaniumCXXABI::emitBeginCatch(CodeGenFunction &CGF,<br>
+ const CXXCatchStmt *S) {<br>
+ // We have to be very careful with the ordering of cleanups here:<br>
+ // C++ [except.throw]p4:<br>
+ // The destruction [of the exception temporary] occurs<br>
+ // immediately after the destruction of the object declared in<br>
+ // the exception-declaration in the handler.<br>
+ //<br>
+ // So the precise ordering is:<br>
+ // 1. Construct catch variable.<br>
+ // 2. __cxa_begin_catch<br>
+ // 3. Enter __cxa_end_catch cleanup<br>
+ // 4. Enter dtor cleanup<br>
+ //<br>
+ // We do this by using a slightly abnormal initialization process.<br>
+ // Delegation sequence:<br>
+ // - ExitCXXTryStmt opens a RunCleanupsScope<br>
+ // - EmitAutoVarAlloca creates the variable and debug info<br>
+ // - InitCatchParam initializes the variable from the exception<br>
+ // - CallBeginCatch calls __cxa_begin_catch<br>
+ // - CallBeginCatch enters the __cxa_end_catch cleanup<br>
+ // - EmitAutoVarCleanups enters the variable destructor cleanup<br>
+ // - EmitCXXTryStmt emits the code for the catch body<br>
+ // - EmitCXXTryStmt close the RunCleanupsScope<br>
+<br>
+ VarDecl *CatchParam = S->getExceptionDecl();<br>
+ if (!CatchParam) {<br>
+ llvm::Value *Exn = CGF.getExceptionFromSlot();<br>
+ CallBeginCatch(CGF, Exn, true);<br>
+ return;<br>
+ }<br>
+<br>
+ // Emit the local.<br>
+ CodeGenFunction::AutoVarEmission var = CGF.EmitAutoVarAlloca(*CatchParam);<br>
+ InitCatchParam(CGF, *CatchParam, var.getObjectAddress(CGF), S->getLocStart());<br>
+ CGF.EmitAutoVarCleanups(var);<br>
+}<br>
+<br>
+/// Get or define the following function:<br>
+/// void @__clang_call_terminate(i8* %exn) nounwind noreturn<br>
+/// This code is used only in C++.<br>
+static llvm::Constant *getClangCallTerminateFn(CodeGenModule &CGM) {<br>
+ llvm::FunctionType *fnTy =<br>
+ llvm::FunctionType::get(CGM.VoidTy, CGM.Int8PtrTy, /*IsVarArgs=*/false);<br>
+ llvm::Constant *fnRef =<br>
+ CGM.CreateRuntimeFunction(fnTy, "__clang_call_terminate");<br>
+<br>
+ llvm::Function *fn = dyn_cast<llvm::Function>(fnRef);<br>
+ if (fn && fn->empty()) {<br>
+ fn->setDoesNotThrow();<br>
+ fn->setDoesNotReturn();<br>
+<br>
+ // What we really want is to massively penalize inlining without<br>
+ // forbidding it completely. The difference between that and<br>
+ // 'noinline' is negligible.<br>
+ fn->addFnAttr(llvm::Attribute::NoInline);<br>
+<br>
+ // Allow this function to be shared across translation units, but<br>
+ // we don't want it to turn into an exported symbol.<br>
+ fn->setLinkage(llvm::Function::LinkOnceODRLinkage);<br>
+ fn->setVisibility(llvm::Function::HiddenVisibility);<br>
+ if (CGM.supportsCOMDAT())<br>
+ fn->setComdat(CGM.getModule().getOrInsertComdat(fn->getName()));<br>
+<br>
+ // Set up the function.<br>
+ llvm::BasicBlock *entry =<br>
+ llvm::BasicBlock::Create(CGM.getLLVMContext(), "", fn);<br>
+ CGBuilderTy builder(entry);<br>
+<br>
+ // Pull the exception pointer out of the parameter list.<br>
+ llvm::Value *exn = &*fn->arg_begin();<br>
+<br>
+ // Call __cxa_begin_catch(exn).<br>
+ llvm::CallInst *catchCall = builder.CreateCall(getBeginCatchFn(CGM), exn);<br>
+ catchCall->setDoesNotThrow();<br>
+ catchCall->setCallingConv(CGM.getRuntimeCC());<br>
+<br>
+ // Call std::terminate().<br>
+ llvm::CallInst *termCall = builder.CreateCall(CGM.getTerminateFn());<br>
+ termCall->setDoesNotThrow();<br>
+ termCall->setDoesNotReturn();<br>
+ termCall->setCallingConv(CGM.getRuntimeCC());<br>
+<br>
+ // std::terminate cannot return.<br>
+ builder.CreateUnreachable();<br>
+ }<br>
+<br>
+ return fnRef;<br>
+}<br>
+<br>
+llvm::CallInst *<br>
+ItaniumCXXABI::emitTerminateForUnexpectedException(CodeGenFunction &CGF,<br>
+ llvm::Value *Exn) {<br>
+ // In C++, we want to call __cxa_begin_catch() before terminating.<br>
+ if (Exn) {<br>
+ assert(CGF.CGM.getLangOpts().CPlusPlus);<br>
+ return CGF.EmitNounwindRuntimeCall(getClangCallTerminateFn(CGF.CGM), Exn);<br>
+ }<br>
+ return CGF.EmitNounwindRuntimeCall(CGF.CGM.getTerminateFn());<br>
+}<br>
<br>
Modified: cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp?rev=231105&r1=231104&r2=231105&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp?rev=231105&r1=231104&r2=231105&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp (original)<br>
+++ cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp Tue Mar 3 13:21:04 2015<br>
@@ -17,12 +17,15 @@<br>
#include "CGCXXABI.h"<br>
#include "CGVTables.h"<br>
#include "CodeGenModule.h"<br>
+#include "TargetInfo.h"<br>
#include "clang/AST/Decl.h"<br>
#include "clang/AST/DeclCXX.h"<br>
+#include "clang/AST/StmtCXX.h"<br>
#include "clang/AST/VTableBuilder.h"<br>
#include "llvm/ADT/StringExtras.h"<br>
#include "llvm/ADT/StringSet.h"<br>
#include "llvm/IR/CallSite.h"<br>
+#include "llvm/IR/Intrinsics.h"<br>
<br>
using namespace clang;<br>
using namespace CodeGen;<br>
@@ -72,6 +75,8 @@ public:<br>
<br>
void emitRethrow(CodeGenFunction &CGF, bool isNoReturn) override;<br>
<br>
+ void emitBeginCatch(CodeGenFunction &CGF, const CXXCatchStmt *C) override;<br>
+<br>
llvm::GlobalVariable *getMSCompleteObjectLocator(const CXXRecordDecl *RD,<br>
const VPtrInfo *Info);<br>
<br>
@@ -695,6 +700,42 @@ void MicrosoftCXXABI::emitRethrow(CodeGe<br>
CGF.EmitRuntimeCallOrInvoke(Fn, Args);<br>
}<br>
<br>
+namespace {<br>
+struct CallEndCatchMSVC : EHScopeStack::Cleanup {<br>
+ CallEndCatchMSVC() {}<br>
+ void Emit(CodeGenFunction &CGF, Flags flags) override {<br>
+ CGF.EmitNounwindRuntimeCall(<br>
+ CGF.CGM.getIntrinsic(llvm::Intrinsic::eh_endcatch));<br>
+ }<br>
+};<br>
+}<br>
+<br>
+void MicrosoftCXXABI::emitBeginCatch(CodeGenFunction &CGF,<br>
+ const CXXCatchStmt *S) {<br>
+ // In the MS ABI, the runtime handles the copy, and the catch handler is<br>
+ // responsible for destruction.<br>
+ VarDecl *CatchParam = S->getExceptionDecl();<br>
+ llvm::Value *Exn = CGF.getExceptionFromSlot();<br>
+ llvm::Function *BeginCatch =<br>
+ CGF.CGM.getIntrinsic(llvm::Intrinsic::eh_begincatch);<br>
+<br>
+ if (!CatchParam) {<br>
+ llvm::Value *Args[2] = {Exn, llvm::Constant::getNullValue(CGF.Int8PtrTy)};<br>
+ CGF.EmitNounwindRuntimeCall(BeginCatch, Args);<br>
+ CGF.EHStack.pushCleanup<CallEndCatchMSVC>(NormalAndEHCleanup);<br>
+ return;<br>
+ }<br>
+<br>
+ CodeGenFunction::AutoVarEmission var = CGF.EmitAutoVarAlloca(*CatchParam);<br>
+ llvm::Value *ParamAddr =<br>
+ CGF.Builder.CreateBitCast(var.getObjectAddress(CGF), CGF.Int8PtrTy);<br>
+ llvm::Value *Args[2] = {Exn, ParamAddr};<br>
+ CGF.EmitNounwindRuntimeCall(BeginCatch, Args);<br>
+ // FIXME: Do we really need exceptional endcatch cleanups?<br>
+ CGF.EHStack.pushCleanup<CallEndCatchMSVC>(NormalAndEHCleanup);<br>
+ CGF.EmitAutoVarCleanups(var);<br>
+}<br>
+<br>
std::pair<llvm::Value *, llvm::Value *><br>
MicrosoftCXXABI::performBaseAdjustment(CodeGenFunction &CGF, llvm::Value *Value,<br>
QualType SrcRecordTy) {<br>
<br>
Added: cfe/trunk/test/CodeGenCXX/microsoft-abi-eh-catch.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/microsoft-abi-eh-catch.cpp?rev=231105&view=auto" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/microsoft-abi-eh-catch.cpp?rev=231105&view=auto</a><br>
==============================================================================<br>
--- cfe/trunk/test/CodeGenCXX/microsoft-abi-eh-catch.cpp (added)<br>
+++ cfe/trunk/test/CodeGenCXX/microsoft-abi-eh-catch.cpp Tue Mar 3 13:21:04 2015<br>
@@ -0,0 +1,98 @@<br>
+// RUN: %clang_cc1 -std=c++11 -emit-llvm %s -o - -triple=x86_64-pc-windows-msvc -mconstructor-aliases -fexceptions -fcxx-exceptions | FileCheck -check-prefix WIN64 %s<br>
+<br>
+extern "C" void might_throw();<br>
+<br>
+// Simplify the generated IR with noexcept.<br>
+extern "C" void recover() noexcept(true);<br>
+extern "C" void handle_exception(void *e) noexcept(true);<br>
+<br>
+extern "C" void catch_all() {<br>
+ try {<br>
+ might_throw();<br>
+ } catch (...) {<br>
+ recover();<br>
+ }<br>
+}<br>
+<br>
+// WIN64-LABEL: define void @catch_all()<br>
+// WIN64: invoke void @might_throw()<br>
+// WIN64-NEXT: to label %[[cont:[^ ]*]] unwind label %[[lpad:[^ ]*]]<br>
+//<br>
+// WIN64: [[cont]]<br>
+// WIN64: br label %[[ret:[^ ]*]]<br>
+//<br>
+// WIN64: [[lpad]]<br>
+// WIN64: landingpad { i8*, i32 }<br>
+// WIN64-NEXT: catch i8* null<br>
+// WIN64: call void @llvm.eh.begincatch(i8* %{{[^,]*}}, i8* null)<br>
+// WIN64: call void @recover()<br>
+// WIN64: call void @llvm.eh.endcatch()<br>
+// WIN64: br label %[[ret]]<br>
+//<br>
+// WIN64: [[ret]]<br>
+// WIN64: ret void<br>
+<br>
+extern "C" void catch_int() {<br>
+ try {<br>
+ might_throw();<br>
+ } catch (int e) {<br>
+ handle_exception(&e);<br>
+ }<br>
+}<br>
+<br>
+// WIN64-LABEL: define void @catch_int()<br>
+// WIN64: landingpad { i8*, i32 }<br>
+// WIN64: %[[e_i8:[^ ]*]] = bitcast i32* %[[e_addr:[^ ]*]] to i8*<br>
+// WIN64: call void @llvm.eh.begincatch(i8* %{{.*}}, i8* %[[e_i8]])<br>
+// WIN64: %[[e_i8:[^ ]*]] = bitcast i32* %[[e_addr]] to i8*<br>
+// WIN64: call void @handle_exception(i8* %[[e_i8]])<br>
+// WIN64: call void @llvm.eh.endcatch()<br>
+<br>
+struct A {<br>
+ A();<br>
+ A(const A &o);<br>
+ ~A();<br>
+ int a;<br>
+};<br>
+<br>
+struct B : A {<br>
+ B();<br>
+ B(const B &o);<br>
+ ~B();<br>
+ int b;<br>
+};<br>
+<br>
+extern "C" void catch_a_byval() {<br>
+ try {<br>
+ might_throw();<br>
+ } catch (A e) {<br>
+ handle_exception(&e);<br>
+ }<br>
+}<br>
+<br>
+// WIN64-LABEL: define void @catch_a_byval()<br>
+// WIN64: %[[e_addr:[^ ]*]] = alloca %struct.A<br>
+// WIN64: landingpad { i8*, i32 }<br>
+// WIN64: %[[e_i8:[^ ]*]] = bitcast %struct.A* %[[e_addr]] to i8*<br>
+// WIN64: call void @llvm.eh.begincatch(i8* %{{.*}}, i8* %[[e_i8]])<br>
+// WIN64: %[[e_i8:[^ ]*]] = bitcast %struct.A* %[[e_addr]] to i8*<br>
+// WIN64: call void @handle_exception(i8* %[[e_i8]])<br>
+// WIN64: call void @llvm.eh.endcatch()<br>
+<br>
+extern "C" void catch_a_ref() {<br>
+ try {<br>
+ might_throw();<br>
+ } catch (A &e) {<br>
+ handle_exception(&e);<br>
+ }<br>
+}<br>
+<br>
+// WIN64-LABEL: define void @catch_a_ref()<br>
+// WIN64: %[[e_addr:[^ ]*]] = alloca %struct.A*<br>
+// WIN64: landingpad { i8*, i32 }<br>
+// WIN64: %[[e_i8:[^ ]*]] = bitcast %struct.A** %[[e_addr]] to i8*<br>
+// WIN64: call void @llvm.eh.begincatch(i8* %{{.*}}, i8* %[[e_i8]])<br>
+// WIN64: %[[eptr:[^ ]*]] = load %struct.A*, %struct.A** %[[e_addr]]<br>
+// WIN64: %[[eptr_i8:[^ ]*]] = bitcast %struct.A* %[[eptr]] to i8*<br>
+// WIN64: call void @handle_exception(i8* %[[eptr_i8]])<br>
+// WIN64: call void @llvm.eh.endcatch()<br>
<br>
Copied: cfe/trunk/test/CodeGenCXX/microsoft-abi-eh-cleanups.cpp (from r231098, cfe/trunk/test/CodeGenCXX/microsoft-abi-exceptions.cpp)<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/microsoft-abi-eh-cleanups.cpp?p2=cfe/trunk/test/CodeGenCXX/microsoft-abi-eh-cleanups.cpp&p1=cfe/trunk/test/CodeGenCXX/microsoft-abi-exceptions.cpp&r1=231098&r2=231105&rev=231105&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/microsoft-abi-eh-cleanups.cpp?p2=cfe/trunk/test/CodeGenCXX/microsoft-abi-eh-cleanups.cpp&p1=cfe/trunk/test/CodeGenCXX/microsoft-abi-exceptions.cpp&r1=231098&r2=231105&rev=231105&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/test/CodeGenCXX/microsoft-abi-exceptions.cpp (original)<br>
+++ cfe/trunk/test/CodeGenCXX/microsoft-abi-eh-cleanups.cpp Tue Mar 3 13:21:04 2015<br>
@@ -1,4 +1,4 @@<br>
-// RUN: %clang_cc1 -emit-llvm %s -o - -triple=i386-pc-win32 -mconstructor-aliases -fexceptions -fno-rtti | FileCheck -check-prefix WIN32 %s<br>
+// RUN: %clang_cc1 -emit-llvm %s -o - -triple=i386-pc-win32 -mconstructor-aliases -fexceptions -fcxx-exceptions -fno-rtti | FileCheck -check-prefix WIN32 %s<br>
<br>
struct A {<br>
A();<br>
<br>
Removed: cfe/trunk/test/CodeGenCXX/microsoft-abi-exceptions.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/microsoft-abi-exceptions.cpp?rev=231104&view=auto" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/microsoft-abi-exceptions.cpp?rev=231104&view=auto</a><br>
==============================================================================<br>
--- cfe/trunk/test/CodeGenCXX/microsoft-abi-exceptions.cpp (original)<br>
+++ cfe/trunk/test/CodeGenCXX/microsoft-abi-exceptions.cpp (removed)<br>
@@ -1,170 +0,0 @@<br>
-// RUN: %clang_cc1 -emit-llvm %s -o - -triple=i386-pc-win32 -mconstructor-aliases -fexceptions -fno-rtti | FileCheck -check-prefix WIN32 %s<br>
-<br>
-struct A {<br>
- A();<br>
- ~A();<br>
- int a;<br>
-};<br>
-<br>
-A getA();<br>
-<br>
-int TakesTwo(A a, A b);<br>
-void HasEHCleanup() {<br>
- TakesTwo(getA(), getA());<br>
-}<br>
-<br>
-// With exceptions, we need to clean up at least one of these temporaries.<br>
-// WIN32-LABEL: define void @"\01?HasEHCleanup@@YAXXZ"() {{.*}} {<br>
-// WIN32: %[[base:.*]] = call i8* @llvm.stacksave()<br>
-// If this call throws, we have to restore the stack.<br>
-// WIN32: invoke void @"\01?getA@@YA?AUA@@XZ"(%struct.A* sret %{{.*}})<br>
-// If this call throws, we have to cleanup the first temporary.<br>
-// WIN32: invoke void @"\01?getA@@YA?AUA@@XZ"(%struct.A* sret %{{.*}})<br>
-// If this call throws, we have to cleanup the stacksave.<br>
-// WIN32: invoke i32 @"\01?TakesTwo@@YAHUA@@0@Z"<br>
-// WIN32: call void @llvm.stackrestore(i8* %[[base]])<br>
-// WIN32: ret void<br>
-//<br>
-// There should be one dtor call for unwinding from the second getA.<br>
-// WIN32: invoke x86_thiscallcc void @"\01??1A@@QAE@XZ"<br>
-// WIN32-NOT: @"\01??1A@@QAE@XZ"<br>
-// WIN32: call void @llvm.stackrestore<br>
-// WIN32: }<br>
-<br>
-void TakeRef(const A &a);<br>
-int HasDeactivatedCleanups() {<br>
- return TakesTwo((TakeRef(A()), A()), (TakeRef(A()), A()));<br>
-}<br>
-<br>
-// WIN32-LABEL: define i32 @"\01?HasDeactivatedCleanups@@YAHXZ"() {{.*}} {<br>
-// WIN32: %[[isactive:.*]] = alloca i1<br>
-// WIN32: call i8* @llvm.stacksave()<br>
-// WIN32: %[[argmem:.*]] = alloca inalloca [[argmem_ty:<{ %struct.A, %struct.A }>]]<br>
-// WIN32: %[[arg1:.*]] = getelementptr inbounds [[argmem_ty]], [[argmem_ty]]* %[[argmem]], i32 0, i32 1<br>
-// WIN32: invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE@XZ"<br>
-// WIN32: invoke void @"\01?TakeRef@@YAXABUA@@@Z"<br>
-//<br>
-// WIN32: invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE@XZ"(%struct.A* %[[arg1]])<br>
-// WIN32: store i1 true, i1* %[[isactive]]<br>
-//<br>
-// WIN32: %[[arg0:.*]] = getelementptr inbounds [[argmem_ty]], [[argmem_ty]]* %[[argmem]], i32 0, i32 0<br>
-// WIN32: invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE@XZ"<br>
-// WIN32: invoke void @"\01?TakeRef@@YAXABUA@@@Z"<br>
-// WIN32: invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE@XZ"<br>
-// WIN32: store i1 false, i1* %[[isactive]]<br>
-//<br>
-// WIN32: invoke i32 @"\01?TakesTwo@@YAHUA@@0@Z"([[argmem_ty]]* inalloca %[[argmem]])<br>
-// WIN32: call void @llvm.stackrestore<br>
-// Destroy the two const ref temporaries.<br>
-// WIN32: invoke x86_thiscallcc void @"\01??1A@@QAE@XZ"<br>
-// WIN32: invoke x86_thiscallcc void @"\01??1A@@QAE@XZ"<br>
-// WIN32: ret i32<br>
-//<br>
-// Conditionally destroy arg1.<br>
-// WIN32: %[[cond:.*]] = load i1, i1* %[[isactive]]<br>
-// WIN32: br i1 %[[cond]]<br>
-// WIN32: invoke x86_thiscallcc void @"\01??1A@@QAE@XZ"(%struct.A* %[[arg1]])<br>
-// WIN32: }<br>
-<br>
-// Test putting the cleanups inside a conditional.<br>
-int CouldThrow();<br>
-int HasConditionalCleanup(bool cond) {<br>
- return (cond ? TakesTwo(A(), A()) : CouldThrow());<br>
-}<br>
-<br>
-// WIN32-LABEL: define i32 @"\01?HasConditionalCleanup@@YAH_N@Z"(i1 zeroext %{{.*}}) {{.*}} {<br>
-// WIN32: store i1 false<br>
-// WIN32: br i1<br>
-// WIN32: call i8* @llvm.stacksave()<br>
-// WIN32: invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE@XZ"(%struct.A* %{{.*}})<br>
-// WIN32: store i1 true<br>
-// WIN32: invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE@XZ"(%struct.A* %{{.*}})<br>
-// WIN32: invoke i32 @"\01?TakesTwo@@YAHUA@@0@Z"<br>
-// WIN32: call void @llvm.stackrestore<br>
-//<br>
-// WIN32: call i32 @"\01?CouldThrow@@YAHXZ"()<br>
-//<br>
-// Only one dtor in the invoke for arg1<br>
-// WIN32: invoke x86_thiscallcc void @"\01??1A@@QAE@XZ"({{.*}})<br>
-// WIN32-NOT: invoke x86_thiscallcc void @"\01??1A@@QAE@XZ"<br>
-// WIN32: call void @llvm.stackrestore<br>
-// WIN32: }<br>
-<br>
-// Now test both.<br>
-int HasConditionalDeactivatedCleanups(bool cond) {<br>
- return (cond ? TakesTwo((TakeRef(A()), A()), (TakeRef(A()), A())) : CouldThrow());<br>
-}<br>
-<br>
-// WIN32-LABEL: define i32 @"\01?HasConditionalDeactivatedCleanups@@YAH_N@Z"{{.*}} {<br>
-// WIN32: alloca i1<br>
-// WIN32: %[[arg1_cond:.*]] = alloca i1<br>
-// Start all four cleanups as deactivated.<br>
-// WIN32: store i1 false<br>
-// WIN32: store i1 false<br>
-// WIN32: store i1 false<br>
-// WIN32: store i1 false<br>
-// WIN32: br i1<br>
-// True condition.<br>
-// WIN32: invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE@XZ"<br>
-// WIN32: store i1 true<br>
-// WIN32: invoke void @"\01?TakeRef@@YAXABUA@@@Z"<br>
-// WIN32: invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE@XZ"<br>
-// WIN32: store i1 true, i1* %[[arg1_cond]]<br>
-// WIN32: invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE@XZ"<br>
-// WIN32: store i1 true<br>
-// WIN32: invoke void @"\01?TakeRef@@YAXABUA@@@Z"<br>
-// WIN32: invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE@XZ"<br>
-// WIN32: store i1 true<br>
-// WIN32: store i1 false, i1* %[[arg1_cond]]<br>
-// WIN32: invoke i32 @"\01?TakesTwo@@YAHUA@@0@Z"<br>
-// False condition.<br>
-// WIN32: invoke i32 @"\01?CouldThrow@@YAHXZ"()<br>
-// Two normal cleanups for TakeRef args.<br>
-// WIN32: invoke x86_thiscallcc void @"\01??1A@@QAE@XZ"<br>
-// WIN32: invoke x86_thiscallcc void @"\01??1A@@QAE@XZ"<br>
-// WIN32: ret i32<br>
-//<br>
-// Somewhere in the landing pad soup, we conditionally destroy arg1.<br>
-// WIN32: %[[isactive:.*]] = load i1, i1* %[[arg1_cond]]<br>
-// WIN32: br i1 %[[isactive]]<br>
-// WIN32: invoke x86_thiscallcc void @"\01??1A@@QAE@XZ"<br>
-// WIN32: }<br>
-<br>
-namespace crash_on_partial_destroy {<br>
-struct A {<br>
- virtual ~A();<br>
-};<br>
-<br>
-struct B : virtual A {<br>
- // Has an implicit destructor.<br>
-};<br>
-<br>
-struct C : B {<br>
- C();<br>
-};<br>
-<br>
-void foo();<br>
-// We used to crash when emitting this.<br>
-C::C() { foo(); }<br>
-<br>
-// Verify that we don't bother with a vbtable lookup when adjusting the this<br>
-// pointer to call a base destructor from a constructor while unwinding.<br>
-// WIN32-LABEL: define {{.*}} @"\01??0C@crash_on_partial_destroy@@QAE@XZ"{{.*}} {<br>
-// WIN32: landingpad<br>
-//<br>
-// We shouldn't do any vbptr loads, just constant GEPs.<br>
-// WIN32-NOT: load<br>
-// WIN32: getelementptr i8, i8* %{{.*}}, i32 4<br>
-// WIN32-NOT: load<br>
-// WIN32: bitcast i8* %{{.*}} to %"struct.crash_on_partial_destroy::B"*<br>
-// WIN32: invoke x86_thiscallcc void @"\01??1B@crash_on_partial_destroy@@UAE@XZ"<br>
-//<br>
-// WIN32-NOT: load<br>
-// WIN32: bitcast %"struct.crash_on_partial_destroy::C"* %{{.*}} to i8*<br>
-// WIN32-NOT: load<br>
-// WIN32: getelementptr inbounds i8, i8* %{{.*}}, i64 4<br>
-// WIN32-NOT: load<br>
-// WIN32: bitcast i8* %{{.*}} to %"struct.crash_on_partial_destroy::A"*<br>
-// WIN32: invoke x86_thiscallcc void @"\01??1A@crash_on_partial_destroy@@UAE@XZ"<br>
-// WIN32: }<br>
-}<br>
<br>
Modified: cfe/trunk/test/CodeGenCXX/microsoft-abi-try-throw.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/microsoft-abi-try-throw.cpp?rev=231105&r1=231104&r2=231105&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/microsoft-abi-try-throw.cpp?rev=231105&r1=231104&r2=231105&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/test/CodeGenCXX/microsoft-abi-try-throw.cpp (original)<br>
+++ cfe/trunk/test/CodeGenCXX/microsoft-abi-try-throw.cpp Tue Mar 3 13:21:04 2015<br>
@@ -1,5 +1,4 @@<br>
-// FIXME: Disabled until catch IRgen change lands.<br>
-// RUNX: %clang_cc1 -emit-llvm %s -o - -triple=i386-pc-win32 -mconstructor-aliases -fcxx-exceptions -fexceptions -fno-rtti -DTRY | FileCheck %s -check-prefix=TRY<br>
+// RUN: %clang_cc1 -emit-llvm %s -o - -triple=i386-pc-win32 -mconstructor-aliases -fcxx-exceptions -fexceptions -fno-rtti -DTRY | FileCheck %s -check-prefix=TRY<br>
// RUN: %clang_cc1 -emit-llvm %s -o - -triple=i386-pc-win32 -mconstructor-aliases -fcxx-exceptions -fexceptions -fno-rtti -DTHROW | FileCheck %s -check-prefix=THROW<br>
<br>
void external();<br>
@@ -15,8 +14,8 @@ int main() {<br>
external(); // TRY: invoke void @"\01?external@@YAXXZ"<br>
} catch (int) {<br>
rv = 1;<br>
- // TRY: call i8* @llvm.eh.begincatch<br>
- // TRY: call void @llvm.eh.endcatch<br>
+ // TRY: call void @llvm.eh.begincatch(i8* %{{.*}}, i8* %{{.*}})<br>
+ // TRY: call void @llvm.eh.endcatch()<br>
}<br>
#endif<br>
#ifdef THROW<br>
<br>
<br>
_______________________________________________<br>
cfe-commits mailing list<br>
<a href="mailto:cfe-commits@cs.uiuc.edu">cfe-commits@cs.uiuc.edu</a><br>
<a href="http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits" target="_blank">http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits</a><br>
</blockquote></div><br></div>