Subject: bug#76470: 31.0.50; `setq-local` makes the var buffer-local too soon

From: Stefan Kangas <[email-masked]>
Date: Fri, 21 Feb 2025 17:01:48 +0000

Stefan Monnier via "Bug reports for GNU Emacs, the Swiss army knife of
text editors" <[email-masked]> writes:

> Po Lu has just pointed me to a bug in `setq-local` which shows up when
> you do something like:
>
>     (setq-local my-foo (progn (defvar my-foo 1000) my-foo))
>
> Commit afd088bd608 added a workaround for exactly this problem in one of
> the uses of `setq-local`.
>
> The problem is that `setq-local` does, fundamentally
>
>     (make-local-variable 'my-foo)
>     (let ((val (progn (defvar my-foo 1000) my-foo)))
>       (setq my-foo val)
>
> so that during the computation of `val`, the variable has already been
> made buffer-local but has not yet been assigned.  So the `defvar` will
> correctly define the default value of `my-foo` but `my-foo` will still
> be unbound in the current-buffer.
>
> I suggest we change the ordering to:
>
>     (let ((val (progn (defvar my-foo 1000) my-foo)))
>       (make-local-variable 'my-foo)
>       (setq my-foo val)
>
> As for how to implement that fix.  The simplest way is to just change
> the macro, of course.  But maybe a better way is to do it by introducing
> a `set-local` function (sibling to `set` and `set-default`) and then
> make the macro expand to a call to this function.

What are the benefits of adding a new function instead of just changing
the macro?

> When I discussed this with Po Lu he felt this was a risky subtle change
> which would interfere with a lot of code.  I was quite surprised at this
> reaction because my own gut feeling is that, while it is undoubtedly
> a subtle change, it's just a very straightforward bug-fix, highly
> unlikely to introduce problems.
>
> WDYT?

I agree that we should fix the bug.