[clang] [clang][bytecode] Check new/delete mismatch earlier (PR #147732)
Timm Baeder via cfe-commits
cfe-commits at lists.llvm.org
Wed Jul 9 06:56:26 PDT 2025
https://github.com/tbaederr created https://github.com/llvm/llvm-project/pull/147732
This fixes a mismatch in diagnostic output with the current intepreter.
>From 5d9464124dc09bde2b697d7bfc0f224b030a0bab Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Timm=20B=C3=A4der?= <tbaeder at redhat.com>
Date: Wed, 9 Jul 2025 15:17:26 +0200
Subject: [PATCH] [clang][bytecode] Check new/delete mismatch earlier
This fixes a mismatch in diagnostic output with the current intepreter.
---
clang/lib/AST/ByteCode/Interp.cpp | 32 +++++++++++++++-----------
clang/test/AST/ByteCode/new-delete.cpp | 14 +++++++++++
2 files changed, 32 insertions(+), 14 deletions(-)
diff --git a/clang/lib/AST/ByteCode/Interp.cpp b/clang/lib/AST/ByteCode/Interp.cpp
index 51cf0c59f0b50..be77657acabcc 100644
--- a/clang/lib/AST/ByteCode/Interp.cpp
+++ b/clang/lib/AST/ByteCode/Interp.cpp
@@ -1196,6 +1196,8 @@ bool Free(InterpState &S, CodePtr OpPC, bool DeleteIsArrayForm,
if (!CheckDynamicMemoryAllocation(S, OpPC))
return false;
+ DynamicAllocator &Allocator = S.getAllocator();
+
const Expr *Source = nullptr;
const Block *BlockToDelete = nullptr;
{
@@ -1212,6 +1214,21 @@ bool Free(InterpState &S, CodePtr OpPC, bool DeleteIsArrayForm,
while (Ptr.isBaseClass())
Ptr = Ptr.getBase();
+ Source = Ptr.getDeclDesc()->asExpr();
+ BlockToDelete = Ptr.block();
+
+ // Check that new[]/delete[] or new/delete were used, not a mixture.
+ const Descriptor *BlockDesc = BlockToDelete->getDescriptor();
+ if (std::optional<DynamicAllocator::Form> AllocForm =
+ Allocator.getAllocationForm(Source)) {
+ DynamicAllocator::Form DeleteForm =
+ DeleteIsArrayForm ? DynamicAllocator::Form::Array
+ : DynamicAllocator::Form::NonArray;
+ if (!CheckNewDeleteForms(S, OpPC, *AllocForm, DeleteForm, BlockDesc,
+ Source))
+ return false;
+ }
+
// For the non-array case, the types must match if the static type
// does not have a virtual destructor.
if (!DeleteIsArrayForm && Ptr.getType() != InitialType &&
@@ -1230,9 +1247,6 @@ bool Free(InterpState &S, CodePtr OpPC, bool DeleteIsArrayForm,
return false;
}
- Source = Ptr.getDeclDesc()->asExpr();
- BlockToDelete = Ptr.block();
-
if (!CheckDeleteSource(S, OpPC, Source, Ptr))
return false;
@@ -1266,11 +1280,6 @@ bool Free(InterpState &S, CodePtr OpPC, bool DeleteIsArrayForm,
if (!RunDestructors(S, OpPC, BlockToDelete))
return false;
- DynamicAllocator &Allocator = S.getAllocator();
- const Descriptor *BlockDesc = BlockToDelete->getDescriptor();
- std::optional<DynamicAllocator::Form> AllocForm =
- Allocator.getAllocationForm(Source);
-
if (!Allocator.deallocate(Source, BlockToDelete, S)) {
// Nothing has been deallocated, this must be a double-delete.
const SourceInfo &Loc = S.Current->getSource(OpPC);
@@ -1278,12 +1287,7 @@ bool Free(InterpState &S, CodePtr OpPC, bool DeleteIsArrayForm,
return false;
}
- assert(AllocForm);
- DynamicAllocator::Form DeleteForm = DeleteIsArrayForm
- ? DynamicAllocator::Form::Array
- : DynamicAllocator::Form::NonArray;
- return CheckNewDeleteForms(S, OpPC, *AllocForm, DeleteForm, BlockDesc,
- Source);
+ return true;
}
void diagnoseEnumValue(InterpState &S, CodePtr OpPC, const EnumDecl *ED,
diff --git a/clang/test/AST/ByteCode/new-delete.cpp b/clang/test/AST/ByteCode/new-delete.cpp
index 840736f332250..3c0bdbc8c99fe 100644
--- a/clang/test/AST/ByteCode/new-delete.cpp
+++ b/clang/test/AST/ByteCode/new-delete.cpp
@@ -171,6 +171,20 @@ namespace Arrays {
}
static_assert(mismatch2() == 6); // both-error {{not an integral constant expression}} \
// both-note {{in call to 'mismatch2()'}}
+
+ constexpr int mismatch3() { // both-error {{never produces a constant expression}}
+ int a = 0;
+ struct S {};
+ struct T : S {};
+ T *p = new T[3]{}; // both-note 2{{heap allocation performed here}}
+ delete (S*)p; // both-note 2{{non-array delete used to delete pointer to array object of type 'T[3]'}}
+
+ return 0;
+
+ }
+ static_assert(mismatch3() == 0); // both-error {{not an integral constant expression}} \
+ // both-note {{in call to}}
+
/// Array of composite elements.
constexpr int foo() {
S *ss = new S[12];
More information about the cfe-commits
mailing list