Skip to content

Commit 36cbd43

Browse files
authored
[clang][bytecode] Check new/delete mismatch earlier (#147732)
This fixes a mismatch in diagnostic output with the current intepreter.
1 parent 00a85e5 commit 36cbd43

File tree

2 files changed

+32
-14
lines changed

2 files changed

+32
-14
lines changed

clang/lib/AST/ByteCode/Interp.cpp

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1196,6 +1196,8 @@ bool Free(InterpState &S, CodePtr OpPC, bool DeleteIsArrayForm,
11961196
if (!CheckDynamicMemoryAllocation(S, OpPC))
11971197
return false;
11981198

1199+
DynamicAllocator &Allocator = S.getAllocator();
1200+
11991201
const Expr *Source = nullptr;
12001202
const Block *BlockToDelete = nullptr;
12011203
{
@@ -1212,6 +1214,21 @@ bool Free(InterpState &S, CodePtr OpPC, bool DeleteIsArrayForm,
12121214
while (Ptr.isBaseClass())
12131215
Ptr = Ptr.getBase();
12141216

1217+
Source = Ptr.getDeclDesc()->asExpr();
1218+
BlockToDelete = Ptr.block();
1219+
1220+
// Check that new[]/delete[] or new/delete were used, not a mixture.
1221+
const Descriptor *BlockDesc = BlockToDelete->getDescriptor();
1222+
if (std::optional<DynamicAllocator::Form> AllocForm =
1223+
Allocator.getAllocationForm(Source)) {
1224+
DynamicAllocator::Form DeleteForm =
1225+
DeleteIsArrayForm ? DynamicAllocator::Form::Array
1226+
: DynamicAllocator::Form::NonArray;
1227+
if (!CheckNewDeleteForms(S, OpPC, *AllocForm, DeleteForm, BlockDesc,
1228+
Source))
1229+
return false;
1230+
}
1231+
12151232
// For the non-array case, the types must match if the static type
12161233
// does not have a virtual destructor.
12171234
if (!DeleteIsArrayForm && Ptr.getType() != InitialType &&
@@ -1230,9 +1247,6 @@ bool Free(InterpState &S, CodePtr OpPC, bool DeleteIsArrayForm,
12301247
return false;
12311248
}
12321249

1233-
Source = Ptr.getDeclDesc()->asExpr();
1234-
BlockToDelete = Ptr.block();
1235-
12361250
if (!CheckDeleteSource(S, OpPC, Source, Ptr))
12371251
return false;
12381252

@@ -1266,24 +1280,14 @@ bool Free(InterpState &S, CodePtr OpPC, bool DeleteIsArrayForm,
12661280
if (!RunDestructors(S, OpPC, BlockToDelete))
12671281
return false;
12681282

1269-
DynamicAllocator &Allocator = S.getAllocator();
1270-
const Descriptor *BlockDesc = BlockToDelete->getDescriptor();
1271-
std::optional<DynamicAllocator::Form> AllocForm =
1272-
Allocator.getAllocationForm(Source);
1273-
12741283
if (!Allocator.deallocate(Source, BlockToDelete, S)) {
12751284
// Nothing has been deallocated, this must be a double-delete.
12761285
const SourceInfo &Loc = S.Current->getSource(OpPC);
12771286
S.FFDiag(Loc, diag::note_constexpr_double_delete);
12781287
return false;
12791288
}
12801289

1281-
assert(AllocForm);
1282-
DynamicAllocator::Form DeleteForm = DeleteIsArrayForm
1283-
? DynamicAllocator::Form::Array
1284-
: DynamicAllocator::Form::NonArray;
1285-
return CheckNewDeleteForms(S, OpPC, *AllocForm, DeleteForm, BlockDesc,
1286-
Source);
1290+
return true;
12871291
}
12881292

12891293
void diagnoseEnumValue(InterpState &S, CodePtr OpPC, const EnumDecl *ED,

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

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,20 @@ namespace Arrays {
171171
}
172172
static_assert(mismatch2() == 6); // both-error {{not an integral constant expression}} \
173173
// both-note {{in call to 'mismatch2()'}}
174+
175+
constexpr int mismatch3() { // both-error {{never produces a constant expression}}
176+
int a = 0;
177+
struct S {};
178+
struct T : S {};
179+
T *p = new T[3]{}; // both-note 2{{heap allocation performed here}}
180+
delete (S*)p; // both-note 2{{non-array delete used to delete pointer to array object of type 'T[3]'}}
181+
182+
return 0;
183+
184+
}
185+
static_assert(mismatch3() == 0); // both-error {{not an integral constant expression}} \
186+
// both-note {{in call to}}
187+
174188
/// Array of composite elements.
175189
constexpr int foo() {
176190
S *ss = new S[12];

0 commit comments

Comments
 (0)