Don’t ignore -Wclobbered in eval.c

This fix is also prompted by Emacs bug#71744.
* src/eval.c (CACHEABLE): Remove.  All uses removed.
Do not ignore -Wclobbered.
(internal_lisp_condition_case): Fix violations of the C standard,
where setjmp clobbered oldhandlerlist, var, and clauses.
Rewrite to pacify GCC, by using a sentinel rather than a count,
which GCC incorrectly complained about, and by coalescing some
duplicate code.  If GCC_LINT && __GNUC__ && !__clang__ add a useless
assignment to pacify GCC.
This commit is contained in:
Paul Eggert 2024-08-16 17:08:36 -07:00
parent cfa5a634e9
commit 1282714da5

View file

@ -31,15 +31,6 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
#include "pdumper.h"
#include "atimer.h"
/* CACHEABLE is ordinarily nothing, except it is 'volatile' if
necessary to cajole GCC into not warning incorrectly that a
variable should be volatile. */
#if defined GCC_LINT || defined lint
# define CACHEABLE volatile
#else
# define CACHEABLE /* empty */
#endif
/* Non-nil means record all fset's and provide's, to be undone
if the file being autoloaded is not fully loaded.
They are recorded by being consed onto the front of Vautoload_queue:
@ -430,7 +421,7 @@ DEFUN ("progn", Fprogn, Sprogn, 0, UNEVALLED, 0,
usage: (progn BODY...) */)
(Lisp_Object body)
{
Lisp_Object CACHEABLE val = Qnil;
Lisp_Object val = Qnil;
while (CONSP (body))
{
@ -1257,12 +1248,6 @@ usage: (catch TAG BODY...) */)
return internal_catch (tag, Fprogn, XCDR (args));
}
/* Work around GCC bug 61118
<https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61118>. */
#if GNUC_PREREQ (4, 9, 0)
# pragma GCC diagnostic ignored "-Wclobbered"
#endif
/* Assert that E is true, but do not evaluate E. Use this instead of
eassert (E) when E contains variables that might be clobbered by a
longjmp. */
@ -1488,8 +1473,10 @@ Lisp_Object
internal_lisp_condition_case (Lisp_Object var, Lisp_Object bodyform,
Lisp_Object handlers)
{
struct handler *oldhandlerlist = handlerlist;
ptrdiff_t CACHEABLE clausenb = 0;
struct handler *volatile oldhandlerlist = handlerlist;
/* The number of non-success handlers, plus 1 for a sentinel. */
ptrdiff_t clausenb = 1;
var = maybe_remove_pos_from_symbol (var);
CHECK_TYPE (BARE_SYMBOL_P (var), Qsymbolp, var);
@ -1521,69 +1508,67 @@ internal_lisp_condition_case (Lisp_Object var, Lisp_Object bodyform,
memory_full (SIZE_MAX);
Lisp_Object volatile *clauses = alloca (clausenb * sizeof *clauses);
clauses += clausenb;
*--clauses = make_fixnum (0);
for (Lisp_Object tail = handlers; CONSP (tail); tail = XCDR (tail))
{
Lisp_Object tem = XCAR (tail);
if (!(CONSP (tem) && EQ (XCAR (tem), QCsuccess)))
*--clauses = tem;
}
for (ptrdiff_t i = 0; i < clausenb; i++)
Lisp_Object volatile var_volatile = var;
Lisp_Object val, handler_body;
for (Lisp_Object volatile *pcl = clauses; ; pcl++)
{
Lisp_Object clause = clauses[i];
if (BASE_EQ (*pcl, make_fixnum (0)))
{
val = eval_sub (bodyform);
handlerlist = oldhandlerlist;
if (NILP (success_handler))
return val;
#if GCC_LINT && __GNUC__ && !__clang__
/* This useless assignment pacifies GCC 14.2.1 x86-64
<https://gcc.gnu.org/bugzilla/show_bug.cgi?id=21161>. */
var = var_volatile;
#endif
handler_body = XCDR (success_handler);
break;
}
Lisp_Object clause = *pcl;
Lisp_Object condition = CONSP (clause) ? XCAR (clause) : Qnil;
if (!CONSP (condition))
condition = list1 (condition);
struct handler *c = push_handler (condition, CONDITION_CASE);
Lisp_Object volatile *clauses_volatile = clauses;
if (sys_setjmp (c->jmp))
{
Lisp_Object val = handlerlist->val;
Lisp_Object volatile *chosen_clause = clauses;
for (struct handler *h = handlerlist->next; h != oldhandlerlist;
h = h->next)
var = var_volatile;
val = handlerlist->val;
Lisp_Object volatile *chosen_clause = clauses_volatile;
struct handler *oldh = oldhandlerlist;
for (struct handler *h = handlerlist->next; h != oldh; h = h->next)
chosen_clause++;
Lisp_Object handler_body = XCDR (*chosen_clause);
handlerlist = oldhandlerlist;
handler_body = XCDR (*chosen_clause);
handlerlist = oldh;
if (NILP (var))
return Fprogn (handler_body);
Lisp_Object handler_var = var;
if (!NILP (Vinternal_interpreter_environment))
{
val = Fcons (Fcons (var, val),
Vinternal_interpreter_environment);
handler_var = Qinternal_interpreter_environment;
}
/* Bind HANDLER_VAR to VAL while evaluating HANDLER_BODY.
The unbind_to undoes just this binding; whoever longjumped
to us unwound the stack to C->pdlcount before throwing. */
specpdl_ref count = SPECPDL_INDEX ();
specbind (handler_var, val);
return unbind_to (count, Fprogn (handler_body));
/* Whoever longjumped to us unwound the stack to C->pdlcount before
throwing, so the unbind_to will undo just this binding. */
break;
}
}
Lisp_Object CACHEABLE result = eval_sub (bodyform);
handlerlist = oldhandlerlist;
if (!NILP (success_handler))
if (NILP (var))
return Fprogn (handler_body);
if (!NILP (Vinternal_interpreter_environment))
{
if (NILP (var))
return Fprogn (XCDR (success_handler));
Lisp_Object handler_var = var;
if (!NILP (Vinternal_interpreter_environment))
{
result = Fcons (Fcons (var, result),
Vinternal_interpreter_environment);
handler_var = Qinternal_interpreter_environment;
}
specpdl_ref count = SPECPDL_INDEX ();
specbind (handler_var, result);
return unbind_to (count, Fprogn (XCDR (success_handler)));
val = Fcons (Fcons (var, val),
Vinternal_interpreter_environment);
var = Qinternal_interpreter_environment;
}
return result;
specpdl_ref count = SPECPDL_INDEX ();
specbind (var, val);
return unbind_to (count, Fprogn (handler_body));
}
/* Call the function BFUN with no arguments, catching errors within it
@ -1740,7 +1725,7 @@ push_handler (Lisp_Object tag_ch_val, enum handlertype handlertype)
struct handler *
push_handler_nosignal (Lisp_Object tag_ch_val, enum handlertype handlertype)
{
struct handler *CACHEABLE c = handlerlist->nextfree;
struct handler *c = handlerlist->nextfree;
if (!c)
{
c = malloc (sizeof *c);