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