@@ -3768,6 +3768,28 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal,
37683768 DeclarationName DeleteName = Context.DeclarationNames .getCXXOperatorName (
37693769 ArrayForm ? OO_Array_Delete : OO_Delete);
37703770
3771+ // C++20 [expr.delete]p6: If the value of the operand of the delete-
3772+ // expression is not a null pointer value and the selected deallocation
3773+ // function (see below) is not a destroying operator delete, the delete-
3774+ // expression will invoke the destructor (if any) for the object or the
3775+ // elements of the array being deleted.
3776+ //
3777+ // This means we should not look at the destructor for a destroying
3778+ // delete operator, as that destructor is never called, unless the
3779+ // destructor is virtual (see [expr.delete]p8.1) because then the
3780+ // selected operator depends on the dynamic type of the pointer.
3781+ auto IsDtorCalled = [](const CXXMethodDecl *Dtor,
3782+ const FunctionDecl *OperatorDelete) {
3783+ if (!OperatorDelete)
3784+ return true ;
3785+
3786+ if (!OperatorDelete->isDestroyingOperatorDelete ())
3787+ return true ;
3788+
3789+ // We have a destroying operator delete, so it depends on the dtor.
3790+ return Dtor->isVirtual ();
3791+ };
3792+
37713793 if (PointeeRD) {
37723794 if (!UseGlobal &&
37733795 FindDeallocationFunction (StartLoc, PointeeRD, DeleteName,
@@ -3792,21 +3814,14 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal,
37923814 .HasSizeT ;
37933815 }
37943816
3795- // C++20 [expr.delete]p6: If the value of the operand of the delete-
3796- // expression is not a null pointer value and the selected deallocation
3797- // function (see below) is not a destroying operator delete, the delete-
3798- // expression will invoke the destructor (if any) for the object or the
3799- // elements of the array being deleted.
3800- //
3801- // This means we should not look at the destructor for a destroying
3802- // delete operator, as that destructor is never called.
3803- if (!PointeeRD->hasIrrelevantDestructor () &&
3804- (!OperatorDelete || !OperatorDelete->isDestroyingOperatorDelete ())) {
3817+ if (!PointeeRD->hasIrrelevantDestructor ()) {
38053818 if (CXXDestructorDecl *Dtor = LookupDestructor (PointeeRD)) {
3806- MarkFunctionReferenced (StartLoc,
3807- const_cast <CXXDestructorDecl *>(Dtor));
3808- if (DiagnoseUseOfDecl (Dtor, StartLoc))
3809- return ExprError ();
3819+ if (IsDtorCalled (Dtor, OperatorDelete)) {
3820+ MarkFunctionReferenced (StartLoc,
3821+ const_cast <CXXDestructorDecl *>(Dtor));
3822+ if (DiagnoseUseOfDecl (Dtor, StartLoc))
3823+ return ExprError ();
3824+ }
38103825 }
38113826 }
38123827
@@ -3839,13 +3854,13 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal,
38393854 MarkFunctionReferenced (StartLoc, OperatorDelete);
38403855
38413856 // Check access and ambiguity of destructor if we're going to call it.
3842- // Note that this is required even for a virtual delete, but not for a
3843- // destroying delete operator.
3857+ // Note that this is required even for a virtual delete.
38443858 bool IsVirtualDelete = false ;
3845- if (PointeeRD && !OperatorDelete-> isDestroyingOperatorDelete () ) {
3859+ if (PointeeRD) {
38463860 if (CXXDestructorDecl *Dtor = LookupDestructor (PointeeRD)) {
3847- CheckDestructorAccess (Ex.get ()->getExprLoc (), Dtor,
3848- PDiag (diag::err_access_dtor) << PointeeElem);
3861+ if (IsDtorCalled (Dtor, OperatorDelete))
3862+ CheckDestructorAccess (Ex.get ()->getExprLoc (), Dtor,
3863+ PDiag (diag::err_access_dtor) << PointeeElem);
38493864 IsVirtualDelete = Dtor->isVirtual ();
38503865 }
38513866 }
0 commit comments