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 | 3a509cd8ccdd07c6bcc3fb0dc8084f4aea5d4659 (patch) | |
| tree | dbd17917d8e1cd9b6c89a5569376e53e5766b329 /clang/lib/CodeGen/CGObjCGNU.cpp | |
| parent | 1704c4331bea9b194dafaeace0616c1c45c969de (diff) | |
| download | bcm5719-llvm-3a509cd8ccdd07c6bcc3fb0dc8084f4aea5d4659.tar.gz bcm5719-llvm-3a509cd8ccdd07c6bcc3fb0dc8084f4aea5d4659.zip | |
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.
llvm-svn: 92117
Diffstat (limited to 'clang/lib/CodeGen/CGObjCGNU.cpp')
| -rw-r--r-- | clang/lib/CodeGen/CGObjCGNU.cpp | 30 | 
1 files changed, 24 insertions, 6 deletions
| diff --git a/clang/lib/CodeGen/CGObjCGNU.cpp b/clang/lib/CodeGen/CGObjCGNU.cpp index be772c7fa31..fce0cf18db2 100644 --- a/clang/lib/CodeGen/CGObjCGNU.cpp +++ b/clang/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, | 

