diff options
author | Bram Moolenaar <Bram@vim.org> | 2022-09-06 18:31:14 +0100 |
---|---|---|
committer | Bram Moolenaar <Bram@vim.org> | 2022-09-06 18:31:14 +0100 |
commit | 58779858fb5a82a3233af5d4237a3cece88c10d4 (patch) | |
tree | c1654eb20a1a8300e1b304263ccea655928b3401 /src/vim9execute.c | |
parent | 2834ebdee473c838e50e60d0aa160f0e62fc8ef9 (diff) | |
download | vim-git-58779858fb5a82a3233af5d4237a3cece88c10d4.tar.gz |
patch 9.0.0397: :defer not tested with exceptions and ":qa!"v9.0.0397
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.
Diffstat (limited to 'src/vim9execute.c')
-rw-r--r-- | src/vim9execute.c | 40 |
1 files changed, 31 insertions, 9 deletions
diff --git a/src/vim9execute.c b/src/vim9execute.c index 08774fee3..0b50acee3 100644 --- a/src/vim9execute.c +++ b/src/vim9execute.c @@ -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) @@ -5604,6 +5602,30 @@ failed_early: } /* + * 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. * "pfx" is prefixed to every line. |