aboutsummaryrefslogtreecommitdiff
path: root/lib/CodeGen/CGException.cpp
diff options
context:
space:
mode:
authorRoman Divacky <rdivacky@FreeBSD.org>2010-05-04 16:12:48 +0000
committerRoman Divacky <rdivacky@FreeBSD.org>2010-05-04 16:12:48 +0000
commit0883ccd9eac3b974df00e6548ee319a7dd3646f4 (patch)
treed6a70c3518b8dea8be7062438d7e8676820ed17f /lib/CodeGen/CGException.cpp
parent60bfabcd8ce617297c0d231f77d14ab507e98796 (diff)
downloadsrc-0883ccd9eac3b974df00e6548ee319a7dd3646f4.tar.gz
src-0883ccd9eac3b974df00e6548ee319a7dd3646f4.zip
Update clang to r103004.
Notes
Notes: svn path=/vendor/clang/dist/; revision=207619
Diffstat (limited to 'lib/CodeGen/CGException.cpp')
-rw-r--r--lib/CodeGen/CGException.cpp235
1 files changed, 120 insertions, 115 deletions
diff --git a/lib/CodeGen/CGException.cpp b/lib/CodeGen/CGException.cpp
index 1e1506683ddd..c1d05bf233b2 100644
--- a/lib/CodeGen/CGException.cpp
+++ b/lib/CodeGen/CGException.cpp
@@ -122,82 +122,71 @@ static llvm::Constant *getTerminateFn(CodeGenFunction &CGF) {
return CGF.CGM.CreateRuntimeFunction(FTy, "_ZSt9terminatev");
}
-// CopyObject - Utility to copy an object. Calls copy constructor as necessary.
-// DestPtr is casted to the right type.
-static void CopyObject(CodeGenFunction &CGF, const Expr *E,
- llvm::Value *DestPtr, llvm::Value *ExceptionPtrPtr) {
- QualType ObjectType = E->getType();
-
- // Store the throw exception in the exception object.
- if (!CGF.hasAggregateLLVMType(ObjectType)) {
- llvm::Value *Value = CGF.EmitScalarExpr(E);
- const llvm::Type *ValuePtrTy = Value->getType()->getPointerTo();
-
- CGF.Builder.CreateStore(Value,
- CGF.Builder.CreateBitCast(DestPtr, ValuePtrTy));
- } else {
- const llvm::Type *Ty = CGF.ConvertType(ObjectType)->getPointerTo();
- const CXXRecordDecl *RD =
- cast<CXXRecordDecl>(ObjectType->getAs<RecordType>()->getDecl());
-
- llvm::Value *This = CGF.Builder.CreateBitCast(DestPtr, Ty);
- if (RD->hasTrivialCopyConstructor()) {
- CGF.EmitAggExpr(E, This, false);
- } else if (CXXConstructorDecl *CopyCtor
- = RD->getCopyConstructor(CGF.getContext(), 0)) {
- llvm::Value *CondPtr = 0;
- if (CGF.Exceptions) {
- CodeGenFunction::EHCleanupBlock Cleanup(CGF);
- llvm::Constant *FreeExceptionFn = getFreeExceptionFn(CGF);
-
- llvm::BasicBlock *CondBlock = CGF.createBasicBlock("cond.free");
- llvm::BasicBlock *Cont = CGF.createBasicBlock("cont");
- CondPtr = CGF.CreateTempAlloca(llvm::Type::getInt1Ty(CGF.getLLVMContext()),
- "doEHfree");
-
- CGF.Builder.CreateCondBr(CGF.Builder.CreateLoad(CondPtr),
- CondBlock, Cont);
- CGF.EmitBlock(CondBlock);
-
- // Load the exception pointer.
- llvm::Value *ExceptionPtr = CGF.Builder.CreateLoad(ExceptionPtrPtr);
- CGF.Builder.CreateCall(FreeExceptionFn, ExceptionPtr);
-
- CGF.EmitBlock(Cont);
- }
-
- if (CondPtr)
- CGF.Builder.CreateStore(llvm::ConstantInt::getTrue(CGF.getLLVMContext()),
- CondPtr);
-
- llvm::Value *Src = CGF.EmitLValue(E).getAddress();
-
- if (CondPtr)
- CGF.Builder.CreateStore(llvm::ConstantInt::getFalse(CGF.getLLVMContext()),
- CondPtr);
-
- llvm::BasicBlock *TerminateHandler = CGF.getTerminateHandler();
- llvm::BasicBlock *PrevLandingPad = CGF.getInvokeDest();
- CGF.setInvokeDest(TerminateHandler);
-
- // Stolen from EmitClassAggrMemberwiseCopy
- llvm::Value *Callee = CGF.CGM.GetAddrOfCXXConstructor(CopyCtor,
- Ctor_Complete);
- CallArgList CallArgs;
- CallArgs.push_back(std::make_pair(RValue::get(This),
- CopyCtor->getThisType(CGF.getContext())));
-
- // Push the Src ptr.
- CallArgs.push_back(std::make_pair(RValue::get(Src),
- CopyCtor->getParamDecl(0)->getType()));
- const FunctionProtoType *FPT
- = CopyCtor->getType()->getAs<FunctionProtoType>();
- CGF.EmitCall(CGF.CGM.getTypes().getFunctionInfo(CallArgs, FPT),
- Callee, ReturnValueSlot(), CallArgs, CopyCtor);
- CGF.setInvokeDest(PrevLandingPad);
- } else
- llvm_unreachable("uncopyable object");
+// Emits an exception expression into the given location. This
+// differs from EmitAnyExprToMem only in that, if a final copy-ctor
+// call is required, an exception within that copy ctor causes
+// std::terminate to be invoked.
+static void EmitAnyExprToExn(CodeGenFunction &CGF, const Expr *E,
+ llvm::Value *ExnLoc) {
+ // We want to release the allocated exception object if this
+ // expression throws. We do this by pushing an EH-only cleanup
+ // block which, furthermore, deactivates itself after the expression
+ // is complete.
+ llvm::AllocaInst *ShouldFreeVar =
+ CGF.CreateTempAlloca(llvm::Type::getInt1Ty(CGF.getLLVMContext()),
+ "should-free-exnobj.var");
+ CGF.InitTempAlloca(ShouldFreeVar,
+ llvm::ConstantInt::getFalse(CGF.getLLVMContext()));
+
+ // A variable holding the exception pointer. This is necessary
+ // because the throw expression does not necessarily dominate the
+ // cleanup, for example if it appears in a conditional expression.
+ llvm::AllocaInst *ExnLocVar =
+ CGF.CreateTempAlloca(ExnLoc->getType(), "exnobj.var");
+
+ llvm::BasicBlock *SavedInvokeDest = CGF.getInvokeDest();
+ {
+ CodeGenFunction::EHCleanupBlock Cleanup(CGF);
+ llvm::BasicBlock *FreeBB = CGF.createBasicBlock("free-exnobj");
+ llvm::BasicBlock *DoneBB = CGF.createBasicBlock("free-exnobj.done");
+
+ llvm::Value *ShouldFree = CGF.Builder.CreateLoad(ShouldFreeVar,
+ "should-free-exnobj");
+ CGF.Builder.CreateCondBr(ShouldFree, FreeBB, DoneBB);
+ CGF.EmitBlock(FreeBB);
+ llvm::Value *ExnLocLocal = CGF.Builder.CreateLoad(ExnLocVar, "exnobj");
+ CGF.Builder.CreateCall(getFreeExceptionFn(CGF), ExnLocLocal);
+ CGF.EmitBlock(DoneBB);
}
+ llvm::BasicBlock *Cleanup = CGF.getInvokeDest();
+
+ CGF.Builder.CreateStore(ExnLoc, ExnLocVar);
+ CGF.Builder.CreateStore(llvm::ConstantInt::getTrue(CGF.getLLVMContext()),
+ ShouldFreeVar);
+
+ // __cxa_allocate_exception returns a void*; we need to cast this
+ // to the appropriate type for the object.
+ const llvm::Type *Ty = CGF.ConvertType(E->getType())->getPointerTo();
+ llvm::Value *TypedExnLoc = CGF.Builder.CreateBitCast(ExnLoc, Ty);
+
+ // FIXME: this isn't quite right! If there's a final unelided call
+ // to a copy constructor, then according to [except.terminate]p1 we
+ // must call std::terminate() if that constructor throws, because
+ // technically that copy occurs after the exception expression is
+ // evaluated but before the exception is caught. But the best way
+ // to handle that is to teach EmitAggExpr to do the final copy
+ // differently if it can't be elided.
+ CGF.EmitAnyExprToMem(E, TypedExnLoc, /*Volatile*/ false);
+
+ CGF.Builder.CreateStore(llvm::ConstantInt::getFalse(CGF.getLLVMContext()),
+ ShouldFreeVar);
+
+ // Pop the cleanup block if it's still the top of the cleanup stack.
+ // Otherwise, temporaries have been created and our cleanup will get
+ // properly removed in time.
+ // TODO: this is not very resilient.
+ if (CGF.getInvokeDest() == Cleanup)
+ CGF.setInvokeDest(SavedInvokeDest);
}
// CopyObject - Utility to copy an object. Calls copy constructor as necessary.
@@ -270,7 +259,7 @@ void CodeGenFunction::EmitCXXThrowExpr(const CXXThrowExpr *E) {
// Now allocate the exception object.
const llvm::Type *SizeTy = ConvertType(getContext().getSizeType());
- uint64_t TypeSize = getContext().getTypeSize(ThrowType) / 8;
+ uint64_t TypeSize = getContext().getTypeSizeInChars(ThrowType).getQuantity();
llvm::Constant *AllocExceptionFn = getAllocateExceptionFn(*this);
llvm::Value *ExceptionPtr =
@@ -278,17 +267,24 @@ void CodeGenFunction::EmitCXXThrowExpr(const CXXThrowExpr *E) {
llvm::ConstantInt::get(SizeTy, TypeSize),
"exception");
- llvm::Value *ExceptionPtrPtr =
- CreateTempAlloca(ExceptionPtr->getType(), "exception.ptr");
- Builder.CreateStore(ExceptionPtr, ExceptionPtrPtr);
-
-
- CopyObject(*this, E->getSubExpr(), ExceptionPtr, ExceptionPtrPtr);
+ EmitAnyExprToExn(*this, E->getSubExpr(), ExceptionPtr);
// Now throw the exception.
const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(getLLVMContext());
- llvm::Constant *TypeInfo = CGM.GetAddrOfRTTIDescriptor(ThrowType);
- llvm::Constant *Dtor = llvm::Constant::getNullValue(Int8PtrTy);
+ llvm::Constant *TypeInfo = CGM.GetAddrOfRTTIDescriptor(ThrowType, true);
+
+ // The address of the destructor. If the exception type has a
+ // trivial destructor (or isn't a record), we just pass null.
+ llvm::Constant *Dtor = 0;
+ if (const RecordType *RecordTy = ThrowType->getAs<RecordType>()) {
+ CXXRecordDecl *Record = cast<CXXRecordDecl>(RecordTy->getDecl());
+ if (!Record->hasTrivialDestructor()) {
+ CXXDestructorDecl *DtorD = Record->getDestructor(getContext());
+ Dtor = CGM.GetAddrOfCXXDestructor(DtorD, Dtor_Complete);
+ Dtor = llvm::ConstantExpr::getBitCast(Dtor, Int8PtrTy);
+ }
+ }
+ if (!Dtor) Dtor = llvm::Constant::getNullValue(Int8PtrTy);
if (getInvokeDest()) {
llvm::BasicBlock *Cont = createBasicBlock("invoke.cont");
@@ -375,7 +371,7 @@ void CodeGenFunction::EmitStartEHSpec(const Decl *D) {
QualType Ty = Proto->getExceptionType(i);
QualType ExceptType
= Ty.getNonReferenceType().getUnqualifiedType();
- llvm::Value *EHType = CGM.GetAddrOfRTTIDescriptor(ExceptType);
+ llvm::Value *EHType = CGM.GetAddrOfRTTIDescriptor(ExceptType, true);
SelectorArgs.push_back(EHType);
}
if (Proto->getNumExceptions())
@@ -498,7 +494,7 @@ void CodeGenFunction::ExitCXXTryStmt(const CXXTryStmt &S,
// are ignored.
QualType CaughtType = C->getCaughtType().getNonReferenceType();
llvm::Value *EHTypeInfo
- = CGM.GetAddrOfRTTIDescriptor(CaughtType.getUnqualifiedType());
+ = CGM.GetAddrOfRTTIDescriptor(CaughtType.getUnqualifiedType(), true);
SelectorArgs.push_back(EHTypeInfo);
} else {
// null indicates catch all
@@ -649,38 +645,46 @@ void CodeGenFunction::ExitCXXTryStmt(const CXXTryStmt &S,
}
CodeGenFunction::EHCleanupBlock::~EHCleanupBlock() {
- llvm::BasicBlock *Cont1 = CGF.createBasicBlock("cont");
- CGF.EmitBranch(Cont1);
CGF.setInvokeDest(PreviousInvokeDest);
+ llvm::BasicBlock *EndOfCleanup = CGF.Builder.GetInsertBlock();
- CGF.EmitBlock(CleanupHandler);
-
+ // Jump to the beginning of the cleanup.
+ CGF.Builder.SetInsertPoint(CleanupHandler, CleanupHandler->begin());
+
+ // The libstdc++ personality function.
+ // TODO: generalize to work with other libraries.
llvm::Constant *Personality =
CGF.CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::getInt32Ty
(CGF.VMContext),
true),
"__gxx_personality_v0");
Personality = llvm::ConstantExpr::getBitCast(Personality, CGF.PtrToInt8Ty);
+
+ // %exception = call i8* @llvm.eh.exception()
+ // Magic intrinsic which tells gives us a handle to the caught
+ // exception.
llvm::Value *llvm_eh_exception =
CGF.CGM.getIntrinsic(llvm::Intrinsic::eh_exception);
- llvm::Value *llvm_eh_selector =
- CGF.CGM.getIntrinsic(llvm::Intrinsic::eh_selector);
-
llvm::Value *Exc = CGF.Builder.CreateCall(llvm_eh_exception, "exc");
- const llvm::IntegerType *Int8Ty;
- const llvm::PointerType *PtrToInt8Ty;
- Int8Ty = llvm::Type::getInt8Ty(CGF.VMContext);
- // C string type. Used in lots of places.
- PtrToInt8Ty = llvm::PointerType::getUnqual(Int8Ty);
- llvm::Constant *Null = llvm::ConstantPointerNull::get(PtrToInt8Ty);
+
+ llvm::Constant *Null = llvm::ConstantPointerNull::get(CGF.PtrToInt8Ty);
+
+ // %ignored = call i32 @llvm.eh.selector(i8* %exception,
+ // i8* @__gxx_personality_v0,
+ // i8* null)
+ // Magic intrinsic which tells LLVM that this invoke landing pad is
+ // just a cleanup block.
llvm::Value *Args[] = { Exc, Personality, Null };
+ llvm::Value *llvm_eh_selector =
+ CGF.CGM.getIntrinsic(llvm::Intrinsic::eh_selector);
CGF.Builder.CreateCall(llvm_eh_selector, &Args[0], llvm::array_endof(Args));
- CGF.EmitBlock(CleanupEntryBB);
-
- CGF.EmitBlock(Cont1);
+ // And then we fall through into the code that the user put there.
+ // Jump back to the end of the cleanup.
+ CGF.Builder.SetInsertPoint(EndOfCleanup);
+ // Rethrow the exception.
if (CGF.getInvokeDest()) {
llvm::BasicBlock *Cont = CGF.createBasicBlock("invoke.cont");
CGF.Builder.CreateInvoke(getUnwindResumeOrRethrowFn(CGF), Cont,
@@ -688,10 +692,15 @@ CodeGenFunction::EHCleanupBlock::~EHCleanupBlock() {
CGF.EmitBlock(Cont);
} else
CGF.Builder.CreateCall(getUnwindResumeOrRethrowFn(CGF), Exc);
-
CGF.Builder.CreateUnreachable();
- CGF.EmitBlock(Cont);
+ // Resume inserting where we started, but put the new cleanup
+ // handler in place.
+ if (PreviousInsertionBlock)
+ CGF.Builder.SetInsertPoint(PreviousInsertionBlock);
+ else
+ CGF.Builder.ClearInsertionPoint();
+
if (CGF.Exceptions)
CGF.setInvokeDest(CleanupHandler);
}
@@ -700,12 +709,11 @@ llvm::BasicBlock *CodeGenFunction::getTerminateHandler() {
if (TerminateHandler)
return TerminateHandler;
- llvm::BasicBlock *Cont = 0;
-
- if (HaveInsertPoint()) {
- Cont = createBasicBlock("cont");
- EmitBranch(Cont);
- }
+ // We don't want to change anything at the current location, so
+ // save it aside and clear the insert point.
+ llvm::BasicBlock *SavedInsertBlock = Builder.GetInsertBlock();
+ llvm::BasicBlock::iterator SavedInsertPoint = Builder.GetInsertPoint();
+ Builder.ClearInsertionPoint();
llvm::Constant *Personality =
CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::getInt32Ty
@@ -735,11 +743,8 @@ llvm::BasicBlock *CodeGenFunction::getTerminateHandler() {
TerminateCall->setDoesNotThrow();
Builder.CreateUnreachable();
- // Clear the insertion point to indicate we are in unreachable code.
- Builder.ClearInsertionPoint();
-
- if (Cont)
- EmitBlock(Cont);
+ // Restore the saved insertion state.
+ Builder.SetInsertPoint(SavedInsertBlock, SavedInsertPoint);
return TerminateHandler;
}