@@ -1002,6 +1002,13 @@ static bool RunDestructors(InterpState &S, CodePtr OpPC, const Block *B) {
10021002 return runRecordDestructor (S, OpPC, Pointer (const_cast <Block *>(B)), Desc);
10031003}
10041004
1005+ static bool hasVirtualDestructor (QualType T) {
1006+ if (const CXXRecordDecl *RD = T->getAsCXXRecordDecl ())
1007+ if (const CXXDestructorDecl *DD = RD->getDestructor ())
1008+ return DD->isVirtual ();
1009+ return false ;
1010+ }
1011+
10051012bool Free (InterpState &S, CodePtr OpPC, bool DeleteIsArrayForm,
10061013 bool IsGlobalDelete) {
10071014 if (!CheckDynamicMemoryAllocation (S, OpPC))
@@ -1019,9 +1026,20 @@ bool Free(InterpState &S, CodePtr OpPC, bool DeleteIsArrayForm,
10191026 return true ;
10201027
10211028 // Remove base casts.
1029+ QualType InitialType = Ptr.getType ();
10221030 while (Ptr.isBaseClass ())
10231031 Ptr = Ptr.getBase ();
10241032
1033+ // For the non-array case, the types must match if the static type
1034+ // does not have a virtual destructor.
1035+ if (!DeleteIsArrayForm && Ptr.getType () != InitialType &&
1036+ !hasVirtualDestructor (InitialType)) {
1037+ S.FFDiag (S.Current ->getSource (OpPC),
1038+ diag::note_constexpr_delete_base_nonvirt_dtor)
1039+ << InitialType << Ptr.getType ();
1040+ return false ;
1041+ }
1042+
10251043 if (!Ptr.isRoot () || Ptr.isOnePastEnd () || Ptr.isArrayElement ()) {
10261044 const SourceInfo &Loc = S.Current ->getSource (OpPC);
10271045 S.FFDiag (Loc, diag::note_constexpr_delete_subobject)
0 commit comments