# HG changeset patch # User Bram Moolenaar # Date 1628335803 -7200 # Node ID e0d6268c153a59b9eb77310fee391f26afb565c7 # Parent 6ce4df29d7c8a75a96bd127d07c2372b15aebb3a patch 8.2.3305: Vim9: :finally in skipped block not handled correctly Commit: https://github.com/vim/vim/commit/84934998806408db3f3ecff7ac4c3980e0c2a96e Author: rbtnn Date: Sat Aug 7 13:26:53 2021 +0200 patch 8.2.3305: Vim9: :finally in skipped block not handled correctly Problem: Vim9: :finally in skipped block not handled correctly. Solution: Check whether :finally is in a skipped block. (Naruhiko Nishino, closes #8724) diff --git a/src/ex_eval.c b/src/ex_eval.c --- a/src/ex_eval.c +++ b/src/ex_eval.c @@ -2018,7 +2018,8 @@ ex_endtry(exarg_T *eap) { idx = cstack->cs_idx; - if (in_vim9script() + // Check the flags only when not in a skipped block. + if (!skip && in_vim9script() && (cstack->cs_flags[idx] & (CSF_CATCH|CSF_FINALLY)) == 0) { // try/endtry without any catch or finally: give an error and diff --git a/src/testdir/test_vim9_script.vim b/src/testdir/test_vim9_script.vim --- a/src/testdir/test_vim9_script.vim +++ b/src/testdir/test_vim9_script.vim @@ -641,6 +641,20 @@ def Test_try_catch_throw() endtry END CheckScriptFailure(lines, 'E1032:') + + # skipping try-finally-endtry when try-finally-endtry is used in another block + lines =<< trim END + if v:true + try + finally + endtry + else + try + finally + endtry + endif + END + CheckDefAndScriptSuccess(lines) enddef def Test_try_in_catch() diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -756,6 +756,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 3305, +/**/ 3304, /**/ 3303, diff --git a/src/vim9compile.c b/src/vim9compile.c --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -8569,49 +8569,52 @@ compile_finally(char_u *arg, cctx_T *cct return NULL; } - // End :catch or :finally scope: set value in ISN_TRY instruction - isn = ((isn_T *)instr->ga_data) + scope->se_u.se_try.ts_try_label; - if (isn->isn_arg.try.try_ref->try_finally != 0) - { - emsg(_(e_finally_dup)); - return NULL; - } - - this_instr = instr->ga_len; + if (cctx->ctx_skip != SKIP_YES) + { + // End :catch or :finally scope: set value in ISN_TRY instruction + isn = ((isn_T *)instr->ga_data) + scope->se_u.se_try.ts_try_label; + if (isn->isn_arg.try.try_ref->try_finally != 0) + { + emsg(_(e_finally_dup)); + return NULL; + } + + this_instr = instr->ga_len; #ifdef FEAT_PROFILE - if (cctx->ctx_compile_type == CT_PROFILE - && ((isn_T *)instr->ga_data)[this_instr - 1] - .isn_type == ISN_PROF_START) - { - // jump to the profile start of the "finally" - --this_instr; - - // jump to the profile end above it - if (this_instr > 0 && ((isn_T *)instr->ga_data)[this_instr - 1] - .isn_type == ISN_PROF_END) + if (cctx->ctx_compile_type == CT_PROFILE + && ((isn_T *)instr->ga_data)[this_instr - 1] + .isn_type == ISN_PROF_START) + { + // jump to the profile start of the "finally" --this_instr; - } + + // jump to the profile end above it + if (this_instr > 0 && ((isn_T *)instr->ga_data)[this_instr - 1] + .isn_type == ISN_PROF_END) + --this_instr; + } #endif - // Fill in the "end" label in jumps at the end of the blocks. - compile_fill_jump_to_end(&scope->se_u.se_try.ts_end_label, - this_instr, cctx); - - // If there is no :catch then an exception jumps to :finally. - if (isn->isn_arg.try.try_ref->try_catch == 0) - isn->isn_arg.try.try_ref->try_catch = this_instr; - isn->isn_arg.try.try_ref->try_finally = this_instr; - if (scope->se_u.se_try.ts_catch_label != 0) - { - // Previous catch without match jumps here - isn = ((isn_T *)instr->ga_data) + scope->se_u.se_try.ts_catch_label; - isn->isn_arg.jump.jump_where = this_instr; - scope->se_u.se_try.ts_catch_label = 0; - } - if (generate_instr(cctx, ISN_FINALLY) == NULL) - return NULL; - - // TODO: set index in ts_finally_label jumps + // Fill in the "end" label in jumps at the end of the blocks. + compile_fill_jump_to_end(&scope->se_u.se_try.ts_end_label, + this_instr, cctx); + + // If there is no :catch then an exception jumps to :finally. + if (isn->isn_arg.try.try_ref->try_catch == 0) + isn->isn_arg.try.try_ref->try_catch = this_instr; + isn->isn_arg.try.try_ref->try_finally = this_instr; + if (scope->se_u.se_try.ts_catch_label != 0) + { + // Previous catch without match jumps here + isn = ((isn_T *)instr->ga_data) + scope->se_u.se_try.ts_catch_label; + isn->isn_arg.jump.jump_where = this_instr; + scope->se_u.se_try.ts_catch_label = 0; + } + if (generate_instr(cctx, ISN_FINALLY) == NULL) + return NULL; + + // TODO: set index in ts_finally_label jumps + } return arg; }