forked from aniani/vim
patch 9.0.0397: :defer not tested with exceptions and ":qa!"
Problem: :defer not tested with exceptions and ":qa!". Solution: Test :defer works when exceptions are thrown and when ":qa!" is used. Invoke the deferred calls on exit.
This commit is contained in:
@@ -5171,13 +5171,7 @@ on_fatal_error:
|
||||
done:
|
||||
ret = OK;
|
||||
theend:
|
||||
{
|
||||
dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data)
|
||||
+ ectx->ec_dfunc_idx;
|
||||
|
||||
if (dfunc->df_defer_var_idx > 0)
|
||||
invoke_defer_funcs(ectx);
|
||||
}
|
||||
may_invoke_defer_funcs(ectx);
|
||||
|
||||
dict_stack_clear(dict_stack_len_at_start);
|
||||
ectx->ec_trylevel_at_start = save_trylevel_at_start;
|
||||
@@ -5258,6 +5252,7 @@ call_def_function(
|
||||
int argc_arg, // nr of arguments
|
||||
typval_T *argv, // arguments
|
||||
partial_T *partial, // optional partial for context
|
||||
funccall_T *funccal,
|
||||
typval_T *rettv) // return value
|
||||
{
|
||||
ectx_T ectx; // execution context
|
||||
@@ -5494,6 +5489,10 @@ call_def_function(
|
||||
ectx.ec_instr = INSTRUCTIONS(dfunc);
|
||||
}
|
||||
|
||||
// Store the execution context in funccal, used by invoke_all_defer().
|
||||
if (funccal != NULL)
|
||||
funccal->fc_ectx = &ectx;
|
||||
|
||||
// Following errors are in the function, not the caller.
|
||||
// Commands behave like vim9script.
|
||||
estack_push_ufunc(ufunc, 1);
|
||||
@@ -5537,8 +5536,7 @@ call_def_function(
|
||||
}
|
||||
|
||||
// When failed need to unwind the call stack.
|
||||
while (ectx.ec_frame_idx != ectx.ec_initial_frame_idx)
|
||||
func_return(&ectx);
|
||||
unwind_def_callstack(&ectx);
|
||||
|
||||
// Deal with any remaining closures, they may be in use somewhere.
|
||||
if (ectx.ec_funcrefs.ga_len > 0)
|
||||
@@ -5603,6 +5601,30 @@ failed_early:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Called when a def function has finished (possibly failed).
|
||||
* Invoke all the function returns to clean up and invoke deferred functions,
|
||||
* except the toplevel one.
|
||||
*/
|
||||
void
|
||||
unwind_def_callstack(ectx_T *ectx)
|
||||
{
|
||||
while (ectx->ec_frame_idx != ectx->ec_initial_frame_idx)
|
||||
func_return(ectx);
|
||||
}
|
||||
|
||||
/*
|
||||
* Invoke any deffered functions for the top function in "ectx".
|
||||
*/
|
||||
void
|
||||
may_invoke_defer_funcs(ectx_T *ectx)
|
||||
{
|
||||
dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data) + ectx->ec_dfunc_idx;
|
||||
|
||||
if (dfunc->df_defer_var_idx > 0)
|
||||
invoke_defer_funcs(ectx);
|
||||
}
|
||||
|
||||
/*
|
||||
* List instructions "instr" up to "instr_count" or until ISN_FINISH.
|
||||
* "ufunc" has the source lines, NULL for the instructions of ISN_SUBSTITUTE.
|
||||
|
Reference in New Issue
Block a user