From 0f5a1930ccf169f9a2885bff18e3169af4aff2a4 Mon Sep 17 00:00:00 2001 From: Sebastian Redl Date: Wed, 22 Feb 2012 17:37:59 +0000 Subject: [PATCH] Unwind path cleanup for array new list initializers. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@151172 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/CodeGen/CGExprCXX.cpp | 39 ++++++++++++++---- test/CodeGenCXX/new-array-init-exceptions.cpp | 40 +++++++++++++++++++ 2 files changed, 72 insertions(+), 7 deletions(-) create mode 100644 test/CodeGenCXX/new-array-init-exceptions.cpp diff --git a/lib/CodeGen/CGExprCXX.cpp b/lib/CodeGen/CGExprCXX.cpp index af9c766238..00fbe9bfb0 100644 --- a/lib/CodeGen/CGExprCXX.cpp +++ b/lib/CodeGen/CGExprCXX.cpp @@ -804,12 +804,32 @@ CodeGenFunction::EmitNewArrayInitializer(const CXXNewExpr *E, unsigned initializerElements = 0; const Expr *Init = E->getInitializer(); + llvm::AllocaInst *endOfInit = 0; + QualType::DestructionKind dtorKind = elementType.isDestructedType(); + EHScopeStack::stable_iterator cleanup; + llvm::Instruction *cleanupDominator = 0; // If the initializer is an initializer list, first do the explicit elements. if (const InitListExpr *ILE = dyn_cast(Init)) { initializerElements = ILE->getNumInits(); - QualType elementType = E->getAllocatedType(); - // FIXME: exception-safety for the explicit initializers + + // Enter a partial-destruction cleanup if necessary. + if (needsEHCleanup(dtorKind)) { + // In principle we could tell the cleanup where we are more + // directly, but the control flow can get so varied here that it + // would actually be quite complex. Therefore we go through an + // alloca. + endOfInit = CreateTempAlloca(beginPtr->getType(), "array.endOfInit"); + cleanupDominator = Builder.CreateStore(beginPtr, endOfInit); + pushIrregularPartialArrayCleanup(beginPtr, endOfInit, elementType, + getDestroyer(dtorKind)); + cleanup = EHStack.stable_begin(); + } + for (unsigned i = 0, e = ILE->getNumInits(); i != e; ++i) { + // Tell the cleanup that it needs to destroy up to this + // element. TODO: some of these stores can be trivially + // observed to be unnecessary. + if (endOfInit) Builder.CreateStore(explicitPtr, endOfInit); StoreAnyExprIntoOneUnit(*this, ILE->getInit(i), elementType, explicitPtr); explicitPtr =Builder.CreateConstGEP1_32(explicitPtr, 1, "array.exp.next"); } @@ -825,7 +845,12 @@ CodeGenFunction::EmitNewArrayInitializer(const CXXNewExpr *E, // anything left to initialize. if (llvm::ConstantInt *constNum = dyn_cast(numElements)) { // If all elements have already been initialized, skip the whole loop. - if (constNum->getZExtValue() <= initializerElements) return; + if (constNum->getZExtValue() <= initializerElements) { + // If there was a cleanup, deactivate it. + if (cleanupDominator) + DeactivateCleanupBlock(cleanup, cleanupDominator);; + return; + } } else { llvm::BasicBlock *nonEmptyBB = createBasicBlock("new.loop.nonempty"); llvm::Value *isEmpty = Builder.CreateICmpEQ(explicitPtr, endPtr, @@ -845,11 +870,11 @@ CodeGenFunction::EmitNewArrayInitializer(const CXXNewExpr *E, Builder.CreatePHI(explicitPtr->getType(), 2, "array.cur"); curPtr->addIncoming(explicitPtr, entryBB); + // Store the new cleanup position for irregular cleanups. + if (endOfInit) Builder.CreateStore(curPtr, endOfInit); + // Enter a partial-destruction cleanup if necessary. - QualType::DestructionKind dtorKind = elementType.isDestructedType(); - EHScopeStack::stable_iterator cleanup; - llvm::Instruction *cleanupDominator = 0; - if (needsEHCleanup(dtorKind)) { + if (!cleanupDominator && needsEHCleanup(dtorKind)) { pushRegularPartialArrayCleanup(beginPtr, curPtr, elementType, getDestroyer(dtorKind)); cleanup = EHStack.stable_begin(); diff --git a/test/CodeGenCXX/new-array-init-exceptions.cpp b/test/CodeGenCXX/new-array-init-exceptions.cpp new file mode 100644 index 0000000000..933f7f7553 --- /dev/null +++ b/test/CodeGenCXX/new-array-init-exceptions.cpp @@ -0,0 +1,40 @@ +// RUN: %clang_cc1 -std=c++11 -triple i386-unknown-unknown -fexceptions -fcxx-exceptions %s -emit-llvm -o - | FileCheck %s + +struct Throws { + Throws(int); + Throws(); + ~Throws(); +}; + +// CHECK: define void @_Z7cleanupi +void cleanup(int n) { + // CHECK: invoke void @_ZN6ThrowsC1Ei + // CHECK-NEXT: to label %{{[^ ]+}} unwind label %[[LPAD:[^ ]+]] + // CHECK: invoke void @_ZN6ThrowsC1Ei + // CHECK-NEXT: to label %{{[^ ]+}} unwind label %[[LPAD]] + // CHECK: invoke void @_ZN6ThrowsC1Ei + // CHECK-NEXT: to label %{{[^ ]+}} unwind label %[[LPAD]] + // CHECK: invoke void @_ZN6ThrowsC1Ev + // CHECK-NEXT: to label %{{[^ ]+}} unwind label %[[LPAD]] + new Throws[n] { 1, 2, 3 }; + // CHECK: [[LPAD]]: + // CHECK-NEXT: landingpad + // CHECK: call void @_ZN6ThrowsD1Ev + // CHECK: call void @_ZdaPv +} + + +// CHECK: define void @_Z7cleanupv +void cleanup() { + // CHECK: invoke void @_ZN6ThrowsC1Ei + // CHECK-NEXT: to label %{{[^ ]+}} unwind label %[[LPAD2:[^ ]+]] + // CHECK: invoke void @_ZN6ThrowsC1Ei + // CHECK-NEXT: to label %{{[^ ]+}} unwind label %[[LPAD2]] + // CHECK: invoke void @_ZN6ThrowsC1Ei + // CHECK-NEXT: to label %{{[^ ]+}} unwind label %[[LPAD2]] + new Throws[3] { 1, 2, 3 }; + // CHECK: [[LPAD2]]: + // CHECK-NEXT: landingpad + // CHECK: call void @_ZN6ThrowsD1Ev + // CHECK: call void @_ZdaPv +} -- 2.40.0