diff options
author | Bram Moolenaar <Bram@vim.org> | 2023-04-17 19:23:45 +0100 |
---|---|---|
committer | Bram Moolenaar <Bram@vim.org> | 2023-04-17 19:23:45 +0100 |
commit | 42994bf678f46dc9ca66e49f512261da8864fff6 (patch) | |
tree | 3daa7460a610b439456f8bfabcd72b6b88efe8db | |
parent | fc8a601c3251c0388a88c1235b18c529385f7196 (diff) | |
download | vim-git-42994bf678f46dc9ca66e49f512261da8864fff6.tar.gz |
patch 9.0.1462: recursively calling :defer function if it does :qav9.0.1462
Problem: Recursively calling :defer function if it does :qa.
Solution: Clear the defer entry before calling the function. (closes #12266)
-rw-r--r-- | src/testdir/test_user_func.vim | 4 | ||||
-rw-r--r-- | src/userfunc.c | 21 | ||||
-rw-r--r-- | src/version.c | 2 |
3 files changed, 20 insertions, 7 deletions
diff --git a/src/testdir/test_user_func.vim b/src/testdir/test_user_func.vim index ade259cff..8715a0b78 100644 --- a/src/testdir/test_user_func.vim +++ b/src/testdir/test_user_func.vim @@ -656,6 +656,7 @@ func Test_defer_quitall() vim9script func DeferLevelTwo() call writefile(['text'], 'XQuitallTwo', 'D') + call writefile(['quit'], 'XQuitallThree', 'a') qa! endfunc @@ -671,6 +672,9 @@ func Test_defer_quitall() call assert_equal(0, v:shell_error) call assert_false(filereadable('XQuitallOne')) call assert_false(filereadable('XQuitallTwo')) + call assert_equal(['quit'], readfile('XQuitallThree')) + + call delete('XQuitallThree') endfunc func Test_defer_quitall_in_expr_func() diff --git a/src/userfunc.c b/src/userfunc.c index 25f76ecb0..a506d72c8 100644 --- a/src/userfunc.c +++ b/src/userfunc.c @@ -6096,20 +6096,27 @@ handle_defer_one(funccall_T *funccal) for (idx = funccal->fc_defer.ga_len - 1; idx >= 0; --idx) { - funcexe_T funcexe; - typval_T rettv; defer_T *dr = ((defer_T *)funccal->fc_defer.ga_data) + idx; - int i; + if (dr->dr_name == NULL) + // already being called, can happen if function does ":qa" + continue; + + funcexe_T funcexe; CLEAR_FIELD(funcexe); funcexe.fe_evaluate = TRUE; + typval_T rettv; rettv.v_type = VAR_UNKNOWN; // clear_tv() uses this - call_func(dr->dr_name, -1, &rettv, - dr->dr_argcount, dr->dr_argvars, &funcexe); + + char_u *name = dr->dr_name; + dr->dr_name = NULL; + + call_func(name, -1, &rettv, dr->dr_argcount, dr->dr_argvars, &funcexe); + clear_tv(&rettv); - vim_free(dr->dr_name); - for (i = dr->dr_argcount - 1; i >= 0; --i) + vim_free(name); + for (int i = dr->dr_argcount - 1; i >= 0; --i) clear_tv(&dr->dr_argvars[i]); } ga_clear(&funccal->fc_defer); diff --git a/src/version.c b/src/version.c index 053fe7827..6dc7e3431 100644 --- a/src/version.c +++ b/src/version.c @@ -696,6 +696,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 1462, +/**/ 1461, /**/ 1460, |