Skip to content

Commit 0e5f9f6

Browse files
authored
[clang][bytecode] Keep a list of initializing blocks in InterpState (#148120)
So we can know what blocks we're currently running constructors or destructors for.
1 parent a9102f5 commit 0e5f9f6

File tree

2 files changed

+25
-22
lines changed

2 files changed

+25
-22
lines changed

clang/lib/AST/ByteCode/Interp.cpp

Lines changed: 21 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -576,23 +576,14 @@ bool CheckConst(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
576576
if (!Ptr.isConst() || Ptr.isMutable())
577577
return true;
578578

579-
// The This pointer is writable in constructors and destructors,
580-
// even if isConst() returns true.
581-
// TODO(perf): We could be hitting this code path quite a lot in complex
582-
// constructors. Is there a better way to do this?
583-
if (S.Current->getFunction()) {
584-
for (const InterpFrame *Frame = S.Current; Frame; Frame = Frame->Caller) {
585-
if (const Function *Func = Frame->getFunction();
586-
Func && (Func->isConstructor() || Func->isDestructor()) &&
587-
Ptr.block() == Frame->getThis().block()) {
588-
return true;
589-
}
590-
}
591-
}
592-
593579
if (!Ptr.isBlockPointer())
594580
return false;
595581

582+
// The This pointer is writable in constructors and destructors,
583+
// even if isConst() returns true.
584+
if (llvm::find(S.InitializingBlocks, Ptr.block()))
585+
return true;
586+
596587
const QualType Ty = Ptr.getType();
597588
const SourceInfo &Loc = S.Current->getSource(OpPC);
598589
S.FFDiag(Loc, diag::note_constexpr_modify_const_type) << Ty;
@@ -1524,6 +1515,9 @@ bool Call(InterpState &S, CodePtr OpPC, const Function *Func,
15241515
return false;
15251516
if (Func->isDestructor() && !CheckDestructor(S, OpPC, ThisPtr))
15261517
return false;
1518+
1519+
if (Func->isConstructor() || Func->isDestructor())
1520+
S.InitializingBlocks.push_back(ThisPtr.block());
15271521
}
15281522

15291523
if (!Func->isFullyCompiled())
@@ -1550,16 +1544,21 @@ bool Call(InterpState &S, CodePtr OpPC, const Function *Func,
15501544
// Note that we cannot assert(CallResult.hasValue()) here since
15511545
// Ret() above only sets the APValue if the curent frame doesn't
15521546
// have a caller set.
1553-
if (Interpret(S)) {
1554-
NewFrame.release(); // Frame was delete'd already.
1555-
assert(S.Current == FrameBefore);
1556-
return true;
1547+
bool Success = Interpret(S);
1548+
// Remove initializing block again.
1549+
if (Func->isConstructor() || Func->isDestructor())
1550+
S.InitializingBlocks.pop_back();
1551+
1552+
if (!Success) {
1553+
// Interpreting the function failed somehow. Reset to
1554+
// previous state.
1555+
S.Current = FrameBefore;
1556+
return false;
15571557
}
15581558

1559-
// Interpreting the function failed somehow. Reset to
1560-
// previous state.
1561-
S.Current = FrameBefore;
1562-
return false;
1559+
NewFrame.release(); // Frame was delete'd already.
1560+
assert(S.Current == FrameBefore);
1561+
return true;
15631562
}
15641563

15651564
bool CallVirt(InterpState &S, CodePtr OpPC, const Function *Func,

clang/lib/AST/ByteCode/InterpState.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,10 @@ class InterpState final : public State, public SourceMapper {
190190
std::pair<const Expr *, const LifetimeExtendedTemporaryDecl *>>
191191
SeenGlobalTemporaries;
192192

193+
/// List of blocks we're currently running either constructors or destructors
194+
/// for.
195+
llvm::SmallVector<const Block *> InitializingBlocks;
196+
193197
mutable llvm::BumpPtrAllocator Allocator;
194198
};
195199

0 commit comments

Comments
 (0)