Skip to content

Commit f0b9a0b

Browse files
authored
[clang][bytecode] Diagnose delete with non-virtual dtor (#114373)
... in the base class.
1 parent 7557972 commit f0b9a0b

File tree

2 files changed

+28
-0
lines changed

2 files changed

+28
-0
lines changed

clang/lib/AST/ByteCode/Interp.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
10051012
bool 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)

clang/test/AST/ByteCode/new-delete.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -569,6 +569,16 @@ namespace CastedDelete {
569569
return a;
570570
}
571571
static_assert(vdtor_1() == 1);
572+
573+
constexpr int foo() { // both-error {{never produces a constant expression}}
574+
struct S {};
575+
struct T : S {};
576+
S *p = new T();
577+
delete p; // both-note 2{{delete of object with dynamic type 'T' through pointer to base class type 'S' with non-virtual destructor}}
578+
return 1;
579+
}
580+
static_assert(foo() == 1); // both-error {{not an integral constant expression}} \
581+
// both-note {{in call to}}
572582
}
573583

574584
constexpr void use_after_free_2() { // both-error {{never produces a constant expression}}

0 commit comments

Comments
 (0)