[clang] [clang][bytecode] Keep a list of initializing blocks in InterpState (PR #148120)
Timm Baeder via cfe-commits
cfe-commits at lists.llvm.org
Thu Jul 10 23:50:29 PDT 2025
https://github.com/tbaederr created https://github.com/llvm/llvm-project/pull/148120
So we can know what blocks we're currently running constructors or destructors for.
>From 047fa0e0bc313548227c724b5b32ce862199f301 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Timm=20B=C3=A4der?= <tbaeder at redhat.com>
Date: Thu, 10 Jul 2025 20:46:52 +0200
Subject: [PATCH] [clang][bytecode] Keep a list of initializing blocks in
InterpState
So we can know what blocks we're currently running constructors or
destructors for.
---
clang/lib/AST/ByteCode/Interp.cpp | 43 ++++++++++++++--------------
clang/lib/AST/ByteCode/InterpState.h | 4 +++
2 files changed, 25 insertions(+), 22 deletions(-)
diff --git a/clang/lib/AST/ByteCode/Interp.cpp b/clang/lib/AST/ByteCode/Interp.cpp
index be77657acabcc..18b84fa48fb1d 100644
--- a/clang/lib/AST/ByteCode/Interp.cpp
+++ b/clang/lib/AST/ByteCode/Interp.cpp
@@ -576,23 +576,14 @@ bool CheckConst(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
if (!Ptr.isConst() || Ptr.isMutable())
return true;
- // The This pointer is writable in constructors and destructors,
- // even if isConst() returns true.
- // TODO(perf): We could be hitting this code path quite a lot in complex
- // constructors. Is there a better way to do this?
- if (S.Current->getFunction()) {
- for (const InterpFrame *Frame = S.Current; Frame; Frame = Frame->Caller) {
- if (const Function *Func = Frame->getFunction();
- Func && (Func->isConstructor() || Func->isDestructor()) &&
- Ptr.block() == Frame->getThis().block()) {
- return true;
- }
- }
- }
-
if (!Ptr.isBlockPointer())
return false;
+ // The This pointer is writable in constructors and destructors,
+ // even if isConst() returns true.
+ if (llvm::find(S.InitializingBlocks, Ptr.block()))
+ return true;
+
const QualType Ty = Ptr.getType();
const SourceInfo &Loc = S.Current->getSource(OpPC);
S.FFDiag(Loc, diag::note_constexpr_modify_const_type) << Ty;
@@ -1524,6 +1515,9 @@ bool Call(InterpState &S, CodePtr OpPC, const Function *Func,
return false;
if (Func->isDestructor() && !CheckDestructor(S, OpPC, ThisPtr))
return false;
+
+ if (Func->isConstructor() || Func->isDestructor())
+ S.InitializingBlocks.push_back(ThisPtr.block());
}
if (!Func->isFullyCompiled())
@@ -1550,16 +1544,21 @@ bool Call(InterpState &S, CodePtr OpPC, const Function *Func,
// Note that we cannot assert(CallResult.hasValue()) here since
// Ret() above only sets the APValue if the curent frame doesn't
// have a caller set.
- if (Interpret(S)) {
- NewFrame.release(); // Frame was delete'd already.
- assert(S.Current == FrameBefore);
- return true;
+ bool Success = Interpret(S);
+ // Remove initializing block again.
+ if (Func->isConstructor() || Func->isDestructor())
+ S.InitializingBlocks.pop_back();
+
+ if (!Success) {
+ // Interpreting the function failed somehow. Reset to
+ // previous state.
+ S.Current = FrameBefore;
+ return false;
}
- // Interpreting the function failed somehow. Reset to
- // previous state.
- S.Current = FrameBefore;
- return false;
+ NewFrame.release(); // Frame was delete'd already.
+ assert(S.Current == FrameBefore);
+ return true;
}
bool CallVirt(InterpState &S, CodePtr OpPC, const Function *Func,
diff --git a/clang/lib/AST/ByteCode/InterpState.h b/clang/lib/AST/ByteCode/InterpState.h
index 08765561985e2..861e4c38049ab 100644
--- a/clang/lib/AST/ByteCode/InterpState.h
+++ b/clang/lib/AST/ByteCode/InterpState.h
@@ -190,6 +190,10 @@ class InterpState final : public State, public SourceMapper {
std::pair<const Expr *, const LifetimeExtendedTemporaryDecl *>>
SeenGlobalTemporaries;
+ /// List of blocks we're currently running either constructors or destructors
+ /// for.
+ llvm::SmallVector<const Block *> InitializingBlocks;
+
mutable llvm::BumpPtrAllocator Allocator;
};
More information about the cfe-commits
mailing list