@@ -1434,6 +1434,70 @@ static bool CanSkipVTablePointerInitialization(CodeGenFunction &CGF,
14341434 return true ;
14351435}
14361436
1437+ static void EmitConditionalArrayDtorCall (const CXXDestructorDecl *DD,
1438+ CodeGenFunction &CGF,
1439+ llvm::Value *ShouldDeleteCondition) {
1440+ Address ThisPtr = CGF.LoadCXXThisAddress ();
1441+ llvm::BasicBlock *ScalarBB = CGF.createBasicBlock (" dtor.scalar" );
1442+ llvm::BasicBlock *callDeleteBB =
1443+ CGF.createBasicBlock (" dtor.call_delete_after_array_destroy" );
1444+ llvm::BasicBlock *VectorBB = CGF.createBasicBlock (" dtor.vector" );
1445+ auto *CondTy = cast<llvm::IntegerType>(ShouldDeleteCondition->getType ());
1446+ llvm::Value *CheckTheBitForArrayDestroy = CGF.Builder .CreateAnd (
1447+ ShouldDeleteCondition, llvm::ConstantInt::get (CondTy, 2 ));
1448+ llvm::Value *ShouldDestroyArray =
1449+ CGF.Builder .CreateIsNull (CheckTheBitForArrayDestroy);
1450+ CGF.Builder .CreateCondBr (ShouldDestroyArray, ScalarBB, VectorBB);
1451+
1452+ CGF.EmitBlock (VectorBB);
1453+
1454+ llvm::Value *numElements = nullptr ;
1455+ llvm::Value *allocatedPtr = nullptr ;
1456+ CharUnits cookieSize;
1457+ QualType EltTy = DD->getThisType ()->getPointeeType ();
1458+ CGF.CGM .getCXXABI ().ReadArrayCookie (CGF, ThisPtr, EltTy, numElements,
1459+ allocatedPtr, cookieSize);
1460+
1461+ // Destroy the elements.
1462+ QualType::DestructionKind dtorKind = EltTy.isDestructedType ();
1463+
1464+ assert (dtorKind);
1465+ assert (numElements && " no element count for a type with a destructor!" );
1466+
1467+ CharUnits elementSize = CGF.getContext ().getTypeSizeInChars (EltTy);
1468+ CharUnits elementAlign =
1469+ ThisPtr.getAlignment ().alignmentOfArrayElement (elementSize);
1470+
1471+ llvm::Value *arrayBegin = ThisPtr.emitRawPointer (CGF);
1472+ llvm::Value *arrayEnd = CGF.Builder .CreateInBoundsGEP (
1473+ ThisPtr.getElementType (), arrayBegin, numElements, " delete.end" );
1474+
1475+ // We already checked that the array is not 0-length before entering vector
1476+ // deleting dtor.
1477+ CGF.emitArrayDestroy (arrayBegin, arrayEnd, EltTy, elementAlign,
1478+ CGF.getDestroyer (dtorKind),
1479+ /* checkZeroLength*/ false , CGF.needsEHCleanup (dtorKind));
1480+
1481+ llvm::BasicBlock *VectorBBCont = CGF.createBasicBlock (" dtor.vector.cont" );
1482+ CGF.EmitBlock (VectorBBCont);
1483+
1484+ llvm::Value *CheckTheBitForDeleteCall = CGF.Builder .CreateAnd (
1485+ ShouldDeleteCondition, llvm::ConstantInt::get (CondTy, 1 ));
1486+
1487+ llvm::Value *ShouldCallDelete =
1488+ CGF.Builder .CreateIsNull (CheckTheBitForDeleteCall);
1489+ CGF.Builder .CreateCondBr (ShouldCallDelete, CGF.ReturnBlock .getBlock (),
1490+ callDeleteBB);
1491+ CGF.EmitBlock (callDeleteBB);
1492+ const CXXDestructorDecl *Dtor = cast<CXXDestructorDecl>(CGF.CurCodeDecl );
1493+ const CXXRecordDecl *ClassDecl = Dtor->getParent ();
1494+ CGF.EmitDeleteCall (Dtor->getOperatorDelete (), allocatedPtr,
1495+ CGF.getContext ().getTagDeclType (ClassDecl));
1496+
1497+ CGF.EmitBranchThroughCleanup (CGF.ReturnBlock );
1498+ CGF.EmitBlock (ScalarBB);
1499+ }
1500+
14371501// / EmitDestructorBody - Emits the body of the current destructor.
14381502void CodeGenFunction::EmitDestructorBody (FunctionArgList &Args) {
14391503 const CXXDestructorDecl *Dtor = cast<CXXDestructorDecl>(CurGD.getDecl ());
@@ -1463,7 +1527,9 @@ void CodeGenFunction::EmitDestructorBody(FunctionArgList &Args) {
14631527 // outside of the function-try-block, which means it's always
14641528 // possible to delegate the destructor body to the complete
14651529 // destructor. Do so.
1466- if (DtorType == Dtor_Deleting) {
1530+ if (DtorType == Dtor_Deleting || DtorType == Dtor_VectorDeleting) {
1531+ if (CXXStructorImplicitParamValue && DtorType == Dtor_VectorDeleting)
1532+ EmitConditionalArrayDtorCall (Dtor, *this , CXXStructorImplicitParamValue);
14671533 RunCleanupsScope DtorEpilogue (*this );
14681534 EnterDtorCleanups (Dtor, Dtor_Deleting);
14691535 if (HaveInsertPoint ()) {
@@ -1492,6 +1558,8 @@ void CodeGenFunction::EmitDestructorBody(FunctionArgList &Args) {
14921558 switch (DtorType) {
14931559 case Dtor_Comdat: llvm_unreachable (" not expecting a COMDAT" );
14941560 case Dtor_Deleting: llvm_unreachable (" already handled deleting case" );
1561+ case Dtor_VectorDeleting:
1562+ llvm_unreachable (" already handled vector deleting case" );
14951563
14961564 case Dtor_Complete:
14971565 assert ((Body || getTarget ().getCXXABI ().isMicrosoft ()) &&
@@ -1574,7 +1642,6 @@ namespace {
15741642 return CGF.EmitScalarExpr (ThisArg);
15751643 return CGF.LoadCXXThis ();
15761644 }
1577-
15781645 // / Call the operator delete associated with the current destructor.
15791646 struct CallDtorDelete final : EHScopeStack::Cleanup {
15801647 CallDtorDelete () {}
@@ -1593,8 +1660,10 @@ namespace {
15931660 bool ReturnAfterDelete) {
15941661 llvm::BasicBlock *callDeleteBB = CGF.createBasicBlock (" dtor.call_delete" );
15951662 llvm::BasicBlock *continueBB = CGF.createBasicBlock (" dtor.continue" );
1596- llvm::Value *ShouldCallDelete
1597- = CGF.Builder .CreateIsNull (ShouldDeleteCondition);
1663+ auto *CondTy = cast<llvm::IntegerType>(ShouldDeleteCondition->getType ());
1664+ llvm::Value *CheckTheBit = CGF.Builder .CreateAnd (
1665+ ShouldDeleteCondition, llvm::ConstantInt::get (CondTy, 1 ));
1666+ llvm::Value *ShouldCallDelete = CGF.Builder .CreateIsNull (CheckTheBit);
15981667 CGF.Builder .CreateCondBr (ShouldCallDelete, continueBB, callDeleteBB);
15991668
16001669 CGF.EmitBlock (callDeleteBB);
0 commit comments