# HG changeset patch # User Bram Moolenaar # Date 1609514104 -3600 # Node ID b0587f7ec42281761a43ad169e8bf6df75b9f144 # Parent ce571f96b8a72bdf36c72849877b52abbe3afeec patch 8.2.2263: Vim9: compilation error with try-catch in skipped block Commit: https://github.com/vim/vim/commit/69f7050cebb0f069d6e39571961b9bbe8531c69a Author: Bram Moolenaar Date: Fri Jan 1 16:10:46 2021 +0100 patch 8.2.2263: Vim9: compilation error with try-catch in skipped block Problem: Vim9: compilation error with try-catch in skipped block. Solution: Do not bail out when generate_instr() returns NULL. (closes https://github.com/vim/vim/issues/7584) 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 @@ -361,6 +361,35 @@ def Test_try_catch() endtry assert_equal(99, n) + var done = 'no' + if 0 + try | catch | endtry + else + done = 'yes' + endif + assert_equal('yes', done) + + done = 'no' + if 1 + done = 'yes' + else + try | catch | endtry + done = 'never' + endif + assert_equal('yes', done) + + if 1 + else + try | catch /pat/ | endtry + try | catch /pat/ + endtry + try + catch /pat/ | endtry + try + catch /pat/ + endtry + endif + try # string slice returns a string, not a number n = g:astring[3] 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 */ /**/ + 2263, +/**/ 2262, /**/ 2261, diff --git a/src/vim9compile.c b/src/vim9compile.c --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -6916,11 +6916,14 @@ compile_try(char_u *arg, cctx_T *cctx) if (try_scope == NULL) return NULL; - // "catch" is set when the first ":catch" is found. - // "finally" is set when ":finally" or ":endtry" is found - try_scope->se_u.se_try.ts_try_label = instr->ga_len; - if (generate_instr(cctx, ISN_TRY) == NULL) - return NULL; + if (cctx->ctx_skip != SKIP_YES) + { + // "catch" is set when the first ":catch" is found. + // "finally" is set when ":finally" or ":endtry" is found + try_scope->se_u.se_try.ts_try_label = instr->ga_len; + if (generate_instr(cctx, ISN_TRY) == NULL) + return NULL; + } // scope for the try block itself scope = new_scope(cctx, BLOCK_SCOPE); @@ -6959,20 +6962,23 @@ compile_catch(char_u *arg, cctx_T *cctx return NULL; } - // Jump from end of previous block to :finally or :endtry - if (compile_jump_to_end(&scope->se_u.se_try.ts_end_label, + if (cctx->ctx_skip != SKIP_YES) + { + // Jump from end of previous block to :finally or :endtry + if (compile_jump_to_end(&scope->se_u.se_try.ts_end_label, JUMP_ALWAYS, cctx) == FAIL) - return NULL; - - // End :try or :catch 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_catch == 0) - isn->isn_arg.try.try_catch = instr->ga_len; - 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 = instr->ga_len; + return NULL; + + // End :try or :catch 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_catch == 0) + isn->isn_arg.try.try_catch = instr->ga_len; + 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 = instr->ga_len; + } } p = skipwhite(arg); @@ -7019,7 +7025,7 @@ compile_catch(char_u *arg, cctx_T *cctx return NULL; } - if (generate_instr(cctx, ISN_CATCH) == NULL) + if (cctx->ctx_skip != SKIP_YES && generate_instr(cctx, ISN_CATCH) == NULL) return NULL; if (new_scope(cctx, BLOCK_SCOPE) == NULL) @@ -7097,33 +7103,37 @@ compile_endtry(char_u *arg, cctx_T *cctx return NULL; } - isn = ((isn_T *)instr->ga_data) + scope->se_u.se_try.ts_try_label; - if (isn->isn_arg.try.try_catch == 0 && isn->isn_arg.try.try_finally == 0) - { - emsg(_(e_missing_catch_or_finally)); - return NULL; - } - - // Fill in the "end" label in jumps at the end of the blocks, if not done - // by ":finally". - compile_fill_jump_to_end(&scope->se_u.se_try.ts_end_label, cctx); - - // End :catch or :finally scope: set value in ISN_TRY instruction - if (isn->isn_arg.try.try_catch == 0) - isn->isn_arg.try.try_catch = instr->ga_len; - if (isn->isn_arg.try.try_finally == 0) - isn->isn_arg.try.try_finally = instr->ga_len; - - if (scope->se_u.se_try.ts_catch_label != 0) - { - // Last 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 = instr->ga_len; + if (cctx->ctx_skip != SKIP_YES) + { + isn = ((isn_T *)instr->ga_data) + scope->se_u.se_try.ts_try_label; + if (isn->isn_arg.try.try_catch == 0 + && isn->isn_arg.try.try_finally == 0) + { + emsg(_(e_missing_catch_or_finally)); + return NULL; + } + + // Fill in the "end" label in jumps at the end of the blocks, if not + // done by ":finally". + compile_fill_jump_to_end(&scope->se_u.se_try.ts_end_label, cctx); + + // End :catch or :finally scope: set value in ISN_TRY instruction + if (isn->isn_arg.try.try_catch == 0) + isn->isn_arg.try.try_catch = instr->ga_len; + if (isn->isn_arg.try.try_finally == 0) + isn->isn_arg.try.try_finally = instr->ga_len; + + if (scope->se_u.se_try.ts_catch_label != 0) + { + // Last 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 = instr->ga_len; + } } compile_endblock(cctx); - if (generate_instr(cctx, ISN_ENDTRY) == NULL) + if (cctx->ctx_skip != SKIP_YES && generate_instr(cctx, ISN_ENDTRY) == NULL) return NULL; return arg; }