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}} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits