Index: lib/CodeGen/CGException.cpp =================================================================== --- lib/CodeGen/CGException.cpp (revision 163683) +++ lib/CodeGen/CGException.cpp (working copy) @@ -745,6 +745,50 @@ }; const CleanupHackLevel_t CleanupHackLevel = CHL_MandatoryCleanup; +// Create a new landing pad for tmp objects destructor's unwind +// To be used only by auto var decl parent creating tmp objs +llvm::BasicBlock *CodeGenFunction::EmitAutoVarDeclCleanupLpad() { + assert(ShouldConsiderParentVarDecCleanUp() && + "!ShouldConsiderParentVarDecCleanUp()"); + + CGBuilderTy::InsertPoint savedIP = Builder.saveAndClearIP(); + llvm::BasicBlock *CurLP = EHStack.begin()->getCachedLandingPad(); + + llvm::BasicBlock *lpad = createBasicBlock("lpad"); //auto var cleanup + EmitBlock(lpad); + + const EHPersonality &personality = EHPersonality::get(getLangOpts()); + llvm::LandingPadInst *LPadInst = + Builder.CreateLandingPad(llvm::StructType::get(Int8PtrTy, Int32Ty, NULL), + getOpaquePersonalityFn(CGM, personality), 1); + + llvm::Value *LPadExn = Builder.CreateExtractValue(LPadInst, 0); + Builder.CreateStore(LPadExn, getExceptionSlot()); + llvm::Value *LPadSel = Builder.CreateExtractValue(LPadInst, 1); + Builder.CreateStore(LPadSel, getEHSelectorSlot()); + + LPadInst->addClause(getCatchAllValue(*this)); + + // Save the current landing pad, to be restored before quitting + llvm::BasicBlock *oldLP = EHStack.begin()->getCachedLandingPad(); + // Unwind dest shall be terminating lpad as we are already inside lpad + EHStack.begin()->setCachedLandingPad(getTerminateLandingPad()); + + // Emit destructor call to destroy the parent auto variable cleanup + destroyCXXObject(*this,CurAutoVarEmission.Address, + CurAutoVarEmission.Variable->getType().getCanonicalType()); + // Restore the saved landing pad + EHStack.begin()->setCachedLandingPad(oldLP); + // Jump to cleanup + Builder.CreateBr(getEHDispatchBlock(EHStack.getInnermostEHScope())); + + // Tmp obj's destructor will use newly created landing pad + EHStack.begin()->setCachedLandingPad(lpad); + + Builder.restoreIP(savedIP); + return CurLP; +} + llvm::BasicBlock *CodeGenFunction::EmitLandingPad() { assert(EHStack.requiresLandingPad()); Index: lib/CodeGen/CodeGenFunction.cpp =================================================================== --- lib/CodeGen/CodeGenFunction.cpp (revision 163683) +++ lib/CodeGen/CodeGenFunction.cpp (working copy) @@ -39,7 +39,8 @@ IndirectBranch(0), SwitchInsn(0), CaseRangeBlock(0), UnreachableBlock(0), CXXABIThisDecl(0), CXXABIThisValue(0), CXXThisValue(0), CXXVTTDecl(0), CXXVTTValue(0), OutermostConditional(0), TerminateLandingPad(0), - TerminateHandler(0), TrapBB(0) { + TerminateHandler(0), TrapBB(0), + CurAutoVarEmission(AutoVarEmission::invalid()){ CatchUndefined = getContext().getLangOpts().CatchUndefined; if (!suppressNewContext) Index: lib/CodeGen/CodeGenFunction.h =================================================================== --- lib/CodeGen/CodeGenFunction.h (revision 163683) +++ lib/CodeGen/CodeGenFunction.h (working copy) @@ -1274,6 +1274,7 @@ Destroyer *destroyer, bool useEHCleanupForArray); void emitDestroy(llvm::Value *addr, QualType type, Destroyer *destroyer, bool useEHCleanupForArray); + llvm::BasicBlock *EmitAutoVarDeclCleanupLpad(); llvm::Function *generateDestroyHelper(llvm::Constant *addr, QualType type, Destroyer *destroyer, @@ -1931,7 +1932,10 @@ Variable->getNameAsString()); } }; + AutoVarEmission CurAutoVarEmission; // tmp obj eh_cleanup will need + AutoVarEmission EmitAutoVarAlloca(const VarDecl &var); + bool ShouldConsiderParentVarDecCleanUp(); void EmitAutoVarInit(const AutoVarEmission &emission); void EmitAutoVarCleanups(const AutoVarEmission &emission); void emitAutoVarTypeCleanup(const AutoVarEmission &emission, Index: lib/CodeGen/CGDecl.cpp =================================================================== --- lib/CodeGen/CGDecl.cpp (revision 163683) +++ lib/CodeGen/CGDecl.cpp (working copy) @@ -13,6 +13,7 @@ #include "CGDebugInfo.h" #include "CodeGenFunction.h" +#include "CGCleanup.h" #include "CodeGenModule.h" #include "CGOpenCLRuntime.h" #include "clang/AST/ASTContext.h" @@ -339,6 +340,36 @@ } } +bool CodeGenFunction::ShouldConsiderParentVarDecCleanUp() { + + if(CurAutoVarEmission.Variable == 0) + return false; + + QualType type = CurAutoVarEmission.Variable->getType().getCanonicalType(); + + if(!type.getTypePtr()->isRecordType() || + getContext().getAsArrayType(type)) + return false; + + const RecordType *rtype; + const CXXRecordDecl *record; + const CXXDestructorDecl *detor; + + rtype = type->castAs(); + if(rtype) { + record = cast(rtype->getDecl()); + if(record){ + detor = record->getDestructor(); + if(detor) { + if(!detor->isTrivial()) + return true; + } + } + } + + return false; +} + namespace { struct DestroyObject : EHScopeStack::Cleanup { DestroyObject(llvm::Value *addr, QualType type, @@ -352,12 +383,35 @@ CodeGenFunction::Destroyer *destroyer; bool useEHCleanupForArray; + llvm::BasicBlock *PushParentVarDeclCleanup(CodeGenFunction &CGF, + Flags flags) { + llvm::BasicBlock *LP = 0; + if(flags.isForNormalCleanup()) { + LP = CGF.EmitAutoVarDeclCleanupLpad(); + } + return LP; + } + + void PopParentVarDeclCleanup(CodeGenFunction &CGF, + llvm::BasicBlock *LP, Flags flags) { + if(flags.isForNormalCleanup()) + CGF.EHStack.begin()->setCachedLandingPad(LP); + } + void Emit(CodeGenFunction &CGF, Flags flags) { // Don't use an EH cleanup recursively from an EH cleanup. bool useEHCleanupForArray = flags.isForNormalCleanup() && this->useEHCleanupForArray; + llvm::BasicBlock *AutoVarDecCleanupLP = 0; + + if(CGF.ShouldConsiderParentVarDecCleanUp()) + AutoVarDecCleanupLP = PushParentVarDeclCleanup(CGF, flags); + CGF.emitDestroy(addr, type, destroyer, useEHCleanupForArray); + + if(CGF.ShouldConsiderParentVarDecCleanUp()) + PopParentVarDeclCleanup(CGF, AutoVarDecCleanupLP, flags); } }; @@ -770,7 +824,9 @@ /// These turn into simple stack objects, or GlobalValues depending on target. void CodeGenFunction::EmitAutoVarDecl(const VarDecl &D) { AutoVarEmission emission = EmitAutoVarAlloca(D); + CurAutoVarEmission = emission; // needed by tmp obj destructor's ehcleanup EmitAutoVarInit(emission); + CurAutoVarEmission = AutoVarEmission::invalid(); EmitAutoVarCleanups(emission); }