https://github.com/tbaederr created https://github.com/llvm/llvm-project/pull/199646
Fixes https://github.com/llvm/llvm-project/issues/146832 >From cc1baea8b519125079839d15b607e78264be0ad1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timm=20B=C3=A4der?= <[email protected]> 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 | 34 ++++++++++++++++++++++-- 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 | 13 +++++++++ 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..f154573233252 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) { @@ -5535,9 +5560,14 @@ bool Compiler<Emitter>::visitAPValueInitializer(const APValue &Val, if (Val.isArray()) { 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 >= Val.getArrayInitializedElts() + ? 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..ce7a067e0490e 100644 --- a/clang/lib/AST/ByteCode/EvalEmitter.cpp +++ b/clang/lib/AST/ByteCode/EvalEmitter.cpp @@ -73,6 +73,19 @@ 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; _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
