# HG changeset patch # User Bram Moolenaar # Date 1621353604 -7200 # Node ID 982516c8d6927a16c7ce91c37b120966386774c6 # Parent 2a206965fff4aca48a8e45b883fa0656679754f6 patch 8.2.2868: Vim9: when executing compiled expression trylevel is changed Commit: https://github.com/vim/vim/commit/cbe178e3dc4ad45d9b2ed5e713e7c4cc88bf8b8b Author: Bram Moolenaar Date: Tue May 18 17:49:59 2021 +0200 patch 8.2.2868: Vim9: when executing compiled expression trylevel is changed Problem: Vim9: When executing a compiled expression the trylevel at start is changed but not restored. (closes https://github.com/vim/vim/issues/8214) Solution: Restore the trylevel at start. diff --git a/src/testdir/test_vim9_builtin.vim b/src/testdir/test_vim9_builtin.vim --- a/src/testdir/test_vim9_builtin.vim +++ b/src/testdir/test_vim9_builtin.vim @@ -1014,12 +1014,15 @@ def Test_searchpair() try searchpairpos('(', '', ')', 'nW', '[0]->map("")') catch + g:caught = 'yes' endtry enddef Fail() END - CheckScriptFailure(lines, 'E15:') + CheckScriptSuccess(lines) + assert_equal('yes', g:caught) + unlet g:caught bwipe! enddef diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -751,6 +751,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 2868, +/**/ 2867, /**/ 2866, diff --git a/src/vim9execute.c b/src/vim9execute.c --- a/src/vim9execute.c +++ b/src/vim9execute.c @@ -1291,6 +1291,8 @@ exec_instructions(ectx_T *ectx) { int breakcheck_count = 0; typval_T *tv; + int ret = FAIL; + int save_trylevel_at_start = ectx->ec_trylevel_at_start; // Start execution at the first instruction. ectx->ec_iidx = 0; @@ -1312,7 +1314,7 @@ exec_instructions(ectx_T *ectx) // Turn CTRL-C into an exception. got_int = FALSE; if (throw_exception("Vim:Interrupt", ET_INTERRUPT, NULL) == FAIL) - return FAIL; + goto theend; did_throw = TRUE; } @@ -1321,7 +1323,7 @@ exec_instructions(ectx_T *ectx) // Turn an error message into an exception. did_emsg = FALSE; if (throw_exception(*msg_list, ET_ERROR, NULL) == FAIL) - return FAIL; + goto theend; did_throw = TRUE; *msg_list = NULL; } @@ -1346,7 +1348,7 @@ exec_instructions(ectx_T *ectx) // Not inside try or need to return from current functions. // Push a dummy return value. if (GA_GROW(&ectx->ec_stack, 1) == FAIL) - return FAIL; + goto theend; tv = STACK_TV_BOT(0); tv->v_type = VAR_NUMBER; tv->vval.v_number = 0; @@ -1356,12 +1358,12 @@ exec_instructions(ectx_T *ectx) // At the toplevel we are done. need_rethrow = TRUE; if (handle_closure_in_use(ectx, FALSE) == FAIL) - return FAIL; + goto theend; goto done; } if (func_return(ectx) == FAIL) - return FAIL; + goto theend; } continue; } @@ -1397,7 +1399,7 @@ exec_instructions(ectx_T *ectx) int save_flags = cmdmod.cmod_flags; if (GA_GROW(&ectx->ec_stack, 1) == FAIL) - return FAIL; + goto theend; tv = STACK_TV_BOT(0); init_tv(tv); cmdmod.cmod_flags |= CMOD_LEGACY; @@ -1413,7 +1415,7 @@ exec_instructions(ectx_T *ectx) case ISN_INSTR: { if (GA_GROW(&ectx->ec_stack, 1) == FAIL) - return FAIL; + goto theend; tv = STACK_TV_BOT(0); tv->vval.v_instr = ALLOC_ONE(instr_T); if (tv->vval.v_instr == NULL) @@ -1480,7 +1482,7 @@ exec_instructions(ectx_T *ectx) if (GA_GROW(&ectx->ec_stack, 1) == FAIL) { vim_free(res); - return FAIL; + goto theend; } tv = STACK_TV_BOT(0); tv->v_type = VAR_STRING; @@ -1545,7 +1547,7 @@ exec_instructions(ectx_T *ectx) { cmd = alloc(len + 1); if (cmd == NULL) - return FAIL; + goto theend; len = 0; } } @@ -1665,7 +1667,7 @@ exec_instructions(ectx_T *ectx) // load local variable or argument case ISN_LOAD: if (GA_GROW(&ectx->ec_stack, 1) == FAIL) - return FAIL; + goto theend; copy_tv(STACK_TV_VAR(iptr->isn_arg.number), STACK_TV_BOT(0)); ++ectx->ec_stack.ga_len; break; @@ -1673,7 +1675,7 @@ exec_instructions(ectx_T *ectx) // load v: variable case ISN_LOADV: if (GA_GROW(&ectx->ec_stack, 1) == FAIL) - return FAIL; + goto theend; copy_tv(get_vim_var_tv(iptr->isn_arg.number), STACK_TV_BOT(0)); ++ectx->ec_stack.ga_len; break; @@ -1686,10 +1688,10 @@ exec_instructions(ectx_T *ectx) sv = get_script_svar(sref, ectx); if (sv == NULL) - return FAIL; + goto theend; allocate_if_null(sv->sv_tv); if (GA_GROW(&ectx->ec_stack, 1) == FAIL) - return FAIL; + goto theend; copy_tv(sv->sv_tv, STACK_TV_BOT(0)); ++ectx->ec_stack.ga_len; } @@ -1712,7 +1714,7 @@ exec_instructions(ectx_T *ectx) else { if (GA_GROW(&ectx->ec_stack, 1) == FAIL) - return FAIL; + goto theend; copy_tv(&di->di_tv, STACK_TV_BOT(0)); ++ectx->ec_stack.ga_len; } @@ -1748,7 +1750,7 @@ exec_instructions(ectx_T *ectx) namespace = 't'; break; default: // Cannot reach here - return FAIL; + goto theend; } di = find_var_in_ht(ht, 0, iptr->isn_arg.string, TRUE); @@ -1762,7 +1764,7 @@ exec_instructions(ectx_T *ectx) else { if (GA_GROW(&ectx->ec_stack, 1) == FAIL) - return FAIL; + goto theend; copy_tv(&di->di_tv, STACK_TV_BOT(0)); ++ectx->ec_stack.ga_len; } @@ -1775,7 +1777,7 @@ exec_instructions(ectx_T *ectx) char_u *name = iptr->isn_arg.string; if (GA_GROW(&ectx->ec_stack, 1) == FAIL) - return FAIL; + goto theend; SOURCING_LNUM = iptr->isn_lnum; if (eval_variable(name, (int)STRLEN(name), STACK_TV_BOT(0), NULL, EVAL_VAR_VERBOSE) == FAIL) @@ -1799,10 +1801,10 @@ exec_instructions(ectx_T *ectx) case ISN_LOADWDICT: d = curwin->w_vars; break; case ISN_LOADTDICT: d = curtab->tp_vars; break; default: // Cannot reach here - return FAIL; + goto theend; } if (GA_GROW(&ectx->ec_stack, 1) == FAIL) - return FAIL; + goto theend; tv = STACK_TV_BOT(0); tv->v_type = VAR_DICT; tv->v_lock = 0; @@ -1821,9 +1823,9 @@ exec_instructions(ectx_T *ectx) // This is not expected to fail, name is checked during // compilation: don't set SOURCING_LNUM. if (GA_GROW(&ectx->ec_stack, 1) == FAIL) - return FAIL; + goto theend; if (eval_option(&name, &optval, TRUE) == FAIL) - return FAIL; + goto theend; *STACK_TV_BOT(0) = optval; ++ectx->ec_stack.ga_len; } @@ -1836,7 +1838,7 @@ exec_instructions(ectx_T *ectx) char_u *name = iptr->isn_arg.string; if (GA_GROW(&ectx->ec_stack, 1) == FAIL) - return FAIL; + goto theend; // name is always valid, checked when compiling (void)eval_env_var(&name, &optval, TRUE); *STACK_TV_BOT(0) = optval; @@ -1847,7 +1849,7 @@ exec_instructions(ectx_T *ectx) // load @register case ISN_LOADREG: if (GA_GROW(&ectx->ec_stack, 1) == FAIL) - return FAIL; + goto theend; tv = STACK_TV_BOT(0); tv->v_type = VAR_STRING; tv->v_lock = 0; @@ -1899,7 +1901,7 @@ exec_instructions(ectx_T *ectx) sv = get_script_svar(sref, ectx); if (sv == NULL) - return FAIL; + goto theend; --ectx->ec_stack.ga_len; // "const" and "final" are checked at compile time, locking @@ -2001,7 +2003,7 @@ exec_instructions(ectx_T *ectx) ht = &curtab->tp_vars->dv_hashtab; break; default: // Cannot reach here - return FAIL; + goto theend; } --ectx->ec_stack.ga_len; @@ -2106,7 +2108,7 @@ exec_instructions(ectx_T *ectx) goto on_error; // append to list, only fails when out of memory if (list_append_tv(list, tv) == FAIL) - return FAIL; + goto theend; clear_tv(tv); } } @@ -2141,7 +2143,7 @@ exec_instructions(ectx_T *ectx) goto on_error; // add to dict, only fails when out of memory if (dict_add_tv(dict, (char *)key, tv) == FAIL) - return FAIL; + goto theend; clear_tv(tv); } } @@ -2274,7 +2276,7 @@ exec_instructions(ectx_T *ectx) { SOURCING_LNUM = iptr->isn_lnum; iemsg("LOADOUTER depth more than scope levels"); - return FAIL; + goto theend; } tv = ((typval_T *)outer->out_stack->ga_data) + outer->out_frame_idx + STACK_FRAME_SIZE @@ -2282,7 +2284,7 @@ exec_instructions(ectx_T *ectx) if (iptr->isn_type == ISN_LOADOUTER) { if (GA_GROW(&ectx->ec_stack, 1) == FAIL) - return FAIL; + goto theend; copy_tv(tv, STACK_TV_BOT(0)); ++ectx->ec_stack.ga_len; } @@ -2444,7 +2446,7 @@ exec_instructions(ectx_T *ectx) case ISN_PUSHCHANNEL: case ISN_PUSHJOB: if (GA_GROW(&ectx->ec_stack, 1) == FAIL) - return FAIL; + goto theend; tv = STACK_TV_BOT(0); tv->v_lock = 0; ++ectx->ec_stack.ga_len; @@ -2520,7 +2522,7 @@ exec_instructions(ectx_T *ectx) // for the list header and the items case ISN_NEWLIST: if (exe_newlist(iptr->isn_arg.number, ectx) == FAIL) - return FAIL; + goto theend; break; // create a dict from items on the stack @@ -2533,7 +2535,7 @@ exec_instructions(ectx_T *ectx) int idx; if (dict == NULL) - return FAIL; + goto theend; for (idx = 0; idx < count; ++idx) { // have already checked key type is VAR_STRING @@ -2554,7 +2556,7 @@ exec_instructions(ectx_T *ectx) if (item == NULL) { dict_unref(dict); - return FAIL; + goto theend; } item->di_tv = *STACK_TV_BOT(2 * (idx - count) + 1); item->di_tv.v_lock = 0; @@ -2562,14 +2564,14 @@ exec_instructions(ectx_T *ectx) { // can this ever happen? dict_unref(dict); - return FAIL; + goto theend; } } if (count > 0) ectx->ec_stack.ga_len -= 2 * count - 1; else if (GA_GROW(&ectx->ec_stack, 1) == FAIL) - return FAIL; + goto theend; else ++ectx->ec_stack.ga_len; tv = STACK_TV_BOT(-1); @@ -2651,7 +2653,7 @@ exec_instructions(ectx_T *ectx) // return from a :def function call case ISN_RETURN_ZERO: if (GA_GROW(&ectx->ec_stack, 1) == FAIL) - return FAIL; + goto theend; tv = STACK_TV_BOT(0); ++ectx->ec_stack.ga_len; tv->v_type = VAR_NUMBER; @@ -2690,15 +2692,15 @@ exec_instructions(ectx_T *ectx) + iptr->isn_arg.funcref.fr_func; if (pt == NULL) - return FAIL; + goto theend; if (GA_GROW(&ectx->ec_stack, 1) == FAIL) { vim_free(pt); - return FAIL; + goto theend; } if (fill_partial_and_closure(pt, pt_dfunc->df_ufunc, ectx) == FAIL) - return FAIL; + goto theend; tv = STACK_TV_BOT(0); ++ectx->ec_stack.ga_len; @@ -2715,7 +2717,7 @@ exec_instructions(ectx_T *ectx) if (copy_func(newfunc->nf_lambda, newfunc->nf_global, ectx) == FAIL) - return FAIL; + goto theend; } break; @@ -2788,7 +2790,7 @@ exec_instructions(ectx_T *ectx) STACK_TV_VAR(iptr->isn_arg.forloop.for_idx); if (GA_GROW(&ectx->ec_stack, 1) == FAIL) - return FAIL; + goto theend; if (ltv->v_type == VAR_LIST) { list_T *list = ltv->vval.v_list; @@ -2884,7 +2886,7 @@ exec_instructions(ectx_T *ectx) { semsg(_(e_for_loop_on_str_not_supported), vartype_name(ltv->v_type)); - return FAIL; + goto theend; } } break; @@ -2895,7 +2897,7 @@ exec_instructions(ectx_T *ectx) trycmd_T *trycmd = NULL; if (GA_GROW(&ectx->ec_trystack, 1) == FAIL) - return FAIL; + goto theend; trycmd = ((trycmd_T *)ectx->ec_trystack.ga_data) + ectx->ec_trystack.ga_len; ++ectx->ec_trystack.ga_len; @@ -2917,10 +2919,10 @@ exec_instructions(ectx_T *ectx) { SOURCING_LNUM = iptr->isn_lnum; iemsg("Evaluating catch while current_exception is NULL"); - return FAIL; + goto theend; } if (GA_GROW(&ectx->ec_stack, 1) == FAIL) - return FAIL; + goto theend; tv = STACK_TV_BOT(0); ++ectx->ec_stack.ga_len; tv->v_type = VAR_STRING; @@ -2958,7 +2960,7 @@ exec_instructions(ectx_T *ectx) { siemsg("TRYCONT: expected %d levels, found %d", trycont->tct_levels, trystack->ga_len); - return FAIL; + goto theend; } // Make :endtry jump to any outer try block and the last // :endtry inside the loop to the loop start. @@ -3049,7 +3051,7 @@ exec_instructions(ectx_T *ectx) vim_free(tv->vval.v_string); SOURCING_LNUM = iptr->isn_lnum; emsg(_(e_throw_with_empty_string)); - return FAIL; + goto theend; } // Inside a "catch" we need to first discard the caught @@ -3072,7 +3074,7 @@ exec_instructions(ectx_T *ectx) == FAIL) { vim_free(tv->vval.v_string); - return FAIL; + goto theend; } did_throw = TRUE; } @@ -3277,7 +3279,7 @@ exec_instructions(ectx_T *ectx) goto on_error; } if (list_append_tv(l, tv2) == FAIL) - return FAIL; + goto theend; clear_tv(tv2); --ectx->ec_stack.ga_len; } @@ -3577,7 +3579,7 @@ exec_instructions(ectx_T *ectx) li = list_find(tv->vval.v_list, index); if (GA_GROW(&ectx->ec_stack, 1) == FAIL) - return FAIL; + goto theend; ++ectx->ec_stack.ga_len; copy_tv(&li->li_tv, STACK_TV_BOT(-1)); @@ -3810,7 +3812,7 @@ exec_instructions(ectx_T *ectx) goto on_error; if (GA_GROW(&ectx->ec_stack, 1) == FAIL) - return FAIL; + goto theend; ++ectx->ec_stack.ga_len; tv = STACK_TV_BOT(-1); tv->v_type = VAR_NUMBER; @@ -3912,7 +3914,7 @@ exec_instructions(ectx_T *ectx) CHECK_LIST_MATERIALIZE(l); if (GA_GROW(&ectx->ec_stack, count - 1) == FAIL) - return FAIL; + goto theend; ectx->ec_stack.ga_len += count - 1; // Variable after semicolon gets a list with the remaining @@ -3923,7 +3925,7 @@ exec_instructions(ectx_T *ectx) list_alloc_with_items(l->lv_len - count + 1); if (rem_list == NULL) - return FAIL; + goto theend; tv = STACK_TV_BOT(-count); tv->vval.v_list = rem_list; ++rem_list->lv_refcount; @@ -4007,7 +4009,7 @@ func_return: if (func_return(ectx) == FAIL) // only fails when out of memory - return FAIL; + goto theend; continue; on_error: @@ -4037,11 +4039,14 @@ on_fatal_error: // Jump here for an error that messes up the stack. // If we are not inside a try-catch started here, abort execution. if (trylevel <= ectx->ec_trylevel_at_start) - return FAIL; + goto theend; } done: - return OK; + ret = OK; +theend: + ectx->ec_trylevel_at_start = save_trylevel_at_start; + return ret; } /*