@@ -1433,6 +1433,83 @@ static bool CanSkipVTablePointerInitialization(CodeGenFunction &CGF,
14331433 return true ;
14341434}
14351435
1436+ namespace {
1437+ llvm::Value *LoadThisForDtorDelete (CodeGenFunction &CGF,
1438+ const CXXDestructorDecl *DD) {
1439+ if (Expr *ThisArg = DD->getOperatorDeleteThisArg ())
1440+ return CGF.EmitScalarExpr (ThisArg);
1441+ return CGF.LoadCXXThis ();
1442+ }
1443+ }
1444+
1445+ void EmitConditionalArrayDtorCall (const CXXDestructorDecl *DD,
1446+ CodeGenFunction &CGF,
1447+ llvm::Value *ShouldDeleteCondition) {
1448+ Address ThisPtr = CGF.LoadCXXThisAddress ();
1449+ llvm::BasicBlock *ScalarBB = CGF.createBasicBlock (" dtor.scalar" );
1450+ llvm::BasicBlock *callDeleteBB =
1451+ CGF.createBasicBlock (" dtor.call_delete_after_array_destroy" );
1452+ llvm::BasicBlock *VectorBB = CGF.createBasicBlock (" dtor.vector" );
1453+ auto *CondTy = cast<llvm::IntegerType>(ShouldDeleteCondition->getType ());
1454+ llvm::Value *CheckTheBitForArrayDestroy = CGF.Builder .CreateAnd (
1455+ ShouldDeleteCondition,
1456+ llvm::Constant::getIntegerValue (CondTy, llvm::APInt (CondTy->getBitWidth (),
1457+ /* val=*/ 2 )));
1458+ llvm::Value *ShouldDestroyArray =
1459+ CGF.Builder .CreateIsNull (CheckTheBitForArrayDestroy);
1460+ CGF.Builder .CreateCondBr (ShouldDestroyArray, ScalarBB, VectorBB);
1461+
1462+ CGF.EmitBlock (VectorBB);
1463+
1464+ llvm::Value *numElements = nullptr ;
1465+ llvm::Value *allocatedPtr = nullptr ;
1466+ CharUnits cookieSize;
1467+ QualType EltTy = DD->getThisType ()->getPointeeType ();
1468+ CGF.CGM .getCXXABI ().ReadArrayCookie (CGF, ThisPtr, EltTy, numElements,
1469+ allocatedPtr, cookieSize);
1470+
1471+ // Destroy the elements.
1472+ QualType::DestructionKind dtorKind = EltTy.isDestructedType ();
1473+
1474+ assert (dtorKind);
1475+ assert (numElements && " no element count for a type with a destructor!" );
1476+
1477+ CharUnits elementSize = CGF.getContext ().getTypeSizeInChars (EltTy);
1478+ CharUnits elementAlign =
1479+ ThisPtr.getAlignment ().alignmentOfArrayElement (elementSize);
1480+
1481+ llvm::Value *arrayBegin = ThisPtr.emitRawPointer (CGF);
1482+ llvm::Value *arrayEnd = CGF.Builder .CreateInBoundsGEP (
1483+ ThisPtr.getElementType (), arrayBegin, numElements, " delete.end" );
1484+
1485+ // We already checked that the array is not 0-length before entering vector
1486+ // deleting dtor.
1487+ CGF.emitArrayDestroy (arrayBegin, arrayEnd, EltTy, elementAlign,
1488+ CGF.getDestroyer (dtorKind),
1489+ /* checkZeroLength*/ false , CGF.needsEHCleanup (dtorKind));
1490+
1491+ llvm::BasicBlock *VectorBBCont = CGF.createBasicBlock (" dtor.vector.cont" );
1492+ CGF.EmitBlock (VectorBBCont);
1493+
1494+ llvm::Value *CheckTheBitForDeleteCall = CGF.Builder .CreateAnd (
1495+ ShouldDeleteCondition,
1496+ llvm::Constant::getIntegerValue (CondTy, llvm::APInt (CondTy->getBitWidth (),
1497+ /* val=*/ 1 )));
1498+
1499+ llvm::Value *ShouldCallDelete =
1500+ CGF.Builder .CreateIsNull (CheckTheBitForDeleteCall);
1501+ CGF.Builder .CreateCondBr (ShouldCallDelete, CGF.ReturnBlock .getBlock (),
1502+ callDeleteBB);
1503+ CGF.EmitBlock (callDeleteBB);
1504+ const CXXDestructorDecl *Dtor = cast<CXXDestructorDecl>(CGF.CurCodeDecl );
1505+ const CXXRecordDecl *ClassDecl = Dtor->getParent ();
1506+ CGF.EmitDeleteCall (Dtor->getOperatorDelete (), allocatedPtr,
1507+ CGF.getContext ().getTagDeclType (ClassDecl));
1508+
1509+ CGF.EmitBranchThroughCleanup (CGF.ReturnBlock );
1510+ CGF.EmitBlock (ScalarBB);
1511+ }
1512+
14361513// / EmitDestructorBody - Emits the body of the current destructor.
14371514void CodeGenFunction::EmitDestructorBody (FunctionArgList &Args) {
14381515 const CXXDestructorDecl *Dtor = cast<CXXDestructorDecl>(CurGD.getDecl ());
@@ -1462,7 +1539,9 @@ void CodeGenFunction::EmitDestructorBody(FunctionArgList &Args) {
14621539 // outside of the function-try-block, which means it's always
14631540 // possible to delegate the destructor body to the complete
14641541 // destructor. Do so.
1465- if (DtorType == Dtor_Deleting) {
1542+ if (DtorType == Dtor_Deleting || DtorType == Dtor_VectorDeleting) {
1543+ if (CXXStructorImplicitParamValue && DtorType == Dtor_VectorDeleting)
1544+ EmitConditionalArrayDtorCall (Dtor, *this , CXXStructorImplicitParamValue);
14661545 RunCleanupsScope DtorEpilogue (*this );
14671546 EnterDtorCleanups (Dtor, Dtor_Deleting);
14681547 if (HaveInsertPoint ()) {
@@ -1491,6 +1570,7 @@ void CodeGenFunction::EmitDestructorBody(FunctionArgList &Args) {
14911570 switch (DtorType) {
14921571 case Dtor_Comdat: llvm_unreachable (" not expecting a COMDAT" );
14931572 case Dtor_Deleting: llvm_unreachable (" already handled deleting case" );
1573+ case Dtor_VectorDeleting: llvm_unreachable (" already handled vector deleting case" );
14941574
14951575 case Dtor_Complete:
14961576 assert ((Body || getTarget ().getCXXABI ().isMicrosoft ()) &&
@@ -1567,13 +1647,6 @@ void CodeGenFunction::emitImplicitAssignmentOperatorBody(FunctionArgList &Args)
15671647}
15681648
15691649namespace {
1570- llvm::Value *LoadThisForDtorDelete (CodeGenFunction &CGF,
1571- const CXXDestructorDecl *DD) {
1572- if (Expr *ThisArg = DD->getOperatorDeleteThisArg ())
1573- return CGF.EmitScalarExpr (ThisArg);
1574- return CGF.LoadCXXThis ();
1575- }
1576-
15771650 // / Call the operator delete associated with the current destructor.
15781651 struct CallDtorDelete final : EHScopeStack::Cleanup {
15791652 CallDtorDelete () {}
@@ -1592,8 +1665,12 @@ namespace {
15921665 bool ReturnAfterDelete) {
15931666 llvm::BasicBlock *callDeleteBB = CGF.createBasicBlock (" dtor.call_delete" );
15941667 llvm::BasicBlock *continueBB = CGF.createBasicBlock (" dtor.continue" );
1595- llvm::Value *ShouldCallDelete
1596- = CGF.Builder .CreateIsNull (ShouldDeleteCondition);
1668+ auto *CondTy = cast<llvm::IntegerType>(ShouldDeleteCondition->getType ());
1669+ llvm::Value *CheckTheBit = CGF.Builder .CreateAnd (
1670+ ShouldDeleteCondition, llvm::Constant::getIntegerValue (
1671+ CondTy, llvm::APInt (CondTy->getBitWidth (),
1672+ /* val=*/ 1 )));
1673+ llvm::Value *ShouldCallDelete = CGF.Builder .CreateIsNull (CheckTheBit);
15971674 CGF.Builder .CreateCondBr (ShouldCallDelete, continueBB, callDeleteBB);
15981675
15991676 CGF.EmitBlock (callDeleteBB);
0 commit comments