To: vim_dev@googlegroups.com Subject: Patch 9.0.1468 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 9.0.1468 Problem: Recursively calling :defer function if it does :qa in a compiled function. Solution: Clear the defer entry before calling the function. (closes #12271) Files: src/vim9execute.c, src/testdir/test_user_func.vim *** ../vim-9.0.1467/src/vim9execute.c 2023-04-01 22:05:35.155519002 +0100 --- src/vim9execute.c 2023-04-18 20:57:03.520916445 +0100 *************** *** 1063,1068 **** --- 1063,1072 ---- int obj_off = functv->v_type == VAR_PARTIAL ? 1 : 0; int argcount = l->lv_len - 1 - obj_off; + if (functv->vval.v_string == NULL) + // already being called, can happen if function does ":qa" + continue; + if (obj_off == 1) arg_li = arg_li->li_next; // second list item is the object for (i = 0; i < argcount; ++i) *************** *** 1082,1090 **** if (funcexe.fe_object != NULL) ++funcexe.fe_object->obj_refcount; } ! (void)call_func(functv->vval.v_string, -1, ! &rettv, argcount, argvars, &funcexe); clear_tv(&rettv); } } --- 1086,1099 ---- if (funcexe.fe_object != NULL) ++funcexe.fe_object->obj_refcount; } ! ! char_u *name = functv->vval.v_string; ! functv->vval.v_string = NULL; ! ! (void)call_func(name, -1, &rettv, argcount, argvars, &funcexe); ! clear_tv(&rettv); + vim_free(name); } } *** ../vim-9.0.1467/src/testdir/test_user_func.vim 2023-04-17 19:23:41.946037074 +0100 --- src/testdir/test_user_func.vim 2023-04-18 21:04:10.898990907 +0100 *************** *** 651,680 **** call assert_false(filereadable('XDeleteTwo')) endfunc ! func Test_defer_quitall() let lines =<< trim END - vim9script func DeferLevelTwo() ! call writefile(['text'], 'XQuitallTwo', 'D') ! call writefile(['quit'], 'XQuitallThree', 'a') qa! endfunc def DeferLevelOne() ! call writefile(['text'], 'XQuitallOne', 'D') ! call DeferLevelTwo() enddef DeferLevelOne() END ! call writefile(lines, 'XdeferQuitall', 'D') ! let res = system(GetVimCommand() .. ' -X -S XdeferQuitall') 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() --- 651,705 ---- call assert_false(filereadable('XDeleteTwo')) endfunc ! func Test_defer_quitall_func() let lines =<< trim END func DeferLevelTwo() ! call writefile(['text'], 'XQuitallFuncTwo', 'D') ! call writefile(['quit'], 'XQuitallFuncThree', 'a') qa! endfunc + func DeferLevelOne() + call writefile(['text'], 'XQuitalFunclOne', 'D') + defer DeferLevelTwo() + endfunc + + call DeferLevelOne() + END + call writefile(lines, 'XdeferQuitallFunc', 'D') + call system(GetVimCommand() .. ' -X -S XdeferQuitallFunc') + call assert_equal(0, v:shell_error) + call assert_false(filereadable('XQuitallFuncOne')) + call assert_false(filereadable('XQuitallFuncTwo')) + call assert_equal(['quit'], readfile('XQuitallFuncThree')) + + call delete('XQuitallFuncThree') + endfunc + + func Test_defer_quitall_def() + let lines =<< trim END + vim9script + def DeferLevelTwo() + call writefile(['text'], 'XQuitallDefTwo', 'D') + call writefile(['quit'], 'XQuitallDefThree', 'a') + qa! + enddef + def DeferLevelOne() ! call writefile(['text'], 'XQuitallDefOne', 'D') ! defer DeferLevelTwo() enddef DeferLevelOne() END ! call writefile(lines, 'XdeferQuitallDef', 'D') ! call system(GetVimCommand() .. ' -X -S XdeferQuitallDef') call assert_equal(0, v:shell_error) ! call assert_false(filereadable('XQuitallDefOne')) ! call assert_false(filereadable('XQuitallDefTwo')) ! call assert_equal(['quit'], readfile('XQuitallDefThree')) ! call delete('XQuitallDefThree') endfunc func Test_defer_quitall_in_expr_func() *************** *** 693,699 **** call Test_defer_in_funcref() END call writefile(lines, 'XdeferQuitallExpr', 'D') ! let res = system(GetVimCommand() .. ' -X -S XdeferQuitallExpr') call assert_equal(0, v:shell_error) call assert_false(filereadable('Xentry0')) call assert_false(filereadable('Xentry1')) --- 718,724 ---- call Test_defer_in_funcref() END call writefile(lines, 'XdeferQuitallExpr', 'D') ! call system(GetVimCommand() .. ' -X -S XdeferQuitallExpr') call assert_equal(0, v:shell_error) call assert_false(filereadable('Xentry0')) call assert_false(filereadable('Xentry1')) *** ../vim-9.0.1467/src/version.c 2023-04-18 20:53:17.734242016 +0100 --- src/version.c 2023-04-18 20:59:06.578559373 +0100 *************** *** 697,698 **** --- 697,700 ---- { /* Add new patch number below this line */ + /**/ + 1468, /**/ -- There are only two hard things in programming: Cache invalidation, naming things and off-by-one errors. /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// \\\ \\\ sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///