@@ -576,23 +576,14 @@ bool CheckConst(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
576
576
if (!Ptr.isConst () || Ptr.isMutable ())
577
577
return true ;
578
578
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
-
593
579
if (!Ptr.isBlockPointer ())
594
580
return false ;
595
581
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
+
596
587
const QualType Ty = Ptr.getType ();
597
588
const SourceInfo &Loc = S.Current ->getSource (OpPC);
598
589
S.FFDiag (Loc, diag::note_constexpr_modify_const_type) << Ty;
@@ -1524,6 +1515,9 @@ bool Call(InterpState &S, CodePtr OpPC, const Function *Func,
1524
1515
return false ;
1525
1516
if (Func->isDestructor () && !CheckDestructor (S, OpPC, ThisPtr))
1526
1517
return false ;
1518
+
1519
+ if (Func->isConstructor () || Func->isDestructor ())
1520
+ S.InitializingBlocks .push_back (ThisPtr.block ());
1527
1521
}
1528
1522
1529
1523
if (!Func->isFullyCompiled ())
@@ -1550,16 +1544,21 @@ bool Call(InterpState &S, CodePtr OpPC, const Function *Func,
1550
1544
// Note that we cannot assert(CallResult.hasValue()) here since
1551
1545
// Ret() above only sets the APValue if the curent frame doesn't
1552
1546
// 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 ;
1557
1557
}
1558
1558
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 ;
1563
1562
}
1564
1563
1565
1564
bool CallVirt (InterpState &S, CodePtr OpPC, const Function *Func,
0 commit comments