vim-patch:9.0.2059: outstanding exceptions may be skipped (#25736)

Problem:  outstanding exceptions may be skipped
Solution: When restoring exception state, process remaining outstanding
          exceptions

closes: vim/vim#13386

0ab500dede

Co-authored-by: Yegappan Lakshmanan <yegappan@yahoo.com>
This commit is contained in:
zeertzjq 2023-10-21 18:46:52 +08:00 committed by GitHub
parent c049ce56cd
commit 9971bea6f1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 74 additions and 6 deletions

View File

@ -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*

View File

@ -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.

View File

@ -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

View File

@ -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