]> granicus.if.org Git - vim/commitdiff
patch 8.2.3305: Vim9: :finally in skipped block not handled correctly v8.2.3305
authorrbtnn <naru123456789@gmail.com>
Sat, 7 Aug 2021 11:26:53 +0000 (13:26 +0200)
committerBram Moolenaar <Bram@vim.org>
Sat, 7 Aug 2021 11:26:53 +0000 (13:26 +0200)
Problem:    Vim9: :finally in skipped block not handled correctly.
Solution:   Check whether :finally is in a skipped block. (Naruhiko Nishino,
            closes #8724)

src/ex_eval.c
src/testdir/test_vim9_script.vim
src/version.c
src/vim9compile.c

index 77dceccf002c3e89a229c70f00533699a5d9649c..6bc7c18b8459f38f23b5762f48f596a09c41d15f 100644 (file)
@@ -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
index b11149a59e53aff309a8231e9748e65a9ce62875..93dce833979a7f54371bc3bfc7bbdb6f6b79eefa 100644 (file)
@@ -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()
index 206234d9b9410226e74ae13f9f68d936441c7a5f..d1117610f4cad47e5c71953cf30ac8fbadce0931 100644 (file)
@@ -755,6 +755,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    3305,
 /**/
     3304,
 /**/
index 23f0a746e199fa06471cf568d9a800907d418a7d..9d7af52a048549e862815e6e00d2fda493ca3515 100644 (file)
@@ -8569,49 +8569,52 @@ compile_finally(char_u *arg, cctx_T *cctx)
        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)
+    if (cctx->ctx_skip != SKIP_YES)
     {
-       emsg(_(e_finally_dup));
-       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;
+       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;
+       // 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
+       // TODO: set index in ts_finally_label jumps
+    }
 
     return arg;
 }