@@ -221,17 +221,17 @@ static void popArg(InterpState &S, const Expr *Arg) {
221221 TYPE_SWITCH (Ty, S.Stk .discard <T>());
222222}
223223
224- void cleanupAfterFunctionCall (InterpState &S, CodePtr OpPC) {
224+ void cleanupAfterFunctionCall (InterpState &S, CodePtr OpPC,
225+ const Function *Func) {
225226 assert (S.Current );
226- const Function *CurFunc = S.Current ->getFunction ();
227- assert (CurFunc);
227+ assert (Func);
228228
229- if (CurFunc ->isUnevaluatedBuiltin ())
229+ if (Func ->isUnevaluatedBuiltin ())
230230 return ;
231231
232232 // Some builtin functions require us to only look at the call site, since
233233 // the classified parameter types do not match.
234- if (unsigned BID = CurFunc ->getBuiltinID ();
234+ if (unsigned BID = Func ->getBuiltinID ();
235235 BID && S.getASTContext ().BuiltinInfo .hasCustomTypechecking (BID)) {
236236 const auto *CE =
237237 cast<CallExpr>(S.Current ->Caller ->getExpr (S.Current ->getRetPC ()));
@@ -242,7 +242,7 @@ void cleanupAfterFunctionCall(InterpState &S, CodePtr OpPC) {
242242 return ;
243243 }
244244
245- if (S.Current ->Caller && CurFunc ->isVariadic ()) {
245+ if (S.Current ->Caller && Func ->isVariadic ()) {
246246 // CallExpr we're look for is at the return PC of the current function, i.e.
247247 // in the caller.
248248 // This code path should be executed very rarely.
@@ -259,8 +259,8 @@ void cleanupAfterFunctionCall(InterpState &S, CodePtr OpPC) {
259259 } else
260260 assert (false && " Can't get arguments from that expression type" );
261261
262- assert (NumArgs >= CurFunc ->getNumWrittenParams ());
263- NumVarArgs = NumArgs - (CurFunc ->getNumWrittenParams () +
262+ assert (NumArgs >= Func ->getNumWrittenParams ());
263+ NumVarArgs = NumArgs - (Func ->getNumWrittenParams () +
264264 isa<CXXOperatorCallExpr>(CallSite));
265265 for (unsigned I = 0 ; I != NumVarArgs; ++I) {
266266 const Expr *A = Args[NumArgs - 1 - I];
@@ -270,7 +270,8 @@ void cleanupAfterFunctionCall(InterpState &S, CodePtr OpPC) {
270270
271271 // And in any case, remove the fixed parameters (the non-variadic ones)
272272 // at the end.
273- S.Current ->popArgs ();
273+ for (PrimType Ty : Func->args_reverse ())
274+ TYPE_SWITCH (Ty, S.Stk .discard <T>());
274275}
275276
276277bool CheckExtern (InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
@@ -1036,6 +1037,12 @@ bool CallVar(InterpState &S, CodePtr OpPC, const Function *Func,
10361037
10371038bool Call (InterpState &S, CodePtr OpPC, const Function *Func,
10381039 uint32_t VarArgSize) {
1040+ assert (Func);
1041+ auto cleanup = [&]() -> bool {
1042+ cleanupAfterFunctionCall (S, OpPC, Func);
1043+ return false ;
1044+ };
1045+
10391046 if (Func->hasThisPointer ()) {
10401047 size_t ArgSize = Func->getArgSize () + VarArgSize;
10411048 size_t ThisOffset = ArgSize - (Func->hasRVO () ? primSize (PT_Ptr) : 0 );
@@ -1052,22 +1059,22 @@ bool Call(InterpState &S, CodePtr OpPC, const Function *Func,
10521059 assert (ThisPtr.isZero ());
10531060 } else {
10541061 if (!CheckInvoke (S, OpPC, ThisPtr))
1055- return false ;
1062+ return cleanup () ;
10561063 }
10571064 }
10581065
10591066 if (!CheckCallable (S, OpPC, Func))
1060- return false ;
1067+ return cleanup () ;
10611068
10621069 // FIXME: The isConstructor() check here is not always right. The current
10631070 // constant evaluator is somewhat inconsistent in when it allows a function
10641071 // call when checking for a constant expression.
10651072 if (Func->hasThisPointer () && S.checkingPotentialConstantExpression () &&
10661073 !Func->isConstructor ())
1067- return false ;
1074+ return cleanup () ;
10681075
10691076 if (!CheckCallDepth (S, OpPC))
1070- return false ;
1077+ return cleanup () ;
10711078
10721079 auto NewFrame = std::make_unique<InterpFrame>(S, Func, OpPC, VarArgSize);
10731080 InterpFrame *FrameBefore = S.Current ;
0 commit comments