[clang] df11ee2 - [clang][bytecode] Diagnose member calls on deleted blocks (#106529)
via cfe-commits
cfe-commits at lists.llvm.org
Thu Aug 29 06:23:03 PDT 2024
Author: Timm Baeder
Date: 2024-08-29T15:22:59+02:00
New Revision: df11ee213e43ae373d1357939cf14ea37d547110
URL: https://github.com/llvm/llvm-project/commit/df11ee213e43ae373d1357939cf14ea37d547110
DIFF: https://github.com/llvm/llvm-project/commit/df11ee213e43ae373d1357939cf14ea37d547110.diff
LOG: [clang][bytecode] Diagnose member calls on deleted blocks (#106529)
This requires a bit of restructuring of ctor calls when checking for a
potential constant expression.
Added:
Modified:
clang/lib/AST/ByteCode/Interp.cpp
clang/lib/AST/ByteCode/Interp.h
clang/lib/AST/ByteCode/InterpBlock.cpp
clang/lib/AST/ByteCode/Pointer.h
clang/test/AST/ByteCode/new-delete.cpp
clang/test/AST/ByteCode/unions.cpp
Removed:
################################################################################
diff --git a/clang/lib/AST/ByteCode/Interp.cpp b/clang/lib/AST/ByteCode/Interp.cpp
index 0cd106b74d1504..42012767c22332 100644
--- a/clang/lib/AST/ByteCode/Interp.cpp
+++ b/clang/lib/AST/ByteCode/Interp.cpp
@@ -305,14 +305,18 @@ bool CheckLive(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
if (!Ptr.isLive()) {
const auto &Src = S.Current->getSource(OpPC);
- bool IsTemp = Ptr.isTemporary();
- S.FFDiag(Src, diag::note_constexpr_lifetime_ended, 1) << AK << !IsTemp;
+ if (Ptr.isDynamic()) {
+ S.FFDiag(Src, diag::note_constexpr_access_deleted_object) << AK;
+ } else {
+ bool IsTemp = Ptr.isTemporary();
+ S.FFDiag(Src, diag::note_constexpr_lifetime_ended, 1) << AK << !IsTemp;
- if (IsTemp)
- S.Note(Ptr.getDeclLoc(), diag::note_constexpr_temporary_here);
- else
- S.Note(Ptr.getDeclLoc(), diag::note_declared_at);
+ if (IsTemp)
+ S.Note(Ptr.getDeclLoc(), diag::note_constexpr_temporary_here);
+ else
+ S.Note(Ptr.getDeclLoc(), diag::note_declared_at);
+ }
return false;
}
diff --git a/clang/lib/AST/ByteCode/Interp.h b/clang/lib/AST/ByteCode/Interp.h
index cfd9b1843d0407..f8af51b71101d2 100644
--- a/clang/lib/AST/ByteCode/Interp.h
+++ b/clang/lib/AST/ByteCode/Interp.h
@@ -2630,7 +2630,11 @@ inline bool Call(InterpState &S, CodePtr OpPC, const Function *Func,
if (!CheckCallable(S, OpPC, Func))
return false;
- if (Func->hasThisPointer() && S.checkingPotentialConstantExpression())
+ // FIXME: The isConstructor() check here is not always right. The current
+ // constant evaluator is somewhat inconsistent in when it allows a function
+ // call when checking for a constant expression.
+ if (Func->hasThisPointer() && S.checkingPotentialConstantExpression() &&
+ !Func->isConstructor())
return false;
if (!CheckCallDepth(S, OpPC))
diff --git a/clang/lib/AST/ByteCode/InterpBlock.cpp b/clang/lib/AST/ByteCode/InterpBlock.cpp
index 7a3962290edb4e..0ce88ca7e52365 100644
--- a/clang/lib/AST/ByteCode/InterpBlock.cpp
+++ b/clang/lib/AST/ByteCode/InterpBlock.cpp
@@ -110,6 +110,8 @@ DeadBlock::DeadBlock(DeadBlock *&Root, Block *Blk)
Prev = nullptr;
Root = this;
+ B.IsDynamic = Blk->IsDynamic;
+
// Transfer pointers.
B.Pointers = Blk->Pointers;
for (Pointer *P = Blk->Pointers; P; P = P->Next)
diff --git a/clang/lib/AST/ByteCode/Pointer.h b/clang/lib/AST/ByteCode/Pointer.h
index 27ac33616f5a8b..ef90e6e0dd7bd1 100644
--- a/clang/lib/AST/ByteCode/Pointer.h
+++ b/clang/lib/AST/ByteCode/Pointer.h
@@ -491,6 +491,14 @@ class Pointer {
}
return false;
}
+ /// Checks if the storage has been dynamically allocated.
+ bool isDynamic() const {
+ if (isBlockPointer()) {
+ assert(asBlockPointer().Pointee);
+ return asBlockPointer().Pointee->isDynamic();
+ }
+ return false;
+ }
/// Checks if the storage is a static temporary.
bool isStaticTemporary() const { return isStatic() && isTemporary(); }
diff --git a/clang/test/AST/ByteCode/new-delete.cpp b/clang/test/AST/ByteCode/new-delete.cpp
index d733e3182fd59c..145bb366710f9b 100644
--- a/clang/test/AST/ByteCode/new-delete.cpp
+++ b/clang/test/AST/ByteCode/new-delete.cpp
@@ -579,6 +579,13 @@ namespace CastedDelete {
// expected-note {{in call to}}
}
+constexpr void use_after_free_2() { // both-error {{never produces a constant expression}}
+ struct X { constexpr void f() {} };
+ X *p = new X;
+ delete p;
+ p->f(); // both-note {{member call on heap allocated object that has been deleted}}
+}
+
#else
/// Make sure we reject this prior to C++20
constexpr int a() { // both-error {{never produces a constant expression}}
diff --git a/clang/test/AST/ByteCode/unions.cpp b/clang/test/AST/ByteCode/unions.cpp
index 35b4a520baa269..7b39bb1bb9316e 100644
--- a/clang/test/AST/ByteCode/unions.cpp
+++ b/clang/test/AST/ByteCode/unions.cpp
@@ -86,7 +86,7 @@ namespace DefaultInit {
#if __cplusplus >= 202002L
namespace SimpleActivate {
- constexpr int foo() { // ref-error {{never produces a constant expression}}
+ constexpr int foo() { // both-error {{never produces a constant expression}}
union {
int a;
int b;
@@ -94,8 +94,7 @@ namespace SimpleActivate {
Z.a = 10;
Z.b = 20;
- return Z.a; // both-note {{read of member 'a' of union with active member 'b'}} \
- // ref-note {{read of member 'a' of union with active member 'b}}
+ return Z.a; // both-note 2{{read of member 'a' of union with active member 'b'}}
}
static_assert(foo() == 20); // both-error {{not an integral constant expression}} \
// both-note {{in call to}}
@@ -212,11 +211,10 @@ namespace Nested {
int y;
};
- constexpr int foo() { // ref-error {{constexpr function never produces a constant expression}}
+ constexpr int foo() { // both-error {{constexpr function never produces a constant expression}}
U2 u;
u.u.a = 10;
- int a = u.y; // both-note {{read of member 'y' of union with active member 'u' is not allowed in a constant expression}} \
- // ref-note {{read of member 'y' of union with active member 'u' is not allowed in a constant expression}}
+ int a = u.y; // both-note 2{{read of member 'y' of union with active member 'u' is not allowed in a constant expression}}
return 1;
}
@@ -230,24 +228,22 @@ namespace Nested {
}
static_assert(foo2() == 10);
- constexpr int foo3() { // ref-error {{constexpr function never produces a constant expression}}
+ constexpr int foo3() { // both-error {{constexpr function never produces a constant expression}}
U2 u;
u.u.a = 10;
- int a = u.u.b; // both-note {{read of member 'b' of union with active member 'a' is not allowed in a constant expression}} \
- // ref-note {{read of member 'b' of union with active member 'a' is not allowed in a constant expression}}
+ 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}}
return 1;
}
static_assert(foo3() == 1); // both-error {{not an integral constant expression}} \
// both-note {{in call to}}
- constexpr int foo4() { // ref-error {{constexpr function never produces a constant expression}}
+ constexpr int foo4() { // both-error {{constexpr function never produces a constant expression}}
U2 u;
u.x = 10;
- return u.u.a;// both-note {{read of member 'u' of union with active member 'x' is not allowed in a constant expression}} \
- // ref-note {{read of member 'u' of union with active member 'x' is not allowed in a constant expression}}
+ return u.u.a; // both-note 2{{read of member 'u' of union with active member 'x' is not allowed in a constant expression}}
}
static_assert(foo4() == 1); // both-error {{not an integral constant expression}} \
// both-note {{in call to}}
More information about the cfe-commits
mailing list