Skip to content

Commit df11ee2

Browse files
authored
[clang][bytecode] Diagnose member calls on deleted blocks (llvm#106529)
This requires a bit of restructuring of ctor calls when checking for a potential constant expression.
1 parent 1f8f2ed commit df11ee2

File tree

6 files changed

+40
-19
lines changed

6 files changed

+40
-19
lines changed

clang/lib/AST/ByteCode/Interp.cpp

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -305,14 +305,18 @@ bool CheckLive(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
305305

306306
if (!Ptr.isLive()) {
307307
const auto &Src = S.Current->getSource(OpPC);
308-
bool IsTemp = Ptr.isTemporary();
309308

310-
S.FFDiag(Src, diag::note_constexpr_lifetime_ended, 1) << AK << !IsTemp;
309+
if (Ptr.isDynamic()) {
310+
S.FFDiag(Src, diag::note_constexpr_access_deleted_object) << AK;
311+
} else {
312+
bool IsTemp = Ptr.isTemporary();
313+
S.FFDiag(Src, diag::note_constexpr_lifetime_ended, 1) << AK << !IsTemp;
311314

312-
if (IsTemp)
313-
S.Note(Ptr.getDeclLoc(), diag::note_constexpr_temporary_here);
314-
else
315-
S.Note(Ptr.getDeclLoc(), diag::note_declared_at);
315+
if (IsTemp)
316+
S.Note(Ptr.getDeclLoc(), diag::note_constexpr_temporary_here);
317+
else
318+
S.Note(Ptr.getDeclLoc(), diag::note_declared_at);
319+
}
316320

317321
return false;
318322
}

clang/lib/AST/ByteCode/Interp.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2630,7 +2630,11 @@ inline bool Call(InterpState &S, CodePtr OpPC, const Function *Func,
26302630
if (!CheckCallable(S, OpPC, Func))
26312631
return false;
26322632

2633-
if (Func->hasThisPointer() && S.checkingPotentialConstantExpression())
2633+
// FIXME: The isConstructor() check here is not always right. The current
2634+
// constant evaluator is somewhat inconsistent in when it allows a function
2635+
// call when checking for a constant expression.
2636+
if (Func->hasThisPointer() && S.checkingPotentialConstantExpression() &&
2637+
!Func->isConstructor())
26342638
return false;
26352639

26362640
if (!CheckCallDepth(S, OpPC))

clang/lib/AST/ByteCode/InterpBlock.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,8 @@ DeadBlock::DeadBlock(DeadBlock *&Root, Block *Blk)
110110
Prev = nullptr;
111111
Root = this;
112112

113+
B.IsDynamic = Blk->IsDynamic;
114+
113115
// Transfer pointers.
114116
B.Pointers = Blk->Pointers;
115117
for (Pointer *P = Blk->Pointers; P; P = P->Next)

clang/lib/AST/ByteCode/Pointer.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -491,6 +491,14 @@ class Pointer {
491491
}
492492
return false;
493493
}
494+
/// Checks if the storage has been dynamically allocated.
495+
bool isDynamic() const {
496+
if (isBlockPointer()) {
497+
assert(asBlockPointer().Pointee);
498+
return asBlockPointer().Pointee->isDynamic();
499+
}
500+
return false;
501+
}
494502
/// Checks if the storage is a static temporary.
495503
bool isStaticTemporary() const { return isStatic() && isTemporary(); }
496504

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -579,6 +579,13 @@ namespace CastedDelete {
579579
// expected-note {{in call to}}
580580
}
581581

582+
constexpr void use_after_free_2() { // both-error {{never produces a constant expression}}
583+
struct X { constexpr void f() {} };
584+
X *p = new X;
585+
delete p;
586+
p->f(); // both-note {{member call on heap allocated object that has been deleted}}
587+
}
588+
582589
#else
583590
/// Make sure we reject this prior to C++20
584591
constexpr int a() { // both-error {{never produces a constant expression}}

clang/test/AST/ByteCode/unions.cpp

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -86,16 +86,15 @@ namespace DefaultInit {
8686

8787
#if __cplusplus >= 202002L
8888
namespace SimpleActivate {
89-
constexpr int foo() { // ref-error {{never produces a constant expression}}
89+
constexpr int foo() { // both-error {{never produces a constant expression}}
9090
union {
9191
int a;
9292
int b;
9393
} Z;
9494

9595
Z.a = 10;
9696
Z.b = 20;
97-
return Z.a; // both-note {{read of member 'a' of union with active member 'b'}} \
98-
// ref-note {{read of member 'a' of union with active member 'b}}
97+
return Z.a; // both-note 2{{read of member 'a' of union with active member 'b'}}
9998
}
10099
static_assert(foo() == 20); // both-error {{not an integral constant expression}} \
101100
// both-note {{in call to}}
@@ -212,11 +211,10 @@ namespace Nested {
212211
int y;
213212
};
214213

215-
constexpr int foo() { // ref-error {{constexpr function never produces a constant expression}}
214+
constexpr int foo() { // both-error {{constexpr function never produces a constant expression}}
216215
U2 u;
217216
u.u.a = 10;
218-
int a = u.y; // both-note {{read of member 'y' of union with active member 'u' is not allowed in a constant expression}} \
219-
// ref-note {{read of member 'y' of union with active member 'u' is not allowed in a constant expression}}
217+
int a = u.y; // both-note 2{{read of member 'y' of union with active member 'u' is not allowed in a constant expression}}
220218

221219
return 1;
222220
}
@@ -230,24 +228,22 @@ namespace Nested {
230228
}
231229
static_assert(foo2() == 10);
232230

233-
constexpr int foo3() { // ref-error {{constexpr function never produces a constant expression}}
231+
constexpr int foo3() { // both-error {{constexpr function never produces a constant expression}}
234232
U2 u;
235233
u.u.a = 10;
236-
int a = u.u.b; // both-note {{read of member 'b' of union with active member 'a' is not allowed in a constant expression}} \
237-
// ref-note {{read of member 'b' of union with active member 'a' is not allowed in a constant expression}}
234+
int a = u.u.b; // both-note 2{{read of member 'b' of union with active member 'a' is not allowed in a constant expression}}
238235

239236
return 1;
240237
}
241238
static_assert(foo3() == 1); // both-error {{not an integral constant expression}} \
242239
// both-note {{in call to}}
243240

244-
constexpr int foo4() { // ref-error {{constexpr function never produces a constant expression}}
241+
constexpr int foo4() { // both-error {{constexpr function never produces a constant expression}}
245242
U2 u;
246243

247244
u.x = 10;
248245

249-
return u.u.a;// both-note {{read of member 'u' of union with active member 'x' is not allowed in a constant expression}} \
250-
// ref-note {{read of member 'u' of union with active member 'x' is not allowed in a constant expression}}
246+
return u.u.a; // both-note 2{{read of member 'u' of union with active member 'x' is not allowed in a constant expression}}
251247
}
252248
static_assert(foo4() == 1); // both-error {{not an integral constant expression}} \
253249
// both-note {{in call to}}

0 commit comments

Comments
 (0)