[clang] [clang][bytecode] Add more checks for pseudo dtors (PR #207959)
Timm Baeder via cfe-commits
cfe-commits at lists.llvm.org
Tue Jul 7 03:22:42 PDT 2026
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?= <tbaeder at redhat.com>
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}}
+ }
+}
More information about the cfe-commits
mailing list