# HG changeset patch # User Bram Moolenaar # Date 1681851603 -7200 # Node ID 774c94489febf66f7f5ca96c7abb6688b76a3f31 # Parent 07141765bae884ea7ae42cf60349ed99d1602f74 patch 9.0.1469: deferred functions not called from autocommands Commit: https://github.com/vim/vim/commit/960cf9119e3f4922ca9719feb5e0c0bc5e3b9840 Author: zeertzjq Date: Tue Apr 18 21:52:54 2023 +0100 patch 9.0.1469: deferred functions not called from autocommands Problem: Deferred functions not called from autocommands. Solution: Also go through the funccal_stack. (closes https://github.com/vim/vim/issues/12267) diff --git a/src/testdir/test_user_func.vim b/src/testdir/test_user_func.vim --- a/src/testdir/test_user_func.vim +++ b/src/testdir/test_user_func.vim @@ -702,6 +702,33 @@ func Test_defer_quitall_def() call delete('XQuitallDefThree') endfunc +func Test_defer_quitall_autocmd() + let lines =<< trim END + autocmd User DeferAutocmdThree qa! + + func DeferLevelTwo() + call writefile(['text'], 'XQuitallAutocmdTwo', 'D') + doautocmd User DeferAutocmdThree + endfunc + + autocmd User DeferAutocmdTwo ++nested call DeferLevelTwo() + + def DeferLevelOne() + call writefile(['text'], 'XQuitallAutocmdOne', 'D') + doautocmd User DeferAutocmdTwo + enddef + + autocmd User DeferAutocmdOne ++nested call DeferLevelOne() + + doautocmd User DeferAutocmdOne + END + call writefile(lines, 'XdeferQuitallAutocmd', 'D') + let res = system(GetVimCommand() .. ' -X -S XdeferQuitallAutocmd') + call assert_equal(0, v:shell_error) + call assert_false(filereadable('XQuitallAutocmdOne')) + call assert_false(filereadable('XQuitallAutocmdTwo')) +endfunc + func Test_defer_quitall_in_expr_func() let lines =<< trim END def DefIndex(idx: number, val: string): bool diff --git a/src/userfunc.c b/src/userfunc.c --- a/src/userfunc.c +++ b/src/userfunc.c @@ -6122,27 +6122,34 @@ handle_defer_one(funccall_T *funccal) ga_clear(&funccal->fc_defer); } + static void +invoke_funccall_defer(funccall_T *fc) +{ + if (fc->fc_ectx != NULL) + { + // :def function + unwind_def_callstack(fc->fc_ectx); + may_invoke_defer_funcs(fc->fc_ectx); + } + else + { + // legacy function + handle_defer_one(fc); + } +} + /* * Called when exiting: call all defer functions. */ void invoke_all_defer(void) { - funccall_T *funccal; - - for (funccal = current_funccal; funccal != NULL; - funccal = funccal->fc_caller) - if (funccal->fc_ectx != NULL) - { - // :def function - unwind_def_callstack(funccal->fc_ectx); - may_invoke_defer_funcs(funccal->fc_ectx); - } - else - { - // legacy function - handle_defer_one(funccal); - } + for (funccal_entry_T *fce = funccal_stack; fce != NULL; fce = fce->next) + for (funccall_T *fc = fce->top_funccal; fc != NULL; fc = fc->fc_caller) + invoke_funccall_defer(fc); + + for (funccall_T *fc = current_funccal; fc != NULL; fc = fc->fc_caller) + invoke_funccall_defer(fc); } /* diff --git a/src/version.c b/src/version.c --- 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 */ /**/ + 1469, +/**/ 1468, /**/ 1467,