https://github.com/tbaederr created https://github.com/llvm/llvm-project/pull/207959
Rename the `EndLifetimePop` op (which was only used for pseudo dtors) to `PseudoDtor` and call `checkDestructor()` in there, so we get the full suite of checks. >From aa29b0c46e6934d122120c22af97ab1caa6362a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timm=20B=C3=A4der?= <[email protected]> Date: Tue, 7 Jul 2026 12:18:34 +0200 Subject: [PATCH] [clang][bytecode] Add more checks for pseudo dtors Rename the `EndLifetimePop` op (which was only used for pseudo dtors) to `PseudoDtor` and call `checkDestructor()` in there, so we get the full suite of checks. --- clang/lib/AST/ByteCode/Compiler.cpp | 2 +- clang/lib/AST/ByteCode/Interp.cpp | 9 ++++----- clang/lib/AST/ByteCode/Interp.h | 6 +++--- clang/lib/AST/ByteCode/Opcodes.td | 2 +- clang/test/AST/ByteCode/cxx2a.cpp | 17 ++++++++++++++++- 5 files changed, 25 insertions(+), 11 deletions(-) diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp index b4468c94ff675..48f5ee8115429 100644 --- a/clang/lib/AST/ByteCode/Compiler.cpp +++ b/clang/lib/AST/ByteCode/Compiler.cpp @@ -6189,7 +6189,7 @@ bool Compiler<Emitter>::VisitCallExpr(const CallExpr *E) { return this->discard(Base); if (!this->visit(Base)) return false; - return this->emitEndLifetimePop(E); + return this->emitPseudoDtor(E); } else if (!FuncDecl) { const Expr *Callee = E->getCallee(); CalleeOffset = diff --git a/clang/lib/AST/ByteCode/Interp.cpp b/clang/lib/AST/ByteCode/Interp.cpp index ce044e7b47e11..8a6d024eda3af 100644 --- a/clang/lib/AST/ByteCode/Interp.cpp +++ b/clang/lib/AST/ByteCode/Interp.cpp @@ -1719,7 +1719,7 @@ static bool diagnoseOutOfLifetimeDestroy(InterpState &S, CodePtr OpPC, return false; } -bool CheckDestructor(InterpState &S, CodePtr OpPC, const Pointer &Ptr) { +bool checkDestructor(InterpState &S, CodePtr OpPC, const Pointer &Ptr) { if (!CheckLive(S, OpPC, Ptr, AK_Destroy)) return false; if (!CheckTemporary(S, OpPC, Ptr.block(), AK_Destroy)) @@ -1920,7 +1920,7 @@ bool Call(InterpState &S, CodePtr OpPC, const Function *Func, if (Func->isConstructor() && !checkConstructor(S, OpPC, Func, ThisPtr)) return false; - if (Func->isDestructor() && !CheckDestructor(S, OpPC, ThisPtr)) + if (Func->isDestructor() && !checkDestructor(S, OpPC, ThisPtr)) return false; InstancePtrTracked = (Func->isConstructor() || Func->isDestructor()); @@ -2448,11 +2448,10 @@ bool EndLifetime(InterpState &S, CodePtr OpPC) { } /// Ends the lifetime of the pop'd pointer. -bool EndLifetimePop(InterpState &S, CodePtr OpPC) { +bool PseudoDtor(InterpState &S, CodePtr OpPC) { const auto &Ptr = S.Stk.pop<Pointer>(); - if (Ptr.isBlockPointer() && !CheckDummy(S, OpPC, Ptr.block(), AK_Destroy)) + if (!checkDestructor(S, OpPC, Ptr)) return false; - setLifeStateRecurse(Ptr.view().narrow(), Lifetime::Ended); return true; } diff --git a/clang/lib/AST/ByteCode/Interp.h b/clang/lib/AST/ByteCode/Interp.h index d16a00414f45a..201679017c98b 100644 --- a/clang/lib/AST/ByteCode/Interp.h +++ b/clang/lib/AST/ByteCode/Interp.h @@ -132,7 +132,7 @@ bool InvalidShuffleVectorIndex(InterpState &S, CodePtr OpPC, uint32_t Index); bool CheckBitCast(InterpState &S, CodePtr OpPC, bool HasIndeterminateBits, bool TargetIsUCharOrByte); bool CheckBCPResult(InterpState &S, const Pointer &Ptr); -bool CheckDestructor(InterpState &S, CodePtr OpPC, const Pointer &Ptr); +bool checkDestructor(InterpState &S, CodePtr OpPC, const Pointer &Ptr); bool CheckFunctionDecl(InterpState &S, CodePtr OpPC, const FunctionDecl *FD); bool CheckBitCast(InterpState &S, CodePtr OpPC, const Type *TargetType, bool SrcIsVoidPtr); @@ -1627,7 +1627,7 @@ bool GetLocal(InterpState &S, CodePtr OpPC, uint32_t I) { } bool EndLifetime(InterpState &S, CodePtr OpPC); -bool EndLifetimePop(InterpState &S, CodePtr OpPC); +bool PseudoDtor(InterpState &S, CodePtr OpPC); bool StartThisLifetime(InterpState &S); bool StartThisLifetime1(InterpState &S); bool MarkDestroyed(InterpState &S, CodePtr OpPC); @@ -4070,7 +4070,7 @@ bool DiagTypeid(InterpState &S, CodePtr OpPC); inline bool CheckDestruction(InterpState &S, CodePtr OpPC) { const auto &Ptr = S.Stk.peek<Pointer>(); - return CheckDestructor(S, OpPC, Ptr); + return checkDestructor(S, OpPC, Ptr); } //===----------------------------------------------------------------------===// diff --git a/clang/lib/AST/ByteCode/Opcodes.td b/clang/lib/AST/ByteCode/Opcodes.td index 577c8523ab6c3..1705ad9d9d24b 100644 --- a/clang/lib/AST/ByteCode/Opcodes.td +++ b/clang/lib/AST/ByteCode/Opcodes.td @@ -457,7 +457,7 @@ def SetLocal : AccessOpcode { let NeedsOpPC = 0; } -def EndLifetimePop : Opcode; +def PseudoDtor : Opcode; def EndLifetime : Opcode; def MarkDestroyed : Opcode; def StartThisLifetime : Opcode { diff --git a/clang/test/AST/ByteCode/cxx2a.cpp b/clang/test/AST/ByteCode/cxx2a.cpp index 78769a4def5b0..cc9ec1666440c 100644 --- a/clang/test/AST/ByteCode/cxx2a.cpp +++ b/clang/test/AST/ByteCode/cxx2a.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -std=c++2a -fsyntax-only -fcxx-exceptions -verify=ref,both %s +// RUN: %clang_cc1 -std=c++2a -fsyntax-only -fcxx-exceptions -verify=ref,both %s // RUN: %clang_cc1 -std=c++2a -fsyntax-only -fcxx-exceptions -verify=expected,both %s -fexperimental-new-constant-interpreter @@ -254,3 +254,18 @@ namespace DependentRequiresExpr { template <class T> using P = p<T>::type; // both-note {{while checking a default template argument}} } + +namespace PseudoDtorOnGlobal { + struct A { + int m; + mutable int n; + constexpr int f() const { return m; } + constexpr int g() const { return n; } + }; + + constexpr A a = {1, 2}; + using T = int; + constexpr void destroy2() { // both-error {{never produces a constant expression}} + a.m.~T(); // both-note {{cannot modify an object that is visible outside}} + } +} _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
