diff options
Diffstat (limited to 'contrib/llvm/tools/clang/lib/CodeGen/CGException.cpp')
-rw-r--r-- | contrib/llvm/tools/clang/lib/CodeGen/CGException.cpp | 442 |
1 files changed, 162 insertions, 280 deletions
diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGException.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGException.cpp index 7fb616e5..6181965 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGException.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGException.cpp @@ -14,163 +14,18 @@ #include "clang/AST/StmtCXX.h" #include "llvm/Intrinsics.h" +#include "llvm/IntrinsicInst.h" #include "llvm/Support/CallSite.h" #include "CGObjCRuntime.h" #include "CodeGenFunction.h" #include "CGException.h" +#include "CGCleanup.h" #include "TargetInfo.h" using namespace clang; using namespace CodeGen; -/// Push an entry of the given size onto this protected-scope stack. -char *EHScopeStack::allocate(size_t Size) { - if (!StartOfBuffer) { - unsigned Capacity = 1024; - while (Capacity < Size) Capacity *= 2; - StartOfBuffer = new char[Capacity]; - StartOfData = EndOfBuffer = StartOfBuffer + Capacity; - } else if (static_cast<size_t>(StartOfData - StartOfBuffer) < Size) { - unsigned CurrentCapacity = EndOfBuffer - StartOfBuffer; - unsigned UsedCapacity = CurrentCapacity - (StartOfData - StartOfBuffer); - - unsigned NewCapacity = CurrentCapacity; - do { - NewCapacity *= 2; - } while (NewCapacity < UsedCapacity + Size); - - char *NewStartOfBuffer = new char[NewCapacity]; - char *NewEndOfBuffer = NewStartOfBuffer + NewCapacity; - char *NewStartOfData = NewEndOfBuffer - UsedCapacity; - memcpy(NewStartOfData, StartOfData, UsedCapacity); - delete [] StartOfBuffer; - StartOfBuffer = NewStartOfBuffer; - EndOfBuffer = NewEndOfBuffer; - StartOfData = NewStartOfData; - } - - assert(StartOfBuffer + Size <= StartOfData); - StartOfData -= Size; - return StartOfData; -} - -EHScopeStack::stable_iterator -EHScopeStack::getEnclosingEHCleanup(iterator it) const { - assert(it != end()); - do { - if (isa<EHCleanupScope>(*it)) { - if (cast<EHCleanupScope>(*it).isEHCleanup()) - return stabilize(it); - return cast<EHCleanupScope>(*it).getEnclosingEHCleanup(); - } - ++it; - } while (it != end()); - return stable_end(); -} - - -void *EHScopeStack::pushCleanup(CleanupKind Kind, size_t Size) { - assert(((Size % sizeof(void*)) == 0) && "cleanup type is misaligned"); - char *Buffer = allocate(EHCleanupScope::getSizeForCleanupSize(Size)); - bool IsNormalCleanup = Kind & NormalCleanup; - bool IsEHCleanup = Kind & EHCleanup; - bool IsActive = !(Kind & InactiveCleanup); - EHCleanupScope *Scope = - new (Buffer) EHCleanupScope(IsNormalCleanup, - IsEHCleanup, - IsActive, - Size, - BranchFixups.size(), - InnermostNormalCleanup, - InnermostEHCleanup); - if (IsNormalCleanup) - InnermostNormalCleanup = stable_begin(); - if (IsEHCleanup) - InnermostEHCleanup = stable_begin(); - - return Scope->getCleanupBuffer(); -} - -void EHScopeStack::popCleanup() { - assert(!empty() && "popping exception stack when not empty"); - - assert(isa<EHCleanupScope>(*begin())); - EHCleanupScope &Cleanup = cast<EHCleanupScope>(*begin()); - InnermostNormalCleanup = Cleanup.getEnclosingNormalCleanup(); - InnermostEHCleanup = Cleanup.getEnclosingEHCleanup(); - StartOfData += Cleanup.getAllocatedSize(); - - if (empty()) NextEHDestIndex = FirstEHDestIndex; - - // Destroy the cleanup. - Cleanup.~EHCleanupScope(); - - // Check whether we can shrink the branch-fixups stack. - if (!BranchFixups.empty()) { - // If we no longer have any normal cleanups, all the fixups are - // complete. - if (!hasNormalCleanups()) - BranchFixups.clear(); - - // Otherwise we can still trim out unnecessary nulls. - else - popNullFixups(); - } -} - -EHFilterScope *EHScopeStack::pushFilter(unsigned NumFilters) { - char *Buffer = allocate(EHFilterScope::getSizeForNumFilters(NumFilters)); - CatchDepth++; - return new (Buffer) EHFilterScope(NumFilters); -} - -void EHScopeStack::popFilter() { - assert(!empty() && "popping exception stack when not empty"); - - EHFilterScope &Filter = cast<EHFilterScope>(*begin()); - StartOfData += EHFilterScope::getSizeForNumFilters(Filter.getNumFilters()); - - if (empty()) NextEHDestIndex = FirstEHDestIndex; - - assert(CatchDepth > 0 && "mismatched filter push/pop"); - CatchDepth--; -} - -EHCatchScope *EHScopeStack::pushCatch(unsigned NumHandlers) { - char *Buffer = allocate(EHCatchScope::getSizeForNumHandlers(NumHandlers)); - CatchDepth++; - EHCatchScope *Scope = new (Buffer) EHCatchScope(NumHandlers); - for (unsigned I = 0; I != NumHandlers; ++I) - Scope->getHandlers()[I].Index = getNextEHDestIndex(); - return Scope; -} - -void EHScopeStack::pushTerminate() { - char *Buffer = allocate(EHTerminateScope::getSize()); - CatchDepth++; - new (Buffer) EHTerminateScope(getNextEHDestIndex()); -} - -/// Remove any 'null' fixups on the stack. However, we can't pop more -/// fixups than the fixup depth on the innermost normal cleanup, or -/// else fixups that we try to add to that cleanup will end up in the -/// wrong place. We *could* try to shrink fixup depths, but that's -/// actually a lot of work for little benefit. -void EHScopeStack::popNullFixups() { - // We expect this to only be called when there's still an innermost - // normal cleanup; otherwise there really shouldn't be any fixups. - assert(hasNormalCleanups()); - - EHScopeStack::iterator it = find(InnermostNormalCleanup); - unsigned MinSize = cast<EHCleanupScope>(*it).getFixupDepth(); - assert(BranchFixups.size() >= MinSize && "fixup stack out of order"); - - while (BranchFixups.size() > MinSize && - BranchFixups.back().Destination == 0) - BranchFixups.pop_back(); -} - static llvm::Constant *getAllocateExceptionFn(CodeGenFunction &CGF) { // void *__cxa_allocate_exception(size_t thrown_size); const llvm::Type *SizeTy = CGF.ConvertType(CGF.getContext().getSizeType()); @@ -287,7 +142,7 @@ static llvm::Constant *getTerminateFn(CodeGenFunction &CGF) { } static llvm::Constant *getCatchallRethrowFn(CodeGenFunction &CGF, - const char *Name) { + llvm::StringRef Name) { const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGF.getLLVMContext()); std::vector<const llvm::Type*> Args(1, Int8PtrTy); @@ -299,6 +154,7 @@ static llvm::Constant *getCatchallRethrowFn(CodeGenFunction &CGF, } const EHPersonality EHPersonality::GNU_C("__gcc_personality_v0"); +const EHPersonality EHPersonality::GNU_C_SJLJ("__gcc_personality_sj0"); const EHPersonality EHPersonality::NeXT_ObjC("__objc_personality_v0"); const EHPersonality EHPersonality::GNU_CPlusPlus("__gxx_personality_v0"); const EHPersonality EHPersonality::GNU_CPlusPlus_SJLJ("__gxx_personality_sj0"); @@ -306,6 +162,8 @@ const EHPersonality EHPersonality::GNU_ObjC("__gnu_objc_personality_v0", "objc_exception_throw"); static const EHPersonality &getCPersonality(const LangOptions &L) { + if (L.SjLjExceptions) + return EHPersonality::GNU_C_SJLJ; return EHPersonality::GNU_C; } @@ -357,24 +215,102 @@ const EHPersonality &EHPersonality::get(const LangOptions &L) { return getCPersonality(L); } -static llvm::Constant *getPersonalityFn(CodeGenFunction &CGF, +static llvm::Constant *getPersonalityFn(CodeGenModule &CGM, const EHPersonality &Personality) { - const char *Name = Personality.getPersonalityFnName(); - llvm::Constant *Fn = - CGF.CGM.CreateRuntimeFunction(llvm::FunctionType::get( - llvm::Type::getInt32Ty( - CGF.CGM.getLLVMContext()), - true), - Name); - return llvm::ConstantExpr::getBitCast(Fn, CGF.CGM.PtrToInt8Ty); + CGM.CreateRuntimeFunction(llvm::FunctionType::get( + llvm::Type::getInt32Ty(CGM.getLLVMContext()), + true), + Personality.getPersonalityFnName()); + return Fn; +} + +static llvm::Constant *getOpaquePersonalityFn(CodeGenModule &CGM, + const EHPersonality &Personality) { + llvm::Constant *Fn = getPersonalityFn(CGM, Personality); + return llvm::ConstantExpr::getBitCast(Fn, CGM.Int8PtrTy); +} + +/// Check whether a personality function could reasonably be swapped +/// for a C++ personality function. +static bool PersonalityHasOnlyCXXUses(llvm::Constant *Fn) { + for (llvm::Constant::use_iterator + I = Fn->use_begin(), E = Fn->use_end(); I != E; ++I) { + llvm::User *User = *I; + + // Conditionally white-list bitcasts. + if (llvm::ConstantExpr *CE = dyn_cast<llvm::ConstantExpr>(User)) { + if (CE->getOpcode() != llvm::Instruction::BitCast) return false; + if (!PersonalityHasOnlyCXXUses(CE)) + return false; + continue; + } + + // Otherwise, it has to be a selector call. + if (!isa<llvm::EHSelectorInst>(User)) return false; + + llvm::EHSelectorInst *Selector = cast<llvm::EHSelectorInst>(User); + for (unsigned I = 2, E = Selector->getNumArgOperands(); I != E; ++I) { + // Look for something that would've been returned by the ObjC + // runtime's GetEHType() method. + llvm::GlobalVariable *GV + = dyn_cast<llvm::GlobalVariable>(Selector->getArgOperand(I)); + if (!GV) continue; + + // ObjC EH selector entries are always global variables with + // names starting like this. + if (GV->getName().startswith("OBJC_EHTYPE")) + return false; + } + } + + return true; +} + +/// Try to use the C++ personality function in ObjC++. Not doing this +/// can cause some incompatibilities with gcc, which is more +/// aggressive about only using the ObjC++ personality in a function +/// when it really needs it. +void CodeGenModule::SimplifyPersonality() { + // For now, this is really a Darwin-specific operation. + if (Context.Target.getTriple().getOS() != llvm::Triple::Darwin) + return; + + // If we're not in ObjC++ -fexceptions, there's nothing to do. + if (!Features.CPlusPlus || !Features.ObjC1 || !Features.Exceptions) + return; + + const EHPersonality &ObjCXX = EHPersonality::get(Features); + const EHPersonality &CXX = getCXXPersonality(Features); + if (&ObjCXX == &CXX || + ObjCXX.getPersonalityFnName() == CXX.getPersonalityFnName()) + return; + + llvm::Function *Fn = + getModule().getFunction(ObjCXX.getPersonalityFnName()); + + // Nothing to do if it's unused. + if (!Fn || Fn->use_empty()) return; + + // Can't do the optimization if it has non-C++ uses. + if (!PersonalityHasOnlyCXXUses(Fn)) return; + + // Create the C++ personality function and kill off the old + // function. + llvm::Constant *CXXFn = getPersonalityFn(*this, CXX); + + // This can happen if the user is screwing with us. + if (Fn->getType() != CXXFn->getType()) return; + + Fn->replaceAllUsesWith(CXXFn); + Fn->eraseFromParent(); } /// Returns the value to inject into a selector to indicate the /// presence of a catch-all. static llvm::Constant *getCatchAllValue(CodeGenFunction &CGF) { // Possibly we should use @llvm.eh.catch.all.value here. - return llvm::ConstantPointerNull::get(CGF.CGM.PtrToInt8Ty); + return llvm::ConstantPointerNull::get(CGF.Int8PtrTy); } /// Returns the value to inject into a selector to indicate the @@ -386,26 +322,11 @@ static llvm::Constant *getCleanupValue(CodeGenFunction &CGF) { namespace { /// A cleanup to free the exception object if its initialization /// throws. - struct FreeExceptionCleanup : EHScopeStack::Cleanup { - FreeExceptionCleanup(llvm::Value *ShouldFreeVar, - llvm::Value *ExnLocVar) - : ShouldFreeVar(ShouldFreeVar), ExnLocVar(ExnLocVar) {} - - llvm::Value *ShouldFreeVar; - llvm::Value *ExnLocVar; - - void Emit(CodeGenFunction &CGF, bool IsForEH) { - 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) + struct FreeException { + static void Emit(CodeGenFunction &CGF, bool forEH, + llvm::Value *exn) { + CGF.Builder.CreateCall(getFreeExceptionFn(CGF), exn) ->setDoesNotThrow(); - CGF.EmitBlock(DoneBB); } }; } @@ -414,41 +335,17 @@ namespace { // 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"); - +static void EmitAnyExprToExn(CodeGenFunction &CGF, const Expr *e, + llvm::Value *addr) { // Make sure the exception object is cleaned up if there's an // exception during initialization. - // FIXME: stmt expressions might require this to be a normal - // cleanup, too. - CGF.EHStack.pushCleanup<FreeExceptionCleanup>(EHCleanup, - ShouldFreeVar, - ExnLocVar); - EHScopeStack::stable_iterator Cleanup = CGF.EHStack.stable_begin(); - - CGF.Builder.CreateStore(ExnLoc, ExnLocVar); - CGF.Builder.CreateStore(llvm::ConstantInt::getTrue(CGF.getLLVMContext()), - ShouldFreeVar); + CGF.pushFullExprCleanup<FreeException>(EHCleanup, addr); + EHScopeStack::stable_iterator cleanup = CGF.EHStack.stable_begin(); // __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); + const llvm::Type *ty = CGF.ConvertTypeForMem(e->getType())->getPointerTo(); + llvm::Value *typedAddr = CGF.Builder.CreateBitCast(addr, 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 @@ -457,22 +354,10 @@ static void EmitAnyExprToExn(CodeGenFunction &CGF, const Expr *E, // 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); + CGF.EmitAnyExprToMem(e, typedAddr, /*Volatile*/ false, /*IsInit*/ true); - // Technically, the exception object is like a temporary; it has to - // be cleaned up when its full-expression is complete. - // Unfortunately, the AST represents full-expressions by creating a - // CXXExprWithTemporaries, which it only does when there are actually - // temporaries. - // - // If any cleanups have been added since we pushed ours, they must - // be from temporaries; this will get popped at the same time. - // Otherwise we need to pop ours off. FIXME: this is very brittle. - if (Cleanup == CGF.EHStack.stable_begin()) - CGF.PopCleanupBlock(); + // Deactivate the cleanup block. + CGF.DeactivateCleanupBlock(cleanup); } llvm::Value *CodeGenFunction::getExceptionSlot() { @@ -495,8 +380,10 @@ void CodeGenFunction::EmitCXXThrowExpr(const CXXThrowExpr *E) { Builder.CreateUnreachable(); } - // Clear the insertion point to indicate we are in unreachable code. - Builder.ClearInsertionPoint(); + // throw is an expression, and the expression emitters expect us + // to leave ourselves at a valid insertion point. + EmitBlock(createBasicBlock("throw.cont")); + return; } @@ -517,7 +404,8 @@ void CodeGenFunction::EmitCXXThrowExpr(const CXXThrowExpr *E) { // Now throw the exception. const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(getLLVMContext()); - llvm::Constant *TypeInfo = CGM.GetAddrOfRTTIDescriptor(ThrowType, true); + llvm::Constant *TypeInfo = CGM.GetAddrOfRTTIDescriptor(ThrowType, + /*ForEH=*/true); // The address of the destructor. If the exception type has a // trivial destructor (or isn't a record), we just pass null. @@ -545,16 +433,13 @@ void CodeGenFunction::EmitCXXThrowExpr(const CXXThrowExpr *E) { Builder.CreateUnreachable(); } - // Clear the insertion point to indicate we are in unreachable code. - Builder.ClearInsertionPoint(); - - // FIXME: For now, emit a dummy basic block because expr emitters in generally - // are not ready to handle emitting expressions at unreachable points. - EnsureInsertPoint(); + // throw is an expression, and the expression emitters expect us + // to leave ourselves at a valid insertion point. + EmitBlock(createBasicBlock("throw.cont")); } void CodeGenFunction::EmitStartEHSpec(const Decl *D) { - if (!Exceptions) + if (!CGM.getLangOptions().areExceptionsEnabled()) return; const FunctionDecl* FD = dyn_cast_or_null<FunctionDecl>(D); @@ -575,13 +460,14 @@ void CodeGenFunction::EmitStartEHSpec(const Decl *D) { for (unsigned I = 0; I != NumExceptions; ++I) { QualType Ty = Proto->getExceptionType(I); QualType ExceptType = Ty.getNonReferenceType().getUnqualifiedType(); - llvm::Value *EHType = CGM.GetAddrOfRTTIDescriptor(ExceptType, true); + llvm::Value *EHType = CGM.GetAddrOfRTTIDescriptor(ExceptType, + /*ForEH=*/true); Filter->setFilter(I, EHType); } } void CodeGenFunction::EmitEndEHSpec(const Decl *D) { - if (!Exceptions) + if (!CGM.getLangOptions().areExceptionsEnabled()) return; const FunctionDecl* FD = dyn_cast_or_null<FunctionDecl>(D); @@ -625,7 +511,7 @@ void CodeGenFunction::EnterCXXTryStmt(const CXXTryStmt &S, bool IsFnTryBlock) { if (CaughtType->isObjCObjectPointerType()) TypeInfo = CGM.getObjCRuntime().GetEHType(CaughtType); else - TypeInfo = CGM.GetAddrOfRTTIDescriptor(CaughtType, true); + TypeInfo = CGM.GetAddrOfRTTIDescriptor(CaughtType, /*ForEH=*/true); CatchScope->setHandler(I, TypeInfo, Handler); } else { // No exception decl indicates '...', a catch-all. @@ -655,7 +541,7 @@ llvm::BasicBlock *CodeGenFunction::getInvokeDestImpl() { assert(EHStack.requiresLandingPad()); assert(!EHStack.empty()); - if (!Exceptions) + if (!CGM.getLangOptions().areExceptionsEnabled()) return 0; // Check the innermost scope for a cached landing pad. If this is @@ -739,8 +625,7 @@ llvm::BasicBlock *CodeGenFunction::EmitLandingPad() { // Save the current IR generation state. CGBuilderTy::InsertPoint SavedIP = Builder.saveAndClearIP(); - const EHPersonality &Personality = - EHPersonality::get(CGF.CGM.getLangOptions()); + const EHPersonality &Personality = EHPersonality::get(getLangOptions()); // Create and configure the landing pad. llvm::BasicBlock *LP = createBasicBlock("lpad"); @@ -757,7 +642,7 @@ llvm::BasicBlock *CodeGenFunction::EmitLandingPad() { // Build the selector arguments. llvm::SmallVector<llvm::Value*, 8> EHSelector; EHSelector.push_back(Exn); - EHSelector.push_back(getPersonalityFn(*this, Personality)); + EHSelector.push_back(getOpaquePersonalityFn(CGM, Personality)); // Accumulate all the handlers in scope. llvm::DenseMap<llvm::Value*, UnwindDest> EHHandlers; @@ -837,7 +722,7 @@ llvm::BasicBlock *CodeGenFunction::EmitLandingPad() { // If we have a catch-all, add null to the selector. if (CatchAll.isValid()) { - EHSelector.push_back(getCatchAllValue(CGF)); + EHSelector.push_back(getCatchAllValue(*this)); // If we have an EH filter, we need to add those handlers in the // right place in the selector, which is to say, at the end. @@ -853,14 +738,14 @@ llvm::BasicBlock *CodeGenFunction::EmitLandingPad() { // Also check whether we need a cleanup. if (UseInvokeInlineHack || HasEHCleanup) EHSelector.push_back(UseInvokeInlineHack - ? getCatchAllValue(CGF) - : getCleanupValue(CGF)); + ? getCatchAllValue(*this) + : getCleanupValue(*this)); // Otherwise, signal that we at least have cleanups. } else if (UseInvokeInlineHack || HasEHCleanup) { EHSelector.push_back(UseInvokeInlineHack - ? getCatchAllValue(CGF) - : getCleanupValue(CGF)); + ? getCatchAllValue(*this) + : getCleanupValue(*this)); } else { assert(LastToEmitInLoop > 2); LastToEmitInLoop--; @@ -902,7 +787,7 @@ llvm::BasicBlock *CodeGenFunction::EmitLandingPad() { // Check whether the exception matches. llvm::CallInst *Id = Builder.CreateCall(llvm_eh_typeid_for, - Builder.CreateBitCast(Type, CGM.PtrToInt8Ty)); + Builder.CreateBitCast(Type, Int8PtrTy)); Id->setDoesNotThrow(); Builder.CreateCondBr(Builder.CreateICmpEQ(Selection, Id), Match, Next); @@ -1141,55 +1026,54 @@ static void InitCatchParam(CodeGenFunction &CGF, return; } - // FIXME: this *really* needs to be done via a proper, Sema-emitted - // initializer expression. - - CXXRecordDecl *RD = CatchType.getTypePtr()->getAsCXXRecordDecl(); - assert(RD && "aggregate catch type was not a record!"); + assert(isa<RecordType>(CatchType) && "unexpected catch type!"); const llvm::Type *PtrTy = LLVMCatchTy->getPointerTo(0); // addrspace 0 ok - if (RD->hasTrivialCopyConstructor()) { - llvm::Value *AdjustedExn = CallBeginCatch(CGF, Exn, true); - llvm::Value *Cast = CGF.Builder.CreateBitCast(AdjustedExn, PtrTy); - CGF.EmitAggregateCopy(ParamAddr, Cast, CatchType); + // Check for a copy expression. If we don't have a copy expression, + // that means a trivial copy is okay. + const Expr *copyExpr = CatchParam.getInit(); + if (!copyExpr) { + llvm::Value *rawAdjustedExn = CallBeginCatch(CGF, Exn, true); + llvm::Value *adjustedExn = CGF.Builder.CreateBitCast(rawAdjustedExn, PtrTy); + CGF.EmitAggregateCopy(ParamAddr, adjustedExn, CatchType); return; } // We have to call __cxa_get_exception_ptr to get the adjusted // pointer before copying. - llvm::CallInst *AdjustedExn = + llvm::CallInst *rawAdjustedExn = CGF.Builder.CreateCall(getGetExceptionPtrFn(CGF), Exn); - AdjustedExn->setDoesNotThrow(); - llvm::Value *Cast = CGF.Builder.CreateBitCast(AdjustedExn, PtrTy); + rawAdjustedExn->setDoesNotThrow(); - CXXConstructorDecl *CD = RD->getCopyConstructor(CGF.getContext(), 0); - assert(CD && "record has no copy constructor!"); - llvm::Value *CopyCtor = CGF.CGM.GetAddrOfCXXConstructor(CD, Ctor_Complete); + // Cast that to the appropriate type. + llvm::Value *adjustedExn = CGF.Builder.CreateBitCast(rawAdjustedExn, PtrTy); - CallArgList CallArgs; - CallArgs.push_back(std::make_pair(RValue::get(ParamAddr), - CD->getThisType(CGF.getContext()))); - CallArgs.push_back(std::make_pair(RValue::get(Cast), - CD->getParamDecl(0)->getType())); - - const FunctionProtoType *FPT - = CD->getType()->getAs<FunctionProtoType>(); + // The copy expression is defined in terms of an OpaqueValueExpr. + // Find it and map it to the adjusted expression. + CodeGenFunction::OpaqueValueMapping + opaque(CGF, OpaqueValueExpr::findInCopyConstruct(copyExpr), + CGF.MakeAddrLValue(adjustedExn, CatchParam.getType())); // Call the copy ctor in a terminate scope. CGF.EHStack.pushTerminate(); - CGF.EmitCall(CGF.CGM.getTypes().getFunctionInfo(CallArgs, FPT), - CopyCtor, ReturnValueSlot(), CallArgs, CD); + + // Perform the copy construction. + CGF.EmitAggExpr(copyExpr, AggValueSlot::forAddr(ParamAddr, false, false)); + + // Leave the terminate scope. CGF.EHStack.popTerminate(); + // Undo the opaque value mapping. + opaque.pop(); + // Finally we can call __cxa_begin_catch. CallBeginCatch(CGF, Exn, true); } /// Begins a catch statement by initializing the catch variable and /// calling __cxa_begin_catch. -static void BeginCatch(CodeGenFunction &CGF, - const CXXCatchStmt *S) { +static void BeginCatch(CodeGenFunction &CGF, const CXXCatchStmt *S) { // We have to be very careful with the ordering of cleanups here: // C++ [except.throw]p4: // The destruction [of the exception temporary] occurs @@ -1221,7 +1105,7 @@ static void BeginCatch(CodeGenFunction &CGF, } // Emit the local. - CGF.EmitLocalBlockVarDecl(*CatchParam, &InitCatchParam); + CGF.EmitAutoVarDecl(*CatchParam, &InitCatchParam); } namespace { @@ -1428,7 +1312,7 @@ CodeGenFunction::EnterFinallyBlock(const Stmt *Body, JumpDest RethrowDest = getJumpDestInCurrentScope(getUnreachableBlock()); // Whether the finally block is being executed for EH purposes. - llvm::AllocaInst *ForEHVar = CreateTempAlloca(CGF.Builder.getInt1Ty(), + llvm::AllocaInst *ForEHVar = CreateTempAlloca(Builder.getInt1Ty(), "finally.for-eh"); InitTempAlloca(ForEHVar, llvm::ConstantInt::getFalse(getLLVMContext())); @@ -1502,7 +1386,7 @@ llvm::BasicBlock *CodeGenFunction::getTerminateLandingPad() { // Tell the backend what the exception table should be: // nothing but a catch-all. - llvm::Value *Args[3] = { Exn, getPersonalityFn(*this, Personality), + llvm::Value *Args[3] = { Exn, getOpaquePersonalityFn(CGM, Personality), getCatchAllValue(*this) }; Builder.CreateCall(CGM.getIntrinsic(llvm::Intrinsic::eh_selector), Args, Args+3, "eh.selector") @@ -1511,7 +1395,7 @@ llvm::BasicBlock *CodeGenFunction::getTerminateLandingPad() { llvm::CallInst *TerminateCall = Builder.CreateCall(getTerminateFn(*this)); TerminateCall->setDoesNotReturn(); TerminateCall->setDoesNotThrow(); - CGF.Builder.CreateUnreachable(); + Builder.CreateUnreachable(); // Restore the saved insertion state. Builder.restoreIP(SavedIP); @@ -1553,8 +1437,9 @@ CodeGenFunction::UnwindDest CodeGenFunction::getRethrowDest() { // This can always be a call because we necessarily didn't find // anything on the EH stack which needs our help. + llvm::StringRef RethrowName = Personality.getCatchallRethrowFnName(); llvm::Constant *RethrowFn; - if (const char *RethrowName = Personality.getCatchallRethrowFnName()) + if (!RethrowName.empty()) RethrowFn = getCatchallRethrowFn(*this, RethrowName); else RethrowFn = getUnwindResumeOrRethrowFn(); @@ -1569,6 +1454,3 @@ CodeGenFunction::UnwindDest CodeGenFunction::getRethrowDest() { return RethrowBlock; } -EHScopeStack::Cleanup::~Cleanup() { - llvm_unreachable("Cleanup is indestructable"); -} |