diff options
| author | Stefan Monnier | 2023-12-25 21:41:08 -0500 |
|---|---|---|
| committer | Stefan Monnier | 2023-12-28 01:17:21 -0500 |
| commit | 26b7078705ae5b9226c99e370740ab9a4063f20f (patch) | |
| tree | 45f130466b1c6cddf5ae705a49e410979ac183a7 /src/eval.c | |
| parent | b925152bffce30abbd48361af6858cd45b785d84 (diff) | |
| download | emacs-scratch/handler-bind.tar.gz emacs-scratch/handler-bind.zip | |
(backtrace-on-redisplay-error): Use `handler-bind`scratch/handler-bind
Reimplement `backtrace-on-redisplay-error` using `push_handler_bind`.
This moves the code from `signal_or_quit` to `xdisp.c` and
`debug-early.el`.
* lisp/emacs-lisp/debug-early.el (debug-early-backtrace):
Add `base` arg to strip "internal" frames.
(debug--early): New function, extracted from `debug-early`.
(debug-early, debug-early--handler): Use it.
(debug-early--muted): New function, extracted (translated) from
`signal_or_quit`; trim the buffer to a max of 10 backtraces.
* src/xdisp.c (funcall_with_backtraces): New function.
(dsafe_calln): Use it.
(syms_of_xdisp): Defsym `Qdebug_early__muted`.
* src/eval.c (redisplay_deep_handler): Delete var.
(init_eval, internal_condition_case_n): Don't set it any more.
(backtrace_yet): Delete var.
(signal_or_quit): Remove special case for `backtrace_on_redisplay_error`.
* src/keyboard.c (command_loop_1): Don't set `backtrace_yet` any more.
* src/lisp.h (backtrace_yet): Don't declare.
Diffstat (limited to 'src/eval.c')
| -rw-r--r-- | src/eval.c | 67 |
1 files changed, 6 insertions, 61 deletions
diff --git a/src/eval.c b/src/eval.c index 0cff38ce7a8..3e352911479 100644 --- a/src/eval.c +++ b/src/eval.c | |||
| @@ -57,12 +57,6 @@ Lisp_Object Vrun_hooks; | |||
| 57 | /* FIXME: We should probably get rid of this! */ | 57 | /* FIXME: We should probably get rid of this! */ |
| 58 | Lisp_Object Vsignaling_function; | 58 | Lisp_Object Vsignaling_function; |
| 59 | 59 | ||
| 60 | /* The handler structure which will catch errors in Lisp hooks called | ||
| 61 | from redisplay. We do not use it for this; we compare it with the | ||
| 62 | handler which is about to be used in signal_or_quit, and if it | ||
| 63 | matches, cause a backtrace to be generated. */ | ||
| 64 | static struct handler *redisplay_deep_handler; | ||
| 65 | |||
| 66 | /* These would ordinarily be static, but they need to be visible to GDB. */ | 60 | /* These would ordinarily be static, but they need to be visible to GDB. */ |
| 67 | bool backtrace_p (union specbinding *) EXTERNALLY_VISIBLE; | 61 | bool backtrace_p (union specbinding *) EXTERNALLY_VISIBLE; |
| 68 | Lisp_Object *backtrace_args (union specbinding *) EXTERNALLY_VISIBLE; | 62 | Lisp_Object *backtrace_args (union specbinding *) EXTERNALLY_VISIBLE; |
| @@ -244,7 +238,6 @@ init_eval (void) | |||
| 244 | lisp_eval_depth = 0; | 238 | lisp_eval_depth = 0; |
| 245 | /* This is less than the initial value of num_nonmacro_input_events. */ | 239 | /* This is less than the initial value of num_nonmacro_input_events. */ |
| 246 | when_entered_debugger = -1; | 240 | when_entered_debugger = -1; |
| 247 | redisplay_deep_handler = NULL; | ||
| 248 | } | 241 | } |
| 249 | 242 | ||
| 250 | static void | 243 | static void |
| @@ -1611,16 +1604,12 @@ internal_condition_case_n (Lisp_Object (*bfun) (ptrdiff_t, Lisp_Object *), | |||
| 1611 | ptrdiff_t nargs, | 1604 | ptrdiff_t nargs, |
| 1612 | Lisp_Object *args)) | 1605 | Lisp_Object *args)) |
| 1613 | { | 1606 | { |
| 1614 | struct handler *old_deep = redisplay_deep_handler; | ||
| 1615 | struct handler *c = push_handler (handlers, CONDITION_CASE); | 1607 | struct handler *c = push_handler (handlers, CONDITION_CASE); |
| 1616 | if (redisplaying_p) | ||
| 1617 | redisplay_deep_handler = c; | ||
| 1618 | if (sys_setjmp (c->jmp)) | 1608 | if (sys_setjmp (c->jmp)) |
| 1619 | { | 1609 | { |
| 1620 | Lisp_Object val = handlerlist->val; | 1610 | Lisp_Object val = handlerlist->val; |
| 1621 | clobbered_eassert (handlerlist == c); | 1611 | clobbered_eassert (handlerlist == c); |
| 1622 | handlerlist = handlerlist->next; | 1612 | handlerlist = handlerlist->next; |
| 1623 | redisplay_deep_handler = old_deep; | ||
| 1624 | return hfun (val, nargs, args); | 1613 | return hfun (val, nargs, args); |
| 1625 | } | 1614 | } |
| 1626 | else | 1615 | else |
| @@ -1628,7 +1617,6 @@ internal_condition_case_n (Lisp_Object (*bfun) (ptrdiff_t, Lisp_Object *), | |||
| 1628 | Lisp_Object val = bfun (nargs, args); | 1617 | Lisp_Object val = bfun (nargs, args); |
| 1629 | eassert (handlerlist == c); | 1618 | eassert (handlerlist == c); |
| 1630 | handlerlist = c->next; | 1619 | handlerlist = c->next; |
| 1631 | redisplay_deep_handler = old_deep; | ||
| 1632 | return val; | 1620 | return val; |
| 1633 | } | 1621 | } |
| 1634 | } | 1622 | } |
| @@ -1766,11 +1754,6 @@ quit (void) | |||
| 1766 | return signal_or_quit (Qquit, Qnil, true); | 1754 | return signal_or_quit (Qquit, Qnil, true); |
| 1767 | } | 1755 | } |
| 1768 | 1756 | ||
| 1769 | /* Has an error in redisplay giving rise to a backtrace occurred as | ||
| 1770 | yet in the current command? This gets reset in the command | ||
| 1771 | loop. */ | ||
| 1772 | bool backtrace_yet = false; | ||
| 1773 | |||
| 1774 | /* Signal an error, or quit. ERROR_SYMBOL and DATA are as with Fsignal. | 1757 | /* Signal an error, or quit. ERROR_SYMBOL and DATA are as with Fsignal. |
| 1775 | If CONTINUABLE, the caller allows this function to return | 1758 | If CONTINUABLE, the caller allows this function to return |
| 1776 | (presumably after calling the debugger); | 1759 | (presumably after calling the debugger); |
| @@ -1897,51 +1880,13 @@ signal_or_quit (Lisp_Object error_symbol, Lisp_Object data, bool continuable) | |||
| 1897 | return Qnil; | 1880 | return Qnil; |
| 1898 | } | 1881 | } |
| 1899 | 1882 | ||
| 1900 | /* If an error is signaled during a Lisp hook in redisplay, write a | ||
| 1901 | backtrace into the buffer *Redisplay-trace*. */ | ||
| 1902 | /* FIXME: Turn this into a `handler-bind` installed during redisplay? */ | ||
| 1903 | if (!debugger_called && !oom | ||
| 1904 | && backtrace_on_redisplay_error | ||
| 1905 | && (NILP (clause) || h == redisplay_deep_handler) | ||
| 1906 | && NILP (Vinhibit_debugger) | ||
| 1907 | && !NILP (Ffboundp (Qdebug_early))) | ||
| 1908 | { | ||
| 1909 | specpdl_ref count = SPECPDL_INDEX (); | ||
| 1910 | max_ensure_room (100); | ||
| 1911 | AUTO_STRING (redisplay_trace, "*Redisplay-trace*"); | ||
| 1912 | Lisp_Object redisplay_trace_buffer; | ||
| 1913 | AUTO_STRING (gap, "\n\n\n\n"); /* Separates things in *Redisplay-trace* */ | ||
| 1914 | Lisp_Object delayed_warning; | ||
| 1915 | redisplay_trace_buffer = Fget_buffer_create (redisplay_trace, Qnil); | ||
| 1916 | current_buffer = XBUFFER (redisplay_trace_buffer); | ||
| 1917 | if (!backtrace_yet) /* Are we on the first backtrace of the command? */ | ||
| 1918 | Ferase_buffer (); | ||
| 1919 | else | ||
| 1920 | Finsert (1, &gap); | ||
| 1921 | backtrace_yet = true; | ||
| 1922 | specbind (Qstandard_output, redisplay_trace_buffer); | ||
| 1923 | specbind (Qdebugger, Qdebug_early); | ||
| 1924 | call_debugger (list2 (Qerror, error)); | ||
| 1925 | unbind_to (count, Qnil); | ||
| 1926 | delayed_warning = make_string | ||
| 1927 | ("Error in a redisplay Lisp hook. See buffer *Redisplay-trace*", 61); | ||
| 1928 | |||
| 1929 | Vdelayed_warnings_list = Fcons (list2 (Qerror, delayed_warning), | ||
| 1930 | Vdelayed_warnings_list); | ||
| 1931 | } | ||
| 1932 | |||
| 1933 | if (!NILP (clause)) | 1883 | if (!NILP (clause)) |
| 1934 | { | 1884 | unwind_to_catch (h, NONLOCAL_EXIT_SIGNAL, error); |
| 1935 | unwind_to_catch (h, NONLOCAL_EXIT_SIGNAL, error); | 1885 | else if (handlerlist != handlerlist_sentinel) |
| 1936 | } | 1886 | /* FIXME: This will come right back here if there's no `top-level' |
| 1937 | else | 1887 | catcher. A better solution would be to abort here, and instead |
| 1938 | { | 1888 | add a catch-all condition handler so we never come here. */ |
| 1939 | if (handlerlist != handlerlist_sentinel) | 1889 | Fthrow (Qtop_level, Qt); |
| 1940 | /* FIXME: This will come right back here if there's no `top-level' | ||
| 1941 | catcher. A better solution would be to abort here, and instead | ||
| 1942 | add a catch-all condition handler so we never come here. */ | ||
| 1943 | Fthrow (Qtop_level, Qt); | ||
| 1944 | } | ||
| 1945 | 1890 | ||
| 1946 | string = Ferror_message_string (error); | 1891 | string = Ferror_message_string (error); |
| 1947 | fatal ("%s", SDATA (string)); | 1892 | fatal ("%s", SDATA (string)); |