mirror of
https://github.com/neovim/neovim.git
synced 2025-10-08 02:46:31 +00:00
fix(exceptions): restore did_throw
(#20000)
`!did_throw` doesn't exactly imply `!current_exception`, as `did_throw = false` is sometimes used to defer exception handling for later (without forgetting the exception). E.g: uncaught exception handling in `do_cmdline()` may be deferred to a different call (e.g: when `try_level > 0`). In #7881, `current_exception = NULL` in `do_cmdline()` is used as an analogue of `did_throw = false`, but also causes the pending exception to be lost, which also leaks as `discard_exception()` wasn't used. It may be possible to fix this by saving/restoring `current_exception`, but handling all of `did_throw`'s edge cases seems messier. Maybe not worth diverging over. This fix also uncovers a `man_spec.lua` bug on Windows: exceptions are thrown due to Windows missing `man`, but they're lost; skip these tests if `man` isn't executable.
This commit is contained in:
@@ -58,6 +58,7 @@ void try_enter(TryState *const tstate)
|
||||
.private_msg_list = NULL,
|
||||
.trylevel = trylevel,
|
||||
.got_int = got_int,
|
||||
.did_throw = did_throw,
|
||||
.need_rethrow = need_rethrow,
|
||||
.did_emsg = did_emsg,
|
||||
};
|
||||
@@ -65,6 +66,7 @@ void try_enter(TryState *const tstate)
|
||||
current_exception = NULL;
|
||||
trylevel = 1;
|
||||
got_int = false;
|
||||
did_throw = false;
|
||||
need_rethrow = false;
|
||||
did_emsg = false;
|
||||
}
|
||||
@@ -85,6 +87,7 @@ bool try_leave(const TryState *const tstate, Error *const err)
|
||||
assert(trylevel == 0);
|
||||
assert(!need_rethrow);
|
||||
assert(!got_int);
|
||||
assert(!did_throw);
|
||||
assert(!did_emsg);
|
||||
assert(msg_list == &tstate->private_msg_list);
|
||||
assert(*msg_list == NULL);
|
||||
@@ -93,6 +96,7 @@ bool try_leave(const TryState *const tstate, Error *const err)
|
||||
current_exception = tstate->current_exception;
|
||||
trylevel = tstate->trylevel;
|
||||
got_int = tstate->got_int;
|
||||
did_throw = tstate->did_throw;
|
||||
need_rethrow = tstate->need_rethrow;
|
||||
did_emsg = tstate->did_emsg;
|
||||
return ret;
|
||||
@@ -127,7 +131,7 @@ bool try_end(Error *err)
|
||||
force_abort = false;
|
||||
|
||||
if (got_int) {
|
||||
if (current_exception) {
|
||||
if (did_throw) {
|
||||
// If we got an interrupt, discard the current exception
|
||||
discard_current_exception();
|
||||
}
|
||||
@@ -146,7 +150,7 @@ bool try_end(Error *err)
|
||||
if (should_free) {
|
||||
xfree(msg);
|
||||
}
|
||||
} else if (current_exception) {
|
||||
} else if (did_throw) {
|
||||
api_set_error(err, kErrorTypeException, "%s", current_exception->value);
|
||||
discard_current_exception();
|
||||
}
|
||||
|
@@ -134,6 +134,7 @@ typedef struct {
|
||||
const msglist_T *const *msg_list;
|
||||
int trylevel;
|
||||
int got_int;
|
||||
bool did_throw;
|
||||
int need_rethrow;
|
||||
int did_emsg;
|
||||
} TryState;
|
||||
|
@@ -137,7 +137,7 @@ Object nvim_eval(String expr, Error *err)
|
||||
if (!recursive) {
|
||||
force_abort = false;
|
||||
suppress_errthrow = false;
|
||||
current_exception = NULL;
|
||||
did_throw = false;
|
||||
// `did_emsg` is set by emsg(), which cancels execution.
|
||||
did_emsg = false;
|
||||
}
|
||||
@@ -196,7 +196,7 @@ static Object _call_function(String fn, Array args, dict_T *self, Error *err)
|
||||
if (!recursive) {
|
||||
force_abort = false;
|
||||
suppress_errthrow = false;
|
||||
current_exception = NULL;
|
||||
did_throw = false;
|
||||
// `did_emsg` is set by emsg(), which cancels execution.
|
||||
did_emsg = false;
|
||||
}
|
||||
|
Reference in New Issue
Block a user