aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--runtime/doc/userfunc.txt3
-rw-r--r--src/nvim/ex_eval.c15
-rw-r--r--src/nvim/ex_eval_defs.h1
-rw-r--r--test/old/testdir/test_user_func.vim61
4 files changed, 74 insertions, 6 deletions
diff --git a/runtime/doc/userfunc.txt b/runtime/doc/userfunc.txt
index 8b6462911d..b0384df454 100644
--- a/runtime/doc/userfunc.txt
+++ b/runtime/doc/userfunc.txt
@@ -410,7 +410,8 @@ Any return value of the deferred function is discarded. The function cannot
be followed by anything, such as "->func" or ".member". Currently `:defer
GetArg()->TheFunc()` does not work, it may work in a later version.
-Errors are reported but do not cause aborting execution of deferred functions.
+Errors are reported but do not cause aborting execution of deferred functions
+or altering execution outside of deferred functions.
No range is accepted. The function can be a partial with extra arguments, but
not with a dictionary. *E1300*
diff --git a/src/nvim/ex_eval.c b/src/nvim/ex_eval.c
index 7412757726..a47c9027a7 100644
--- a/src/nvim/ex_eval.c
+++ b/src/nvim/ex_eval.c
@@ -668,17 +668,21 @@ void exception_state_save(exception_state_T *estate)
estate->estate_did_throw = did_throw;
estate->estate_need_rethrow = need_rethrow;
estate->estate_trylevel = trylevel;
+ estate->estate_did_emsg = did_emsg;
}
/// Restore the current exception state from "estate"
void exception_state_restore(exception_state_T *estate)
{
- if (current_exception == NULL) {
- current_exception = estate->estate_current_exception;
+ // Handle any outstanding exceptions before restoring the state
+ if (did_throw) {
+ handle_did_throw();
}
- did_throw |= estate->estate_did_throw;
- need_rethrow |= estate->estate_need_rethrow;
- trylevel |= estate->estate_trylevel;
+ current_exception = estate->estate_current_exception;
+ did_throw = estate->estate_did_throw;
+ need_rethrow = estate->estate_need_rethrow;
+ trylevel = estate->estate_trylevel;
+ did_emsg = estate->estate_did_emsg;
}
/// Clear the current exception state
@@ -688,6 +692,7 @@ void exception_state_clear(void)
did_throw = false;
need_rethrow = false;
trylevel = 0;
+ did_emsg = 0;
}
// Flags specifying the message displayed by report_pending.
diff --git a/src/nvim/ex_eval_defs.h b/src/nvim/ex_eval_defs.h
index 442e4581cc..16b8d2f02b 100644
--- a/src/nvim/ex_eval_defs.h
+++ b/src/nvim/ex_eval_defs.h
@@ -126,6 +126,7 @@ struct exception_state_S {
bool estate_did_throw;
bool estate_need_rethrow;
int estate_trylevel;
+ int estate_did_emsg;
};
#endif // NVIM_EX_EVAL_DEFS_H
diff --git a/test/old/testdir/test_user_func.vim b/test/old/testdir/test_user_func.vim
index d65f70445d..fc7dcd62b8 100644
--- a/test/old/testdir/test_user_func.vim
+++ b/test/old/testdir/test_user_func.vim
@@ -827,7 +827,68 @@ func Test_defer_after_exception()
delfunc Defer
delfunc Foo
+ delfunc Bar
unlet g:callTrace
endfunc
+" Test for multiple deferred function which throw exceptions.
+" Exceptions thrown by deferred functions should result in error messages but
+" not propagated into the calling functions.
+func Test_multidefer_with_exception()
+ let g:callTrace = []
+ func Except()
+ let g:callTrace += [1]
+ throw 'InnerException'
+ let g:callTrace += [2]
+ endfunc
+
+ func FirstDefer()
+ let g:callTrace += [3]
+ let g:callTrace += [4]
+ endfunc
+
+ func SecondDeferWithExcept()
+ let g:callTrace += [5]
+ call Except()
+ let g:callTrace += [6]
+ endfunc
+
+ func ThirdDefer()
+ let g:callTrace += [7]
+ let g:callTrace += [8]
+ endfunc
+
+ func Foo()
+ let g:callTrace += [9]
+ defer FirstDefer()
+ defer SecondDeferWithExcept()
+ defer ThirdDefer()
+ let g:callTrace += [10]
+ endfunc
+
+ let v:errmsg = ''
+ try
+ let g:callTrace += [11]
+ call Foo()
+ let g:callTrace += [12]
+ catch /TestException/
+ let g:callTrace += [13]
+ catch
+ let g:callTrace += [14]
+ finally
+ let g:callTrace += [15]
+ endtry
+ let g:callTrace += [16]
+
+ call assert_equal('E605: Exception not caught: InnerException', v:errmsg)
+ call assert_equal([11, 9, 10, 7, 8, 5, 1, 3, 4, 12, 15, 16], g:callTrace)
+
+ unlet g:callTrace
+ delfunc Except
+ delfunc FirstDefer
+ delfunc SecondDeferWithExcept
+ delfunc ThirdDefer
+ delfunc Foo
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab