[clang] [clang][bytecode] Use in `VarDecl::evaluateDestruction()` (PR #199646)
Timm Baeder via cfe-commits
cfe-commits at lists.llvm.org
Tue May 26 03:20:22 PDT 2026
https://github.com/tbaederr updated https://github.com/llvm/llvm-project/pull/199646
>From f01289f8ae1c71ab1c91bb6818b432f3840ae201 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Timm=20B=C3=A4der?= <tbaeder at redhat.com>
Date: Tue, 26 May 2026 10:15:41 +0200
Subject: [PATCH] dtor
---
clang/lib/AST/ByteCode/ByteCodeEmitter.h | 1 +
clang/lib/AST/ByteCode/Compiler.cpp | 35 ++++++++++++++++++++++--
clang/lib/AST/ByteCode/Compiler.h | 1 +
clang/lib/AST/ByteCode/Context.cpp | 16 +++++++++++
clang/lib/AST/ByteCode/Context.h | 3 ++
clang/lib/AST/ByteCode/EvalEmitter.cpp | 12 ++++++++
clang/lib/AST/ByteCode/EvalEmitter.h | 2 ++
clang/lib/AST/ExprConstant.cpp | 20 ++++++++++++--
8 files changed, 85 insertions(+), 5 deletions(-)
diff --git a/clang/lib/AST/ByteCode/ByteCodeEmitter.h b/clang/lib/AST/ByteCode/ByteCodeEmitter.h
index e3aa3c940de47..4b42b7eb4063b 100644
--- a/clang/lib/AST/ByteCode/ByteCodeEmitter.h
+++ b/clang/lib/AST/ByteCode/ByteCodeEmitter.h
@@ -49,6 +49,7 @@ class ByteCodeEmitter {
virtual bool visitLValueExpr(const Expr *E, bool DestroyToplevelScope) = 0;
virtual bool visitDeclAndReturn(const VarDecl *VD, const Expr *Init,
bool ConstantContext) = 0;
+ virtual bool visitDtorCall(const VarDecl *VD, const APValue &) = 0;
virtual bool visit(const Expr *E) = 0;
virtual bool emitBool(bool V, const Expr *E) = 0;
diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp
index 4d13cd7139f83..9a41856195915 100644
--- a/clang/lib/AST/ByteCode/Compiler.cpp
+++ b/clang/lib/AST/ByteCode/Compiler.cpp
@@ -5378,6 +5378,31 @@ VarCreationState Compiler<Emitter>::visitVarDecl(const VarDecl *VD,
return false;
}
+template <class Emitter>
+bool Compiler<Emitter>::visitDtorCall(const VarDecl *VD, const APValue &Value) {
+ assert(!canClassify(VD->getType()));
+
+ DeclScope<Emitter> LocalScope(this, VD);
+ // Create a local variable to use as the instance.
+ QualType Ty = VD->getType();
+ Descriptor *D = P.createDescriptor(
+ VD, Ty.getTypePtr(), Descriptor::InlineDescMD, /*IsConst=*/false,
+ /*IsTemporary=*/false, /*IsMutable=*/false,
+ /*IsVolatile=*/Ty.isVolatileQualified(), nullptr);
+ if (!D)
+ return false;
+
+ Scope::Local Local = this->createLocal(D);
+ Locals.insert({VD, Local});
+ VarScope->addForScopeKind(Local, ScopeKind::Block);
+
+ if (!this->emitGetPtrLocal(Local.Offset, VD))
+ return false;
+ if (!this->visitAPValueInitializer(Value, nullptr, Ty))
+ return false;
+ return this->emitDestructionPop(D, VD);
+}
+
template <class Emitter>
bool Compiler<Emitter>::visitAPValue(const APValue &Val, PrimType ValType,
const Expr *E) {
@@ -5533,11 +5558,17 @@ bool Compiler<Emitter>::visitAPValueInitializer(const APValue &Val,
return this->emitPopPtr(E);
}
if (Val.isArray()) {
+ unsigned InitializedElems = Val.getArrayInitializedElts();
const auto *ArrType = T->getAsArrayTypeUnsafe();
QualType ElemType = ArrType->getElementType();
+ OptPrimType ElemT = classify(ElemType);
+
for (unsigned A = 0, AN = Val.getArraySize(); A != AN; ++A) {
- const APValue &Elem = Val.getArrayInitializedElt(A);
- if (OptPrimType ElemT = classify(ElemType)) {
+ const APValue &Elem = A >= InitializedElems
+ ? Val.getArrayFiller()
+ : Val.getArrayInitializedElt(A);
+
+ if (ElemT) {
if (!this->visitAPValue(Elem, *ElemT, E))
return false;
if (!this->emitInitElem(*ElemT, A, E))
diff --git a/clang/lib/AST/ByteCode/Compiler.h b/clang/lib/AST/ByteCode/Compiler.h
index 235024ca97ce0..1654cd96d4261 100644
--- a/clang/lib/AST/ByteCode/Compiler.h
+++ b/clang/lib/AST/ByteCode/Compiler.h
@@ -259,6 +259,7 @@ class Compiler : public ConstStmtVisitor<Compiler<Emitter>, bool>,
bool visitDeclAndReturn(const VarDecl *VD, const Expr *Init,
bool ConstantContext) override;
+ bool visitDtorCall(const VarDecl *VD, const APValue &Value) override;
protected:
/// Emits scope cleanup instructions.
diff --git a/clang/lib/AST/ByteCode/Context.cpp b/clang/lib/AST/ByteCode/Context.cpp
index 35959715946c3..4beb35a9a7b43 100644
--- a/clang/lib/AST/ByteCode/Context.cpp
+++ b/clang/lib/AST/ByteCode/Context.cpp
@@ -161,6 +161,22 @@ bool Context::evaluateAsInitializer(State &Parent, const VarDecl *VD,
return true;
}
+bool Context::evaluateDestruction(State &Parent, const VarDecl *VD,
+ APValue Value) {
+ assert(Stk.empty());
+ Compiler<EvalEmitter> C(*this, *P, Parent, Stk);
+
+ auto Res = C.interpretDestructor(VD, Value);
+
+ if (Res.isInvalid()) {
+ C.cleanup();
+ Stk.clear();
+ return false;
+ }
+
+ return true;
+}
+
template <typename ResultT>
bool Context::evaluateStringRepr(State &Parent, const Expr *SizeExpr,
const Expr *PtrExpr, ResultT &Result) {
diff --git a/clang/lib/AST/ByteCode/Context.h b/clang/lib/AST/ByteCode/Context.h
index 63709f7abfdd7..9a66226807e4e 100644
--- a/clang/lib/AST/ByteCode/Context.h
+++ b/clang/lib/AST/ByteCode/Context.h
@@ -68,6 +68,9 @@ class Context final {
bool evaluateAsInitializer(State &Parent, const VarDecl *VD, const Expr *Init,
APValue &Result);
+ /// Evaluates the destruction of a variable.
+ bool evaluateDestruction(State &Parent, const VarDecl *VD, APValue Value);
+
bool evaluateCharRange(State &Parent, const Expr *SizeExpr,
const Expr *PtrExpr, APValue &Result);
bool evaluateCharRange(State &Parent, const Expr *SizeExpr,
diff --git a/clang/lib/AST/ByteCode/EvalEmitter.cpp b/clang/lib/AST/ByteCode/EvalEmitter.cpp
index d3acaa406af51..3e1aade65afc8 100644
--- a/clang/lib/AST/ByteCode/EvalEmitter.cpp
+++ b/clang/lib/AST/ByteCode/EvalEmitter.cpp
@@ -73,6 +73,18 @@ EvaluationResult EvalEmitter::interpretDecl(const VarDecl *VD, const Expr *Init,
return std::move(this->EvalResult);
}
+EvaluationResult EvalEmitter::interpretDestructor(const VarDecl *VD,
+ const APValue &Value) {
+ assert(VD);
+ S.setEvalLocation(VD->getLocation());
+ EvalResult.setSource(VD);
+
+ if (!this->visitDtorCall(VD, Value))
+ EvalResult.setInvalid();
+
+ return std::move(this->EvalResult);
+}
+
EvaluationResult EvalEmitter::interpretAsPointer(const Expr *E,
PtrCallback PtrCB) {
S.setEvalLocation(E->getExprLoc());
diff --git a/clang/lib/AST/ByteCode/EvalEmitter.h b/clang/lib/AST/ByteCode/EvalEmitter.h
index ce5825eef3607..6fd50da8cad76 100644
--- a/clang/lib/AST/ByteCode/EvalEmitter.h
+++ b/clang/lib/AST/ByteCode/EvalEmitter.h
@@ -40,6 +40,7 @@ class EvalEmitter : public SourceMapper {
bool DestroyToplevelScope = false);
EvaluationResult interpretDecl(const VarDecl *VD, const Expr *Init,
bool CheckFullyInitialized);
+ EvaluationResult interpretDestructor(const VarDecl *VD, const APValue &Value);
/// Interpret the given Expr to a Pointer.
EvaluationResult interpretAsPointer(const Expr *E, PtrCallback PtrCB);
EvaluationResult interpretAsLValuePointer(const Expr *E, PtrCallback PtrCB);
@@ -65,6 +66,7 @@ class EvalEmitter : public SourceMapper {
virtual bool visitLValueExpr(const Expr *E, bool DestroyToplevelScope) = 0;
virtual bool visitDeclAndReturn(const VarDecl *VD, const Expr *Init,
bool ConstantContext) = 0;
+ virtual bool visitDtorCall(const VarDecl *VD, const APValue &Value) = 0;
virtual bool visitFunc(const FunctionDecl *F) = 0;
virtual bool visit(const Expr *E) = 0;
virtual bool emitBool(bool V, const Expr *E) = 0;
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 0522d6f1dc944..b1cea63a8ede6 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -21554,6 +21554,7 @@ bool VarDecl::evaluateDestruction(
// Only treat the destruction as constant destruction if we formally have
// constant initialization (or are usable in a constant expression).
bool IsConstantDestruction = hasConstantInitialization();
+ ASTContext &Ctx = getASTContext();
// Make a copy of the value for the destructor to mutate, if we know it.
// Otherwise, treat the value as default-initialized; if the destructor works
@@ -21564,9 +21565,22 @@ bool VarDecl::evaluateDestruction(
else if (!handleDefaultInitValue(getType(), DestroyedValue))
return false;
- if (!EvaluateDestruction(getASTContext(), this, std::move(DestroyedValue),
- getType(), getLocation(), EStatus,
- IsConstantDestruction) ||
+ if (Ctx.getLangOpts().EnableNewConstInterp) {
+ EvalInfo Info(Ctx, EStatus,
+ IsConstantDestruction ? EvaluationMode::ConstantExpression
+ : EvaluationMode::ConstantFold);
+ Info.setEvaluatingDecl(this, DestroyedValue,
+ EvalInfo::EvaluatingDeclKind::Dtor);
+ Info.InConstantContext = IsConstantDestruction;
+ if (!Ctx.getInterpContext().evaluateDestruction(Info, this,
+ std::move(DestroyedValue)))
+ return false;
+ ensureEvaluatedStmt()->HasConstantDestruction = true;
+ return true;
+ }
+
+ if (!EvaluateDestruction(Ctx, this, std::move(DestroyedValue), getType(),
+ getLocation(), EStatus, IsConstantDestruction) ||
EStatus.HasSideEffects)
return false;
More information about the cfe-commits
mailing list