]> granicus.if.org Git - vim/commitdiff
patch 8.2.3077: Vim9: an error in a catch block is not reported v8.2.3077
authorBram Moolenaar <Bram@vim.org>
Wed, 30 Jun 2021 17:54:43 +0000 (19:54 +0200)
committerBram Moolenaar <Bram@vim.org>
Wed, 30 Jun 2021 17:54:43 +0000 (19:54 +0200)
Problem:    Vim9: an error in a catch block is not reported.
Solution:   Put the "in catch" flag in the try stack. (closes #8478)

src/testdir/test_vim9_script.vim
src/version.c
src/vim9execute.c

index 40cdfa39c17e493a0b27cd4d7ad5432fbf99d390..a258bcb7a8a3a4427e2204bf3c84d7e2e8cfe1c3 100644 (file)
@@ -631,6 +631,17 @@ def Test_try_in_catch()
   END
 enddef
 
+def Test_error_in_catch()
+  var lines =<< trim END
+      try
+        eval [][0]
+      catch /E684:/
+        eval [][0]
+      endtry
+  END
+  CheckDefExecFailure(lines, 'E684:', 4)
+enddef
+
 " :while at the very start of a function that :continue jumps to
 def TryContinueFunc()
  while g:Count < 2
@@ -768,6 +779,30 @@ def Test_try_catch_nested()
 
   assert_equal('intry', ReturnFinally())
   assert_equal('finally', g:in_finally)
+
+  var l = []
+  try
+    l->add('1')
+    throw 'bad'
+    l->add('x')
+  catch /bad/
+    l->add('2')
+    try
+      l->add('3')
+      throw 'one'
+      l->add('x')
+    catch /one/
+      l->add('4')
+      try
+        l->add('5')
+        throw 'more'
+        l->add('x')
+      catch /more/
+        l->add('6')
+      endtry
+    endtry
+  endtry
+  assert_equal(['1', '2', '3', '4', '5', '6'], l)
 enddef
 
 def TryOne(): number
index 70e0ff2f9d94138863fd553355abf0981634f929..655aaaea33faa999cbeb50cb3d6bec38c904e351 100644 (file)
@@ -755,6 +755,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    3077,
 /**/
     3076,
 /**/
index 0de11bab0b01201480c863253132e654e37d9c03..4013c06cda2316fca72ca1be1a98efce29c4be8a 100644 (file)
@@ -26,7 +26,8 @@
 typedef struct {
     int            tcd_frame_idx;      // ec_frame_idx at ISN_TRY
     int            tcd_stack_len;      // size of ectx.ec_stack at ISN_TRY
-    int            tcd_save_in_catch;  // saved ec_in_catch
+    int            tcd_in_catch;       // in catch or finally block
+    int            tcd_did_throw;      // set did_throw in :endtry
     int            tcd_catch_idx;      // instruction of the first :catch or :finally
     int            tcd_finally_idx;    // instruction of the :finally block or zero
     int            tcd_endtry_idx;     // instruction of the :endtry
@@ -83,7 +84,6 @@ struct ectx_S {
     funclocal_T ec_funclocal;
 
     garray_T   ec_trystack;    // stack of trycmd_T values
-    int                ec_in_catch;    // when TRUE in catch or finally block
 
     int                ec_dfunc_idx;   // current function index
     isn_T      *ec_instr;      // array with instructions
@@ -1566,20 +1566,31 @@ exec_instructions(ectx_T *ectx)
            *msg_list = NULL;
        }
 
-       if (did_throw && !ectx->ec_in_catch)
+       if (did_throw)
        {
            garray_T    *trystack = &ectx->ec_trystack;
            trycmd_T    *trycmd = NULL;
+           int         index = trystack->ga_len;
 
            // An exception jumps to the first catch, finally, or returns from
            // the current function.
-           if (trystack->ga_len > 0)
-               trycmd = ((trycmd_T *)trystack->ga_data) + trystack->ga_len - 1;
+           while (index > 0)
+           {
+               trycmd = ((trycmd_T *)trystack->ga_data) + index - 1;
+               if (!trycmd->tcd_in_catch)
+                   break;
+               // In the catch and finally block of this try we have to go up
+               // one level.
+               --index;
+               trycmd = NULL;
+           }
            if (trycmd != NULL && trycmd->tcd_frame_idx == ectx->ec_frame_idx)
            {
                // jump to ":catch" or ":finally"
-               ectx->ec_in_catch = TRUE;
+               trycmd->tcd_in_catch = TRUE;
                ectx->ec_iidx = trycmd->tcd_catch_idx;
+               did_throw = FALSE;  // don't come back here until :endtry
+               trycmd->tcd_did_throw = TRUE;
            }
            else
            {
@@ -3167,8 +3178,6 @@ exec_instructions(ectx_T *ectx)
                    CLEAR_POINTER(trycmd);
                    trycmd->tcd_frame_idx = ectx->ec_frame_idx;
                    trycmd->tcd_stack_len = ectx->ec_stack.ga_len;
-                   trycmd->tcd_save_in_catch = ectx->ec_in_catch;
-                   ectx->ec_in_catch = FALSE;
                    trycmd->tcd_catch_idx =
                                          iptr->isn_arg.try.try_ref->try_catch;
                    trycmd->tcd_finally_idx =
@@ -3205,6 +3214,7 @@ exec_instructions(ectx_T *ectx)
                        trycmd_T    *trycmd = ((trycmd_T *)trystack->ga_data)
                                                        + trystack->ga_len - 1;
                        trycmd->tcd_caught = TRUE;
+                       trycmd->tcd_did_throw = FALSE;
                    }
                    did_emsg = got_int = did_throw = FALSE;
                    force_abort = need_rethrow = FALSE;
@@ -3268,7 +3278,8 @@ exec_instructions(ectx_T *ectx)
                        --trylevel;
                        trycmd = ((trycmd_T *)trystack->ga_data)
                                                            + trystack->ga_len;
-                       ectx->ec_in_catch = trycmd->tcd_save_in_catch;
+                       if (trycmd->tcd_did_throw)
+                           did_throw = TRUE;
                        if (trycmd->tcd_caught && current_exception != NULL)
                        {
                            // discard the exception