summaryrefslogtreecommitdiff
path: root/src/vim9execute.c
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2022-09-06 18:31:14 +0100
committerBram Moolenaar <Bram@vim.org>2022-09-06 18:31:14 +0100
commit58779858fb5a82a3233af5d4237a3cece88c10d4 (patch)
treec1654eb20a1a8300e1b304263ccea655928b3401 /src/vim9execute.c
parent2834ebdee473c838e50e60d0aa160f0e62fc8ef9 (diff)
downloadvim-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.c40
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.