changeset 25537:e0d6268c153a v8.2.3305

patch 8.2.3305: Vim9: :finally in skipped block not handled correctly Commit: https://github.com/vim/vim/commit/84934998806408db3f3ecff7ac4c3980e0c2a96e Author: rbtnn <naru123456789@gmail.com> 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)
author Bram Moolenaar <Bram@vim.org>
date Sat, 07 Aug 2021 13:30:03 +0200
parents 6ce4df29d7c8
children e53a494dbfff
files src/ex_eval.c src/testdir/test_vim9_script.vim src/version.c src/vim9compile.c
diffstat 4 files changed, 60 insertions(+), 40 deletions(-) [+]
line wrap: on
line diff
--- 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
--- 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()
--- 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,
--- 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;
 }