[cfe-commits] r108944 - in /cfe/trunk: lib/CodeGen/CGException.cpp lib/CodeGen/TargetInfo.h test/CodeGenCXX/eh.cpp
John McCall
rjmccall at apple.com
Tue Jul 20 15:17:55 PDT 2010
Author: rjmccall
Date: Tue Jul 20 17:17:55 2010
New Revision: 108944
URL: http://llvm.org/viewvc/llvm-project?rev=108944&view=rev
Log:
Fix the IR generation for catching pointers by references.
Fixes <rdar://problem/8212123>.
Modified:
cfe/trunk/lib/CodeGen/CGException.cpp
cfe/trunk/lib/CodeGen/TargetInfo.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=108944&r1=108943&r2=108944&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGException.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGException.cpp Tue Jul 20 17:17:55 2010
@@ -18,6 +18,7 @@
#include "CodeGenFunction.h"
#include "CGException.h"
+#include "TargetInfo.h"
using namespace clang;
using namespace CodeGen;
@@ -1099,11 +1100,57 @@
// 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();
+ QualType CaughtType = cast<ReferenceType>(CatchType)->getPointeeType();
+ bool EndCatchMightThrow = CaughtType->isRecordType();
// __cxa_begin_catch returns the adjusted object pointer.
llvm::Value *AdjustedExn = CallBeginCatch(CGF, Exn, EndCatchMightThrow);
+
+ // We have no way to tell the personality function that we're
+ // catching by reference, so if we're catching a pointer,
+ // __cxa_begin_catch will actually return that pointer by value.
+ if (const PointerType *PT = dyn_cast<PointerType>(CaughtType)) {
+ QualType PointeeType = PT->getPointeeType();
+
+ // When catching by reference, generally we should just ignore
+ // this by-value pointer and use the exception object instead.
+ if (!PointeeType->isRecordType()) {
+
+ // Exn points to the struct _Unwind_Exception header, which
+ // we have to skip past in order to reach the exception data.
+ unsigned HeaderSize =
+ CGF.CGM.getTargetCodeGenInfo().getSizeOfUnwindException();
+ AdjustedExn = CGF.Builder.CreateConstGEP1_32(Exn, HeaderSize);
+
+ // However, if we're catching a pointer-to-record type that won't
+ // work, because the personality function might have adjusted
+ // the pointer. There's actually no way for us to fully satisfy
+ // the language/ABI contract here: we can't use Exn because it
+ // might have the wrong adjustment, but we can't use the by-value
+ // pointer because it's off by a level of abstraction.
+ //
+ // The current solution is to dump the adjusted pointer into an
+ // alloca, which breaks language semantics (because changing the
+ // pointer doesn't change the exception) but at least works.
+ // The better solution would be to filter out non-exact matches
+ // and rethrow them, but this is tricky because the rethrow
+ // really needs to be catchable by other sites at this landing
+ // pad. The best solution is to fix the personality function.
+ } else {
+ // Pull the pointer for the reference type off.
+ const llvm::Type *PtrTy =
+ cast<llvm::PointerType>(LLVMCatchTy)->getElementType();
+
+ // Create the temporary and write the adjusted pointer into it.
+ llvm::Value *ExnPtrTmp = CGF.CreateTempAlloca(PtrTy, "exn.byref.tmp");
+ llvm::Value *Casted = CGF.Builder.CreateBitCast(AdjustedExn, PtrTy);
+ CGF.Builder.CreateStore(Casted, ExnPtrTmp);
+
+ // Bind the reference to the temporary.
+ AdjustedExn = ExnPtrTmp;
+ }
+ }
+
llvm::Value *ExnCast =
CGF.Builder.CreateBitCast(AdjustedExn, LLVMCatchTy, "exn.byref");
CGF.Builder.CreateStore(ExnCast, ParamAddr);
Modified: cfe/trunk/lib/CodeGen/TargetInfo.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/TargetInfo.h?rev=108944&r1=108943&r2=108944&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/TargetInfo.h (original)
+++ cfe/trunk/lib/CodeGen/TargetInfo.h Tue Jul 20 17:17:55 2010
@@ -47,6 +47,16 @@
virtual void SetTargetAttributes(const Decl *D, llvm::GlobalValue *GV,
CodeGen::CodeGenModule &M) const { }
+ /// Determines the size of struct _Unwind_Exception on this platform,
+ /// in 8-bit units. The Itanium ABI defines this as:
+ /// struct _Unwind_Exception {
+ /// uint64 exception_class;
+ /// _Unwind_Exception_Cleanup_Fn exception_cleanup;
+ /// uint64 private_1;
+ /// uint64 private_2;
+ /// };
+ unsigned getSizeOfUnwindException() const { return 32; }
+
/// Controls whether __builtin_extend_pointer should sign-extend
/// pointers to uint64_t or zero-extend them (the default). Has
/// no effect for targets:
Modified: cfe/trunk/test/CodeGenCXX/eh.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/eh.cpp?rev=108944&r1=108943&r2=108944&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/eh.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/eh.cpp Tue Jul 20 17:17:55 2010
@@ -249,3 +249,44 @@
// CHECK: call void @_ZN6test101AD1Ev(
}
}
+
+// __cxa_begin_catch returns pointers by value, even when catching by reference
+// <rdar://problem/8212123>
+namespace test11 {
+ void opaque();
+
+ // CHECK: define void @_ZN6test113fooEv()
+ void foo() {
+ try {
+ // CHECK: invoke void @_ZN6test116opaqueEv()
+ opaque();
+ } catch (int**&p) {
+ // CHECK: [[EXN:%.*]] = load i8**
+ // CHECK-NEXT: call i8* @__cxa_begin_catch(i8* [[EXN]]) nounwind
+ // CHECK-NEXT: [[ADJ1:%.*]] = getelementptr i8* [[EXN]], i32 32
+ // CHECK-NEXT: [[ADJ2:%.*]] = bitcast i8* [[ADJ1]] to i32***
+ // CHECK-NEXT: store i32*** [[ADJ2]], i32**** [[P:%.*]]
+ // CHECK-NEXT: call void @__cxa_end_catch() nounwind
+ }
+ }
+
+ struct A {};
+
+ // CHECK: define void @_ZN6test113barEv()
+ void bar() {
+ try {
+ // CHECK: [[EXNSLOT:%.*]] = alloca i8*
+ // CHECK-NEXT: [[P:%.*]] = alloca [[A:%.*]]**,
+ // CHECK-NEXT: [[TMP:%.*]] = alloca [[A]]*
+ // CHECK-NEXT: invoke void @_ZN6test116opaqueEv()
+ opaque();
+ } catch (A*&p) {
+ // CHECK: [[EXN:%.*]] = load i8** [[EXNSLOT]]
+ // CHECK-NEXT: [[ADJ1:%.*]] = call i8* @__cxa_begin_catch(i8* [[EXN]]) nounwind
+ // CHECK-NEXT: [[ADJ2:%.*]] = bitcast i8* [[ADJ1]] to [[A]]*
+ // CHECK-NEXT: store [[A]]* [[ADJ2]], [[A]]** [[TMP]]
+ // CHECK-NEXT: store [[A]]** [[TMP]], [[A]]*** [[P]]
+ // CHECK-NEXT: call void @__cxa_end_catch() nounwind
+ }
+ }
+}
More information about the cfe-commits
mailing list