@@ -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
15651564bool CallVirt (InterpState &S, CodePtr OpPC, const Function *Func,
0 commit comments