diff --git a/clang/lib/CodeGen/CGCXXABI.h b/clang/lib/CodeGen/CGCXXABI.h index 382ad11f504b811..f05b6ea3e94c77d 100644 --- a/clang/lib/CodeGen/CGCXXABI.h +++ b/clang/lib/CodeGen/CGCXXABI.h @@ -251,9 +251,10 @@ class CGCXXABI { public: virtual void emitVirtualObjectDelete(CodeGenFunction &CGF, - const CXXDeleteExpr *DE, - Address Ptr, QualType ElementType, - const CXXDestructorDecl *Dtor) = 0; + const CXXDeleteExpr *DE, Address Ptr, + QualType ElementType, + const CXXDestructorDecl *Dtor, + bool VectorDeleting) = 0; virtual void emitRethrow(CodeGenFunction &CGF, bool isNoReturn) = 0; virtual void emitThrow(CodeGenFunction &CGF, const CXXThrowExpr *E) = 0; virtual llvm::GlobalVariable *getThrowInfo(QualType T) { return nullptr; } diff --git a/clang/lib/CodeGen/CGExprCXX.cpp b/clang/lib/CodeGen/CGExprCXX.cpp index 648b9b9ed98063d..458c405698300e5 100644 --- a/clang/lib/CodeGen/CGExprCXX.cpp +++ b/clang/lib/CodeGen/CGExprCXX.cpp @@ -1903,7 +1903,7 @@ static void EmitDestroyingObjectDelete(CodeGenFunction &CGF, auto *Dtor = ElementType->getAsCXXRecordDecl()->getDestructor(); if (Dtor && Dtor->isVirtual()) CGF.CGM.getCXXABI().emitVirtualObjectDelete(CGF, DE, Ptr, ElementType, - Dtor); + Dtor, false); else CGF.EmitDeleteCall(DE->getOperatorDelete(), Ptr.emitRawPointer(CGF), ElementType); @@ -1916,7 +1916,8 @@ static bool EmitObjectDelete(CodeGenFunction &CGF, const CXXDeleteExpr *DE, Address Ptr, QualType ElementType, - llvm::BasicBlock *UnconditionalDeleteBlock) { + llvm::BasicBlock *UnconditionalDeleteBlock, + bool VectorDeleting) { // C++11 [expr.delete]p3: // If the static type of the object to be deleted is different from its // dynamic type, the static type shall be a base class of the dynamic type @@ -1961,7 +1962,7 @@ static bool EmitObjectDelete(CodeGenFunction &CGF, } if (UseVirtualCall) { CGF.CGM.getCXXABI().emitVirtualObjectDelete(CGF, DE, Ptr, ElementType, - Dtor); + Dtor, VectorDeleting); return false; } } @@ -2130,12 +2131,22 @@ void CodeGenFunction::EmitCXXDeleteExpr(const CXXDeleteExpr *E) { } assert(ConvertTypeForMem(DeleteTy) == Ptr.getElementType()); + bool RequiresVectorDestructor = false; + // FIXME check that ABI requires to call "vector" destructors or check MSVC? + if (const RecordType *RT = DeleteTy->getAs()) { + CXXRecordDecl *RD = cast(RT->getDecl()); + if (RD->hasDefinition() && !RD->hasTrivialDestructor()) { + // FIXME: check devirtualization? + const CXXDestructorDecl *Dtor = RD->getDestructor(); + RequiresVectorDestructor = Dtor->isVirtual(); + } + } - if (E->isArrayForm()) { + if (E->isArrayForm() && !RequiresVectorDestructor) { EmitArrayDelete(*this, E, Ptr, DeleteTy); EmitBlock(DeleteEnd); } else { - if (!EmitObjectDelete(*this, E, Ptr, DeleteTy, DeleteEnd)) + if (!EmitObjectDelete(*this, E, Ptr, DeleteTy, DeleteEnd, E->isArrayForm())) EmitBlock(DeleteEnd); } } diff --git a/clang/lib/CodeGen/ItaniumCXXABI.cpp b/clang/lib/CodeGen/ItaniumCXXABI.cpp index cf9e338236e5561..a2311bae090c0c3 100644 --- a/clang/lib/CodeGen/ItaniumCXXABI.cpp +++ b/clang/lib/CodeGen/ItaniumCXXABI.cpp @@ -159,7 +159,8 @@ class ItaniumCXXABI : public CodeGen::CGCXXABI { void emitVirtualObjectDelete(CodeGenFunction &CGF, const CXXDeleteExpr *DE, Address Ptr, QualType ElementType, - const CXXDestructorDecl *Dtor) override; + const CXXDestructorDecl *Dtor, + bool VectorDeleting = false) override; void emitRethrow(CodeGenFunction &CGF, bool isNoReturn) override; void emitThrow(CodeGenFunction &CGF, const CXXThrowExpr *E) override; @@ -1368,7 +1369,8 @@ void ItaniumCXXABI::emitVirtualObjectDelete(CodeGenFunction &CGF, const CXXDeleteExpr *DE, Address Ptr, QualType ElementType, - const CXXDestructorDecl *Dtor) { + const CXXDestructorDecl *Dtor, + bool VectorDeleting) { bool UseGlobalDelete = DE->isGlobalDelete(); if (UseGlobalDelete) { // Derive the complete-object pointer, which is what we need diff --git a/clang/lib/CodeGen/MicrosoftCXXABI.cpp b/clang/lib/CodeGen/MicrosoftCXXABI.cpp index f3f78f251233f1a..e41ddc1467b281a 100644 --- a/clang/lib/CodeGen/MicrosoftCXXABI.cpp +++ b/clang/lib/CodeGen/MicrosoftCXXABI.cpp @@ -120,7 +120,8 @@ class MicrosoftCXXABI : public CGCXXABI { void emitVirtualObjectDelete(CodeGenFunction &CGF, const CXXDeleteExpr *DE, Address Ptr, QualType ElementType, - const CXXDestructorDecl *Dtor) override; + const CXXDestructorDecl *Dtor, + bool VectorDeleting) override; void emitRethrow(CodeGenFunction &CGF, bool isNoReturn) override; void emitThrow(CodeGenFunction &CGF, const CXXThrowExpr *E) override; @@ -888,14 +889,15 @@ MicrosoftCXXABI::getRecordArgABI(const CXXRecordDecl *RD) const { void MicrosoftCXXABI::emitVirtualObjectDelete(CodeGenFunction &CGF, const CXXDeleteExpr *DE, - Address Ptr, - QualType ElementType, - const CXXDestructorDecl *Dtor) { + Address Ptr, QualType ElementType, + const CXXDestructorDecl *Dtor, + bool VectorDeleting) { // FIXME: Provide a source location here even though there's no // CXXMemberCallExpr for dtor call. bool UseGlobalDelete = DE->isGlobalDelete(); - // FIXME check that vector deletion is actually required. - CXXDtorType DtorType = UseGlobalDelete ? Dtor_Complete : Dtor_VectorDeleting; + CXXDtorType DtorType = UseGlobalDelete ? Dtor_Complete + : (VectorDeleting) ? Dtor_VectorDeleting + : Dtor_Deleting; llvm::Value *MDThis = EmitVirtualDestructorCall(CGF, Dtor, DtorType, Ptr, DE, /*CallOrInvoke=*/nullptr); if (UseGlobalDelete) @@ -2005,7 +2007,8 @@ llvm::Value *MicrosoftCXXABI::EmitVirtualDestructorCall( auto *D = E.dyn_cast(); assert((CE != nullptr) ^ (D != nullptr)); assert(CE == nullptr || CE->arg_begin() == CE->arg_end()); - assert(DtorType == Dtor_VectorDeleting || DtorType == Dtor_Complete); + assert(DtorType == Dtor_VectorDeleting || DtorType == Dtor_Complete || + DtorType == Dtor_Deleting); // We have only one destructor in the vftable but can get both behaviors // by passing an implicit int parameter.