changeset 32276:774c94489feb v9.0.1469

patch 9.0.1469: deferred functions not called from autocommands Commit: https://github.com/vim/vim/commit/960cf9119e3f4922ca9719feb5e0c0bc5e3b9840 Author: zeertzjq <zeertzjq@outlook.com> 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)
author Bram Moolenaar <Bram@vim.org>
date Tue, 18 Apr 2023 23:00:03 +0200
parents 07141765bae8
children 272dc3dcacd3
files src/testdir/test_user_func.vim src/userfunc.c src/version.c
diffstat 3 files changed, 51 insertions(+), 15 deletions(-) [+]
line wrap: on
line diff
--- 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
--- 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);
 }
 
 /*
--- 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,