@@ -1432,6 +1432,70 @@ static bool CanSkipVTablePointerInitialization(CodeGenFunction &CGF,
14321432 return true ;
14331433}
14341434
1435+ static void EmitConditionalArrayDtorCall (const CXXDestructorDecl *DD,
1436+ CodeGenFunction &CGF,
1437+ llvm::Value *ShouldDeleteCondition) {
1438+ Address ThisPtr = CGF.LoadCXXThisAddress ();
1439+ llvm::BasicBlock *ScalarBB = CGF.createBasicBlock (" dtor.scalar" );
1440+ llvm::BasicBlock *callDeleteBB =
1441+ CGF.createBasicBlock (" dtor.call_delete_after_array_destroy" );
1442+ llvm::BasicBlock *VectorBB = CGF.createBasicBlock (" dtor.vector" );
1443+ auto *CondTy = cast<llvm::IntegerType>(ShouldDeleteCondition->getType ());
1444+ llvm::Value *CheckTheBitForArrayDestroy = CGF.Builder .CreateAnd (
1445+ ShouldDeleteCondition, llvm::ConstantInt::get (CondTy, 2 ));
1446+ llvm::Value *ShouldDestroyArray =
1447+ CGF.Builder .CreateIsNull (CheckTheBitForArrayDestroy);
1448+ CGF.Builder .CreateCondBr (ShouldDestroyArray, ScalarBB, VectorBB);
1449+
1450+ CGF.EmitBlock (VectorBB);
1451+
1452+ llvm::Value *numElements = nullptr ;
1453+ llvm::Value *allocatedPtr = nullptr ;
1454+ CharUnits cookieSize;
1455+ QualType EltTy = DD->getThisType ()->getPointeeType ();
1456+ CGF.CGM .getCXXABI ().ReadArrayCookie (CGF, ThisPtr, EltTy, numElements,
1457+ allocatedPtr, cookieSize);
1458+
1459+ // Destroy the elements.
1460+ QualType::DestructionKind dtorKind = EltTy.isDestructedType ();
1461+
1462+ assert (dtorKind);
1463+ assert (numElements && " no element count for a type with a destructor!" );
1464+
1465+ CharUnits elementSize = CGF.getContext ().getTypeSizeInChars (EltTy);
1466+ CharUnits elementAlign =
1467+ ThisPtr.getAlignment ().alignmentOfArrayElement (elementSize);
1468+
1469+ llvm::Value *arrayBegin = ThisPtr.emitRawPointer (CGF);
1470+ llvm::Value *arrayEnd = CGF.Builder .CreateInBoundsGEP (
1471+ ThisPtr.getElementType (), arrayBegin, numElements, " delete.end" );
1472+
1473+ // We already checked that the array is not 0-length before entering vector
1474+ // deleting dtor.
1475+ CGF.emitArrayDestroy (arrayBegin, arrayEnd, EltTy, elementAlign,
1476+ CGF.getDestroyer (dtorKind),
1477+ /* checkZeroLength*/ false , CGF.needsEHCleanup (dtorKind));
1478+
1479+ llvm::BasicBlock *VectorBBCont = CGF.createBasicBlock (" dtor.vector.cont" );
1480+ CGF.EmitBlock (VectorBBCont);
1481+
1482+ llvm::Value *CheckTheBitForDeleteCall = CGF.Builder .CreateAnd (
1483+ ShouldDeleteCondition, llvm::ConstantInt::get (CondTy, 1 ));
1484+
1485+ llvm::Value *ShouldCallDelete =
1486+ CGF.Builder .CreateIsNull (CheckTheBitForDeleteCall);
1487+ CGF.Builder .CreateCondBr (ShouldCallDelete, CGF.ReturnBlock .getBlock (),
1488+ callDeleteBB);
1489+ CGF.EmitBlock (callDeleteBB);
1490+ const CXXDestructorDecl *Dtor = cast<CXXDestructorDecl>(CGF.CurCodeDecl );
1491+ const CXXRecordDecl *ClassDecl = Dtor->getParent ();
1492+ CGF.EmitDeleteCall (Dtor->getOperatorDelete (), allocatedPtr,
1493+ CGF.getContext ().getTagDeclType (ClassDecl));
1494+
1495+ CGF.EmitBranchThroughCleanup (CGF.ReturnBlock );
1496+ CGF.EmitBlock (ScalarBB);
1497+ }
1498+
14351499// / EmitDestructorBody - Emits the body of the current destructor.
14361500void CodeGenFunction::EmitDestructorBody (FunctionArgList &Args) {
14371501 const CXXDestructorDecl *Dtor = cast<CXXDestructorDecl>(CurGD.getDecl ());
@@ -1461,7 +1525,9 @@ void CodeGenFunction::EmitDestructorBody(FunctionArgList &Args) {
14611525 // outside of the function-try-block, which means it's always
14621526 // possible to delegate the destructor body to the complete
14631527 // destructor. Do so.
1464- if (DtorType == Dtor_Deleting) {
1528+ if (DtorType == Dtor_Deleting || DtorType == Dtor_VectorDeleting) {
1529+ if (CXXStructorImplicitParamValue && DtorType == Dtor_VectorDeleting)
1530+ EmitConditionalArrayDtorCall (Dtor, *this , CXXStructorImplicitParamValue);
14651531 RunCleanupsScope DtorEpilogue (*this );
14661532 EnterDtorCleanups (Dtor, Dtor_Deleting);
14671533 if (HaveInsertPoint ()) {
@@ -1490,6 +1556,8 @@ void CodeGenFunction::EmitDestructorBody(FunctionArgList &Args) {
14901556 switch (DtorType) {
14911557 case Dtor_Comdat: llvm_unreachable (" not expecting a COMDAT" );
14921558 case Dtor_Deleting: llvm_unreachable (" already handled deleting case" );
1559+ case Dtor_VectorDeleting:
1560+ llvm_unreachable (" already handled vector deleting case" );
14931561
14941562 case Dtor_Complete:
14951563 assert ((Body || getTarget ().getCXXABI ().isMicrosoft ()) &&
@@ -1572,7 +1640,6 @@ namespace {
15721640 return CGF.EmitScalarExpr (ThisArg);
15731641 return CGF.LoadCXXThis ();
15741642 }
1575-
15761643 // / Call the operator delete associated with the current destructor.
15771644 struct CallDtorDelete final : EHScopeStack::Cleanup {
15781645 CallDtorDelete () {}
@@ -1591,8 +1658,10 @@ namespace {
15911658 bool ReturnAfterDelete) {
15921659 llvm::BasicBlock *callDeleteBB = CGF.createBasicBlock (" dtor.call_delete" );
15931660 llvm::BasicBlock *continueBB = CGF.createBasicBlock (" dtor.continue" );
1594- llvm::Value *ShouldCallDelete
1595- = CGF.Builder .CreateIsNull (ShouldDeleteCondition);
1661+ auto *CondTy = cast<llvm::IntegerType>(ShouldDeleteCondition->getType ());
1662+ llvm::Value *CheckTheBit = CGF.Builder .CreateAnd (
1663+ ShouldDeleteCondition, llvm::ConstantInt::get (CondTy, 1 ));
1664+ llvm::Value *ShouldCallDelete = CGF.Builder .CreateIsNull (CheckTheBit);
15961665 CGF.Builder .CreateCondBr (ShouldCallDelete, continueBB, callDeleteBB);
15971666
15981667 CGF.EmitBlock (callDeleteBB);
0 commit comments