Skip to content

Commit df3761f

Browse files
committed
[c++20] Check for a class-specific operator delete when deleting an
object of class type with a virtual destructor. llvm-svn: 373875
1 parent 74ce711 commit df3761f

File tree

2 files changed

+38
-0
lines changed

2 files changed

+38
-0
lines changed

clang/lib/AST/ExprConstant.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6019,6 +6019,13 @@ static bool hasVirtualDestructor(QualType T) {
60196019
return false;
60206020
}
60216021

6022+
static const FunctionDecl *getVirtualOperatorDelete(QualType T) {
6023+
if (CXXRecordDecl *RD = T->getAsCXXRecordDecl())
6024+
if (CXXDestructorDecl *DD = RD->getDestructor())
6025+
return DD->isVirtual() ? DD->getOperatorDelete() : nullptr;
6026+
return nullptr;
6027+
}
6028+
60226029
/// Check that the given object is a suitable pointer to a heap allocation that
60236030
/// still exists and is of the right kind for the purpose of a deletion.
60246031
///
@@ -13208,6 +13215,18 @@ bool VoidExprEvaluator::VisitCXXDeleteExpr(const CXXDeleteExpr *E) {
1320813215
return false;
1320913216
}
1321013217

13218+
// For a class type with a virtual destructor, the selected operator delete
13219+
// is the one looked up when building the destructor.
13220+
if (!E->isArrayForm() && !E->isGlobalDelete()) {
13221+
const FunctionDecl *VirtualDelete = getVirtualOperatorDelete(AllocType);
13222+
if (VirtualDelete &&
13223+
!VirtualDelete->isReplaceableGlobalAllocationFunction()) {
13224+
Info.FFDiag(E, diag::note_constexpr_new_non_replaceable)
13225+
<< isa<CXXMethodDecl>(VirtualDelete) << VirtualDelete;
13226+
return false;
13227+
}
13228+
}
13229+
1321113230
if (!HandleDestruction(Info, E->getExprLoc(), Pointer.getLValueBase(),
1321213231
(*Alloc)->Value, AllocType))
1321313232
return false;

clang/test/SemaCXX/constant-expression-cxx2a.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1190,6 +1190,25 @@ namespace dtor_call {
11901190
static_assert(virt_dtor(3, "YX"));
11911191
static_assert(virt_dtor(4, "X"));
11921192

1193+
constexpr bool virt_delete(bool global) {
1194+
struct A {
1195+
virtual constexpr ~A() {}
1196+
};
1197+
struct B : A {
1198+
void operator delete(void *);
1199+
constexpr ~B() {}
1200+
};
1201+
1202+
A *p = new B;
1203+
if (global)
1204+
::delete p;
1205+
else
1206+
delete p; // expected-note {{call to class-specific 'operator delete'}}
1207+
return true;
1208+
}
1209+
static_assert(virt_delete(true));
1210+
static_assert(virt_delete(false)); // expected-error {{}} expected-note {{in call}}
1211+
11931212
constexpr void use_after_virt_destroy() {
11941213
char buff[4] = {};
11951214
VU vu;

0 commit comments

Comments
 (0)