[cfe-commits] r108287 - in /cfe/trunk: lib/CodeGen/CGException.cpp lib/CodeGen/CGObjCMac.cpp lib/CodeGen/CodeGenFunction.h test/CodeGenCXX/eh.cpp
John McCall
rjmccall at apple.com
Tue Jul 13 15:12:15 PDT 2010
Author: rjmccall
Date: Tue Jul 13 17:12:14 2010
New Revision: 108287
URL: http://llvm.org/viewvc/llvm-project?rev=108287&view=rev
Log:
Allow for the possibility that __cxa_end_catch might throw for a catch-all block
or a catch of a record type by value or reference. Also convert this to a
lazy cleanup.
Modified:
cfe/trunk/lib/CodeGen/CGException.cpp
cfe/trunk/lib/CodeGen/CGObjCMac.cpp
cfe/trunk/lib/CodeGen/CodeGenFunction.h
cfe/trunk/test/CodeGenCXX/eh.cpp
Modified: cfe/trunk/lib/CodeGen/CGException.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGException.cpp?rev=108287&r1=108286&r2=108287&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGException.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGException.cpp Tue Jul 13 17:12:14 2010
@@ -1020,18 +1020,45 @@
return LP;
}
+namespace {
+ /// A cleanup to call __cxa_end_catch. In many cases, the caught
+ /// exception type lets us state definitively that the thrown exception
+ /// type does not have a destructor. In particular:
+ /// - Catch-alls tell us nothing, so we have to conservatively
+ /// assume that the thrown exception might have a destructor.
+ /// - Catches by reference behave according to their base types.
+ /// - Catches of non-record types will only trigger for exceptions
+ /// of non-record types, which never have destructors.
+ /// - Catches of record types can trigger for arbitrary subclasses
+ /// of the caught type, so we have to assume the actual thrown
+ /// exception type might have a throwing destructor, even if the
+ /// caught type's destructor is trivial or nothrow.
+ struct CallEndCatch : EHScopeStack::LazyCleanup {
+ CallEndCatch(bool MightThrow) : MightThrow(MightThrow) {}
+ bool MightThrow;
+
+ void Emit(CodeGenFunction &CGF, bool IsForEH) {
+ if (!MightThrow) {
+ CGF.Builder.CreateCall(getEndCatchFn(CGF))->setDoesNotThrow();
+ return;
+ }
+
+ CGF.EmitCallOrInvoke(getEndCatchFn(CGF), 0, 0);
+ }
+ };
+}
+
/// Emits a call to __cxa_begin_catch and enters a cleanup to call
/// __cxa_end_catch.
-static llvm::Value *CallBeginCatch(CodeGenFunction &CGF, llvm::Value *Exn) {
+///
+/// \param EndMightThrow - true if __cxa_end_catch might throw
+static llvm::Value *CallBeginCatch(CodeGenFunction &CGF,
+ llvm::Value *Exn,
+ bool EndMightThrow) {
llvm::CallInst *Call = CGF.Builder.CreateCall(getBeginCatchFn(CGF), Exn);
Call->setDoesNotThrow();
- {
- CodeGenFunction::CleanupBlock EndCatchCleanup(CGF, NormalAndEHCleanup);
-
- // __cxa_end_catch never throws, so this can just be a call.
- CGF.Builder.CreateCall(getEndCatchFn(CGF))->setDoesNotThrow();
- }
+ CGF.EHStack.pushLazyCleanup<CallEndCatch>(NormalAndEHCleanup, EndMightThrow);
return Call;
}
@@ -1051,8 +1078,11 @@
// If we're catching by reference, we can just cast the object
// pointer to the appropriate pointer.
if (isa<ReferenceType>(CatchType)) {
+ bool EndCatchMightThrow = cast<ReferenceType>(CatchType)->getPointeeType()
+ ->isRecordType();
+
// __cxa_begin_catch returns the adjusted object pointer.
- llvm::Value *AdjustedExn = CallBeginCatch(CGF, Exn);
+ llvm::Value *AdjustedExn = CallBeginCatch(CGF, Exn, EndCatchMightThrow);
llvm::Value *ExnCast =
CGF.Builder.CreateBitCast(AdjustedExn, LLVMCatchTy, "exn.byref");
CGF.Builder.CreateStore(ExnCast, ParamAddr);
@@ -1063,7 +1093,7 @@
bool IsComplex = false;
if (!CGF.hasAggregateLLVMType(CatchType) ||
(IsComplex = CatchType->isAnyComplexType())) {
- llvm::Value *AdjustedExn = CallBeginCatch(CGF, Exn);
+ llvm::Value *AdjustedExn = CallBeginCatch(CGF, Exn, false);
// If the catch type is a pointer type, __cxa_begin_catch returns
// the pointer by value.
@@ -1098,7 +1128,7 @@
const llvm::Type *PtrTy = LLVMCatchTy->getPointerTo(0); // addrspace 0 ok
if (RD->hasTrivialCopyConstructor()) {
- llvm::Value *AdjustedExn = CallBeginCatch(CGF, Exn);
+ llvm::Value *AdjustedExn = CallBeginCatch(CGF, Exn, true);
llvm::Value *Cast = CGF.Builder.CreateBitCast(AdjustedExn, PtrTy);
CGF.EmitAggregateCopy(ParamAddr, Cast, CatchType);
return;
@@ -1131,7 +1161,7 @@
CGF.EHStack.popTerminate();
// Finally we can call __cxa_begin_catch.
- CallBeginCatch(CGF, Exn);
+ CallBeginCatch(CGF, Exn, true);
}
/// Begins a catch statement by initializing the catch variable and
@@ -1164,7 +1194,7 @@
VarDecl *CatchParam = S->getExceptionDecl();
if (!CatchParam) {
llvm::Value *Exn = CGF.Builder.CreateLoad(CGF.getExceptionSlot(), "exn");
- CallBeginCatch(CGF, Exn);
+ CallBeginCatch(CGF, Exn, true);
return;
}
@@ -1298,7 +1328,7 @@
Builder.CreateLoad(ForEHVar, "finally.endcatch");
Builder.CreateCondBr(ShouldEndCatch, EndCatchBB, CleanupContBB);
EmitBlock(EndCatchBB);
- Builder.CreateCall(EndCatchFn)->setDoesNotThrow();
+ EmitCallOrInvoke(EndCatchFn, 0, 0); // catch-all, so might throw
EmitBlock(CleanupContBB);
}
Modified: cfe/trunk/lib/CodeGen/CGObjCMac.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGObjCMac.cpp?rev=108287&r1=108286&r2=108287&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGObjCMac.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGObjCMac.cpp Tue Jul 13 17:12:14 2010
@@ -32,6 +32,7 @@
#include "llvm/ADT/SetVector.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/Support/CallSite.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Target/TargetData.h"
#include <cstdio>
@@ -5712,6 +5713,22 @@
llvm::BasicBlock *Block;
llvm::Value *TypeInfo;
};
+
+ struct CallObjCEndCatch : EHScopeStack::LazyCleanup {
+ CallObjCEndCatch(bool MightThrow, llvm::Value *Fn) :
+ MightThrow(MightThrow), Fn(Fn) {}
+ bool MightThrow;
+ llvm::Value *Fn;
+
+ void Emit(CodeGenFunction &CGF, bool IsForEH) {
+ if (!MightThrow) {
+ CGF.Builder.CreateCall(Fn)->setDoesNotThrow();
+ return;
+ }
+
+ CGF.EmitCallOrInvoke(Fn, 0, 0);
+ }
+ };
}
void CGObjCNonFragileABIMac::EmitTryStmt(CodeGen::CodeGenFunction &CGF,
@@ -5801,13 +5818,10 @@
Exn->setDoesNotThrow();
// Add a cleanup to leave the catch.
- {
- CodeGenFunction::CleanupBlock EndCatchBlock(CGF, NormalAndEHCleanup);
-
- // __objc_end_catch never throws.
- CGF.Builder.CreateCall(ObjCTypes.getObjCEndCatchFn())
- ->setDoesNotThrow();
- }
+ bool EndCatchMightThrow = (Handler.Variable == 0);
+ CGF.EHStack.pushLazyCleanup<CallObjCEndCatch>(NormalAndEHCleanup,
+ EndCatchMightThrow,
+ ObjCTypes.getObjCEndCatchFn());
// Bind the catch parameter if it exists.
if (const VarDecl *CatchParam = Handler.Variable) {
Modified: cfe/trunk/lib/CodeGen/CodeGenFunction.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenFunction.h?rev=108287&r1=108286&r2=108287&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CodeGenFunction.h (original)
+++ cfe/trunk/lib/CodeGen/CodeGenFunction.h Tue Jul 13 17:12:14 2010
@@ -207,6 +207,22 @@
// Variadic templates would make this not terrible.
/// Push a lazily-created cleanup on the stack.
+ template <class T>
+ void pushLazyCleanup(CleanupKind Kind) {
+ void *Buffer = pushLazyCleanup(Kind, sizeof(T));
+ LazyCleanup *Obj = new(Buffer) T();
+ (void) Obj;
+ }
+
+ /// Push a lazily-created cleanup on the stack.
+ template <class T, class A0>
+ void pushLazyCleanup(CleanupKind Kind, A0 a0) {
+ void *Buffer = pushLazyCleanup(Kind, sizeof(T));
+ LazyCleanup *Obj = new(Buffer) T(a0);
+ (void) Obj;
+ }
+
+ /// Push a lazily-created cleanup on the stack.
template <class T, class A0, class A1>
void pushLazyCleanup(CleanupKind Kind, A0 a0, A1 a1) {
void *Buffer = pushLazyCleanup(Kind, sizeof(T));
Modified: cfe/trunk/test/CodeGenCXX/eh.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/eh.cpp?rev=108287&r1=108286&r2=108287&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/eh.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/eh.cpp Tue Jul 13 17:12:14 2010
@@ -181,11 +181,7 @@
// CHECK-NEXT: invoke void @_ZN5test81AC1ERKS0_(
// CHECK: call i8* @__cxa_begin_catch
// CHECK-NEXT: invoke void @_ZN5test81AD1Ev(
-
// CHECK: call void @__cxa_end_catch()
- // CHECK-NEXT: load
- // CHECK-NEXT: switch
-
// CHECK: ret void
}
}
@@ -217,3 +213,39 @@
// CHECK: call i8* @llvm.eh.exception
// CHECK: call i32 (i8*, i8*, ...)* @llvm.eh.selector(i8* {{.*}}, i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*), i8* bitcast (i8** @_ZTIi to i8*), i8* null)
}
+
+// __cxa_end_catch can throw for some kinds of caught exceptions.
+namespace test10 {
+ void opaque();
+
+ struct A { ~A(); };
+ struct B { int x; };
+
+ // CHECK: define void @_ZN6test103fooEv()
+ void foo() {
+ A a; // force a cleanup context
+
+ try {
+ // CHECK: invoke void @_ZN6test106opaqueEv()
+ opaque();
+ } catch (int i) {
+ // CHECK: call i8* @__cxa_begin_catch
+ // CHECK-NEXT: bitcast
+ // CHECK-NEXT: load i32*
+ // CHECK-NEXT: store i32
+ // CHECK-NEXT: call void @__cxa_end_catch() nounwind
+ } catch (B a) {
+ // CHECK: call i8* @__cxa_begin_catch
+ // CHECK-NEXT: bitcast
+ // CHECK-NEXT: bitcast
+ // CHECK-NEXT: bitcast
+ // CHECK-NEXT: call void @llvm.memcpy
+ // CHECK-NEXT: invoke void @__cxa_end_catch()
+ } catch (...) {
+ // CHECK: call i8* @__cxa_begin_catch
+ // CHECK-NEXT: invoke void @__cxa_end_catch()
+ }
+
+ // CHECK: call void @_ZN6test101AD1Ev(
+ }
+}
More information about the cfe-commits
mailing list