GNU bug report logs - #67116
byte-compile-let: reversing the order of evaluation of the clauses CAN make a difference.

Previous Next

Package: emacs;

Reported by: Alan Mackenzie <acm <at> muc.de>

Date: Sat, 11 Nov 2023 22:50:01 UTC

Severity: normal

Done: Mattias EngdegÄrd <mattias.engdegard <at> gmail.com>

Bug is archived. No further changes may be made.

Full log


Message #8 received at submit <at> debbugs.gnu.org (full text, mbox):

From: Stefan Monnier <monnier <at> iro.umontreal.ca>
To: Alan Mackenzie <acm <at> muc.de>
Cc: bug-gnu-emacs <at> gnu.org
Subject: Re: byte-compile-let: reversing the order of evaluation of the
 clauses CAN make a difference.
Date: Sat, 11 Nov 2023 23:52:38 -0500
> In lisp/emacs-lisp/bytecomp.el (byte-compile-let), when the following
> form (from jit-lock--debug-fontify):
>
>                           (let
>                               ((beg pos)
>                                 (end (setq pos
>                                                (next-single-property-change
>                                                 pos 'fontified
>                                                 nil (point-max)))))
>                             (put-text-property beg end 'fontified nil)
>                             (jit-lock-fontify-now beg end))
>
> gets byte compiled, the order of evaluating BEG and END gets reversed so
> that END gets evaluated first.

Sounds like a bug.  Do you have some recipe to reproduce it?
I looked at the bytecode but it's a bit hard to tell what's going on
there, since the var names are lost along the way.

> The comment in byte-compile-let:
>
>       ;; Bind the variables.
>       ;; For `let', do it in reverse order, because it makes no
>       ;; semantic difference, but it is a lot more efficient since the
>       ;; values are now in reverse order on the stack.
>
> , is not true.  It can make a semantic difference.  So doing the binding
> in reverse order is a bug.

Note that this is talking about the actual binding operations, which is
separate from the computation of the values that are to be given.
What this is saying is that

    (let ((X1 E1)
          (X2 E2))
      ...)

can be compiled to

    <compute E1>
    <compute E2>
    varbind X2
    varbind X1

since computing E pushes it value on the stack, so after the two
"compute" we have the values of E1 and E2 on the stack and we can pop
them in reverse order.  And indeed it should make no difference if we
do the `varbind X1` before or after `varbind X2` as long as they get
the right value and as long as we don't compute anything which depends
on those vars in-between.


        Stefan





This bug report was last modified 1 year and 245 days ago.

Previous Next


GNU bug tracking system
Copyright (C) 1999 Darren O. Benham, 1997,2003 nCipher Corporation Ltd, 1994-97 Ian Jackson.