]> granicus.if.org Git - vim/commitdiff
patch 8.2.4542: Vim9: "break" inside try/catch not handled correctly v8.2.4542
authorBram Moolenaar <Bram@vim.org>
Thu, 10 Mar 2022 21:53:44 +0000 (21:53 +0000)
committerBram Moolenaar <Bram@vim.org>
Thu, 10 Mar 2022 21:53:44 +0000 (21:53 +0000)
Problem:    Vim9: "break" inside try/catch not handled correctly.
Solution:   First jump to :endtry. (closes #9927)

src/testdir/test_vim9_script.vim
src/version.c
src/vim9.h
src/vim9cmds.c

index 46a25396d0e435268cd9e8cc6d82f0e8387ddd2c..594b1cd2c4b94d920abd94f511ca76e229dcf95f 100644 (file)
@@ -907,6 +907,28 @@ def Test_continue_in_try_in_while()
   unlet g:sequence
 enddef
 
+def Test_break_in_try_in_for()
+  var lines =<< trim END
+      vim9script
+      def Ls(): list<string>
+        var ls: list<string>
+        for s in ['abc', 'def']
+          for _ in [123, 456]
+            try
+              eval [][0]
+            catch
+              break
+            endtry
+          endfor
+          ls += [s]
+        endfor
+        return ls
+      enddef
+      assert_equal(['abc', 'def'], Ls())
+  END
+  v9.CheckScriptSuccess(lines)
+enddef
+
 def Test_nocatch_return_in_try()
   # return in try block returns normally
   def ReturnInTry(): string
index 122ba03e41027baf6163789a82cf8da4926cf029..56f365aac87d1a2c7e89157769d9e6991f0dbb34 100644 (file)
@@ -750,6 +750,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    4542,
 /**/
     4541,
 /**/
index a4fcc9b32aee271a9a9d5d47603d9cc1532f670b..03602e674c75a5cbfb79ede18d98204b467d999b 100644 (file)
@@ -121,7 +121,7 @@ typedef enum {
     ISN_CATCH,     // drop v:exception
     ISN_FINALLY,    // start of :finally block
     ISN_ENDTRY,            // take entry off from ec_trystack
-    ISN_TRYCONT,    // handle :continue inside a :try statement
+    ISN_TRYCONT,    // handle :continue or :break inside a :try statement
 
     // more expression operations
     ISN_ADDLIST,    // add two lists
index c49a48270b8f3c7579e5973fccff53e186f33252..5a44644599a661d16b4859fafb62d5018dcd0148 100644 (file)
@@ -1206,6 +1206,7 @@ compile_continue(char_u *arg, cctx_T *cctx)
 compile_break(char_u *arg, cctx_T *cctx)
 {
     scope_T    *scope = cctx->ctx_scope;
+    int                try_scopes = 0;
     endlabel_T **el;
 
     for (;;)
@@ -1215,16 +1216,29 @@ compile_break(char_u *arg, cctx_T *cctx)
            emsg(_(e_break_without_while_or_for));
            return NULL;
        }
-       if (scope->se_type == FOR_SCOPE || scope->se_type == WHILE_SCOPE)
+       if (scope->se_type == FOR_SCOPE)
+       {
+           el = &scope->se_u.se_for.fs_end_label;
+           break;
+       }
+       if (scope->se_type == WHILE_SCOPE)
+       {
+           el = &scope->se_u.se_while.ws_end_label;
            break;
+       }
+       if (scope->se_type == TRY_SCOPE)
+           ++try_scopes;
        scope = scope->se_outer;
     }
 
-    // Jump to the end of the FOR or WHILE loop.
-    if (scope->se_type == FOR_SCOPE)
-       el = &scope->se_u.se_for.fs_end_label;
-    else
-       el = &scope->se_u.se_while.ws_end_label;
+    if (try_scopes > 0)
+       // Inside one or more try/catch blocks we first need to jump to the
+       // "finally" or "endtry" to cleanup.  Then come to the next JUMP
+       // intruction, which we don't know the index of yet.
+       generate_TRYCONT(cctx, try_scopes, cctx->ctx_instr.ga_len + 1);
+
+    // Jump to the end of the FOR or WHILE loop.  The instruction index will be
+    // filled in later.
     if (compile_jump_to_end(el, JUMP_ALWAYS, cctx) == FAIL)
        return FAIL;