diff options
author | David Chisnall <csdavec@swan.ac.uk> | 2009-12-24 02:26:34 +0000 |
---|---|---|
committer | David Chisnall <csdavec@swan.ac.uk> | 2009-12-24 02:26:34 +0000 |
commit | 0faa51632584b8d56311d5792a2a275729bc67e3 (patch) | |
tree | 2e279a25aaabb41c43876aa6278bbbb076a345b7 | |
parent | 598278bee8e5797bc73d24d6ac8a1d6ff6413cae (diff) |
Fix for bug 5691.
This fixes throwing exceptions inside @catch blocks nested inside outer @try blocks and also fixes jumping from an inner @finally to an outer @finally (via any relevant @catch blocks).
The code exhibiting this bug was based on code from CGObjCMac. I believe that this bug may still be present on the Mac runtimes, although the test case in the bug contains a few GNUisms and won't compile without some minor tweaks with Apple's libobjc.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@92117 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | lib/CodeGen/CGObjCGNU.cpp | 30 |
1 files changed, 24 insertions, 6 deletions
diff --git a/lib/CodeGen/CGObjCGNU.cpp b/lib/CodeGen/CGObjCGNU.cpp index be772c7fa3..fce0cf18db 100644 --- a/lib/CodeGen/CGObjCGNU.cpp +++ b/lib/CodeGen/CGObjCGNU.cpp @@ -1607,7 +1607,7 @@ void CGObjCGNU::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF, Params.push_back(PtrTy); llvm::Value *RethrowFn = CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext), - Params, false), "_Unwind_Resume_or_Rethrow"); + Params, false), "objc_exception_throw"); bool isTry = isa<ObjCAtTryStmt>(S); llvm::BasicBlock *TryBlock = CGF.createBasicBlock("try"); @@ -1618,7 +1618,7 @@ void CGObjCGNU::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF, llvm::BasicBlock *FinallyRethrow = CGF.createBasicBlock("finally.throw"); llvm::BasicBlock *FinallyEnd = CGF.createBasicBlock("finally.end"); - // GNU runtime does not currently support @synchronized() + // @synchronized() if (!isTry) { std::vector<const llvm::Type*> Args(1, IdTy); llvm::FunctionType *FTy = @@ -1770,7 +1770,13 @@ void CGObjCGNU::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF, ESelArgs.clear(); ESelArgs.push_back(Exc); ESelArgs.push_back(Personality); - ESelArgs.push_back(llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), 0)); + // If there is a @catch or @finally clause in outside of this one then we + // need to make sure that we catch and rethrow it. + if (PrevLandingPad) { + ESelArgs.push_back(NULLPtr); + } else { + ESelArgs.push_back(llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), 0)); + } CGF.Builder.CreateCall(llvm_eh_selector, ESelArgs.begin(), ESelArgs.end(), "selector"); CGF.Builder.CreateCall(llvm_eh_typeid_for, @@ -1811,11 +1817,23 @@ void CGObjCGNU::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF, CGF.EmitBranch(FinallyEnd); CGF.EmitBlock(FinallyRethrow); - CGF.Builder.CreateCall(RethrowFn, CGF.Builder.CreateLoad(RethrowPtr)); - CGF.Builder.CreateUnreachable(); - CGF.EmitBlock(FinallyEnd); + llvm::Value *ExceptionObject = CGF.Builder.CreateLoad(RethrowPtr); + llvm::BasicBlock *UnwindBB = CGF.getInvokeDest(); + if (!UnwindBB) { + CGF.Builder.CreateCall(RethrowFn, ExceptionObject); + // Exception always thrown, next instruction is never reached. + CGF.Builder.CreateUnreachable(); + } else { + // If there is a @catch block outside this scope, we invoke instead of + // calling because we may return to this function. This is very slow, but + // some people still do it. It would be nice to add an optimised path for + // this. + CGF.Builder.CreateInvoke(RethrowFn, UnwindBB, UnwindBB, &ExceptionObject, + &ExceptionObject+1); + } + CGF.EmitBlock(FinallyEnd); } void CGObjCGNU::EmitThrowStmt(CodeGen::CodeGenFunction &CGF, |