aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/nvim/eval/userfunc.c30
-rw-r--r--test/old/testdir/test_user_func.vim29
2 files changed, 51 insertions, 8 deletions
diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c
index 6016ad0646..32f9f9182c 100644
--- a/src/nvim/eval/userfunc.c
+++ b/src/nvim/eval/userfunc.c
@@ -881,6 +881,27 @@ static void func_clear_free(ufunc_T *fp, bool force)
func_free(fp);
}
+/// Allocate a funccall_T, link it in current_funccal and fill in "fp" and "rettv".
+/// Must be followed by one call to remove_funccal() or cleanup_function_call().
+funccall_T *create_funccal(ufunc_T *fp, typval_T *rettv)
+{
+ funccall_T *fc = xcalloc(1, sizeof(funccall_T));
+ fc->fc_caller = current_funccal;
+ current_funccal = fc;
+ fc->fc_func = fp;
+ func_ptr_ref(fp);
+ fc->fc_rettv = rettv;
+ return fc;
+}
+
+/// Restore current_funccal.
+void remove_funccal(void)
+{
+ funccall_T *fc = current_funccal;
+ current_funccal = fc->fc_caller;
+ free_funccal(fc);
+}
+
/// Call a user function
///
/// @param fp Function to call.
@@ -895,7 +916,6 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars, typval_T *rett
FUNC_ATTR_NONNULL_ARG(1, 3, 4)
{
bool using_sandbox = false;
- funccall_T *fc;
int save_did_emsg;
static int depth = 0;
dictitem_T *v;
@@ -930,19 +950,13 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars, typval_T *rett
// check for CTRL-C hit
line_breakcheck();
// prepare the funccall_T structure
- fc = xcalloc(1, sizeof(funccall_T));
- fc->fc_caller = current_funccal;
- current_funccal = fc;
- fc->fc_func = fp;
- fc->fc_rettv = rettv;
+ funccall_T *fc = create_funccal(fp, rettv);
fc->fc_level = ex_nesting_level;
// Check if this function has a breakpoint.
fc->fc_breakpoint = dbg_find_breakpoint(false, fp->uf_name, (linenr_T)0);
fc->fc_dbg_tick = debug_tick;
-
// Set up fields for closure.
ga_init(&fc->fc_ufuncs, sizeof(ufunc_T *), 1);
- func_ptr_ref(fp);
if (strncmp(fp->uf_name, "<lambda>", 8) == 0) {
islambda = true;
diff --git a/test/old/testdir/test_user_func.vim b/test/old/testdir/test_user_func.vim
index 4bb4078a1c..5a1931e690 100644
--- a/test/old/testdir/test_user_func.vim
+++ b/test/old/testdir/test_user_func.vim
@@ -633,5 +633,34 @@ func Test_defer_quitall()
call assert_false(filereadable('XQuitallTwo'))
endfunc
+func Test_defer_quitall_in_expr_func()
+ throw 'Skipped: Vim9 script is N/A'
+ let lines =<< trim END
+ def DefIndex(idx: number, val: string): bool
+ call writefile([idx .. ': ' .. val], 'Xentry' .. idx, 'D')
+ if val == 'b'
+ qa!
+ endif
+ return val == 'c'
+ enddef
+
+ def Test_defer_in_funcref()
+ assert_equal(2, indexof(['a', 'b', 'c'], funcref('g:DefIndex')))
+ enddef
+ call Test_defer_in_funcref()
+ END
+ call writefile(lines, 'XdeferQuitallExpr', 'D')
+ let res = system(GetVimCommandClean() .. ' -X -S XdeferQuitallExpr')
+ call assert_equal(0, v:shell_error)
+ call assert_false(filereadable('Xentry0'))
+ call assert_false(filereadable('Xentry1'))
+ call assert_false(filereadable('Xentry2'))
+endfunc
+
+func FuncIndex(idx, val)
+ call writefile([a:idx .. ': ' .. a:val], 'Xentry' .. a:idx, 'D')
+ return a:val == 'c'
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab