GNU bug report logs -
#78056
31.0.50; bug in `cl-eval-when` with symbols with positions
Previous Next
To reply to this bug, email your comments to 78056 AT debbugs.gnu.org.
Toggle the display of automated, internal messages from the tracker.
Report forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#78056
; Package
emacs
.
(Fri, 25 Apr 2025 07:39:02 GMT)
Full text and
rfc822 format available.
Acknowledgement sent
to
David Ponce <da_vid <at> orange.fr>
:
New bug report received and forwarded. Copy sent to
bug-gnu-emacs <at> gnu.org
.
(Fri, 25 Apr 2025 07:39:02 GMT)
Full text and
rfc822 format available.
Message #5 received at submit <at> debbugs.gnu.org (full text, mbox):
[Message part 1 (text/plain, inline)]
Hello,
Following advice of S. Monnier, I am creating this specific bug report for
this issue discovered while working on bug report #77725. I am copying
the messages exchanged on this subject here.
I attached the test file cl-type-recipe2.el for the mentioned simple recipe
to reproduce the issue.
Thanks!
> On 2025-04-24 13:44, David Ponce wrote:
>> It seems the side effect is more general than just with cl-type.el.
>>
>> I attached cl-type-recipe2.el, another simple recipe to illustrate with
>> current `cl-deftype'.
>>
>> - Run emacs -Q and load cl-type-recipe2.el.
>> - Then in the scratch buffer eval:
>>
>> (symbol-plist 'cons-car-foo)
>> => (cl-deftype-handler #[nil ((list 'satisfies #'(lambda (x) (eq (car-safe x) 'foo)))) (t) nil "A cons with a `foo' car."])
>>
>> - Then open cl-type-recipe2.el and M-x emacs-lisp-byte-compile
>>
>> - Then in the scratch buffer eval again:
>>
>> (symbol-plist 'cons-car-foo)
>> => (cl-deftype-handler #[nil (`(#<symbol satisfies at 113> ,(#<symbol lambda at 125> (x) (#<symbol eq at 137> (#<symbol car-safe at 141> #<symbol x at 150>) '#<symbol foo at 154>)))) (t) nil "A cons with a `foo' car."])
>>
>> And, of course:
>>
>> (cl-typep '(foo) 'cons-car-foo)
>> => (invalid-function #<symbol lambda at 125>)
>>
>> Without compile in the `cl-eval-when' in `cl-deftype', there is no side effect.
>>
>> Hope it will help.
>>
>> David
>
> Another information which could be useful: if I replace (cl-eval-when (compile load eval) ...)
> by (eval-and-compile ...) in the definition of `cl-deftype', there is no side effect
> of the byte-compilation on the current definition.
>
> What I don't know is if the two forms are equivalent.
>
>
On 2025-04-24 21:44, Stefan Monnier wrote:
>> Another information which could be useful: if I replace (cl-eval-when
>> (compile load eval) ...) by (eval-and-compile ...) in the definition
>> of `cl-deftype', there is no side effect of the byte-compilation on
>> the current definition.
>
> It looks like this is a bug in `cl-eval-when` introduced when Alan added
> "symbol with positions" for better error reporting.
>
> Could you make it a separate bug-report?
>
>> What I don't know is if the two forms are equivalent.
>
> Obviously they don't do quite the same thing, but AFAIK they *should*
> behave the same, so I'd use `eval-and-compile`.
>
>
> Stefan
>
In GNU Emacs 31.0.50 (build 3, x86_64-pc-linux-gnu, GTK+ Version
3.24.43, cairo version 1.18.2) of 2025-04-22
Repository revision: 871ec9615a949e967bf7d19466eb9c56ed80ff7e
Repository branch: master
Windowing system distributor 'The X.Org Foundation', version 11.0.12101016
System Description: Fedora Linux 41 (KDE Plasma)
Configured using:
'configure --with-native-compilation=no
PKG_CONFIG_PATH=/usr/local/lib/pkgconfig:/usr/lib/pkgconfig'
Configured features:
ACL CAIRO DBUS FREETYPE GIF GLIB GMP GNUTLS GPM GSETTINGS HARFBUZZ JPEG
LCMS2 LIBOTF LIBSELINUX LIBSYSTEMD LIBXML2 M17N_FLT MODULES NOTIFY
INOTIFY PDUMPER PNG RSVG SECCOMP SOUND SQLITE3 THREADS TIFF
TOOLKIT_SCROLL_BARS TREE_SITTER WEBP X11 XDBE XIM XINERAMA XINPUT2 XPM
XRANDR GTK3 ZLIB
Important settings:
value of $LC_TIME: fr_FR.utf8
value of $LANG: fr_FR.UTF-8
locale-coding-system: utf-8-unix
[cl-type-recipe2.el (text/x-emacs-lisp, attachment)]
Information forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#78056
; Package
emacs
.
(Sun, 27 Apr 2025 05:14:02 GMT)
Full text and
rfc822 format available.
Message #8 received at 78056 <at> debbugs.gnu.org (full text, mbox):
[Message part 1 (text/plain, inline)]
>>> (cl-typep '(foo) 'cons-car-foo)
>>> => (invalid-function #<symbol lambda at 125>)
>>>
>>> Without compile in the `cl-eval-when' in `cl-deftype', there is no side effect.
To fix this problem, `cl-eval-when` would need to do the same kind of
`byte-run-strip-symbol-positions` dance as is done for
`eval-when-compile` and `eval-and-compile`.
But I suggest the patch below instead, which starts by acknowledging
that `cl-eval-when` doesn't actually distinguish if it's used at
top-level (it has an ugly hack which tries to do that, but only for those
`cl-eval-when` nested inside another `cl-eval-when`, which his
extremely rare, and even in those cases it's right only some of the
time).
So the patch throws away the ugly hack and just reduces `cl-eval-when`
to one of `eval-when-compile`, `eval-and-compile`, `progn`, or nil.
It might be worthwhile to improve our macro-expansion machinery to let
(compiler-)macros know if they're used at top-level or not, but that's
a larger undertaking and it will be easy to retro-fit it into this macro
if/when we do that.
Comments, objections?
Stefan
[cl-when.patch (text/x-diff, inline)]
diff --git a/lisp/emacs-lisp/cl-macs.el b/lisp/emacs-lisp/cl-macs.el
index a966ec5eaf6..0f748e01791 100644
--- a/lisp/emacs-lisp/cl-macs.el
+++ b/lisp/emacs-lisp/cl-macs.el
@@ -724,8 +724,6 @@ cl-destructuring-bind
;;; The `cl-eval-when' form.
-(defvar cl--not-toplevel nil)
-
;;;###autoload
(defmacro cl-eval-when (when &rest body)
"Control when BODY is evaluated.
@@ -733,31 +731,22 @@ cl-eval-when
If `load' is in WHEN, BODY is evaluated when loaded after top-level compile.
If `eval' is in WHEN, BODY is evaluated when interpreted or at non-top-level.
+Beware: the implementation currently fails to correctly distinguish top-level
+from non-top-level uses. Among other things, this means that `load' and `eval'
+are conflated.
+
\(fn (WHEN...) BODY...)"
(declare (indent 1) (debug (sexp body)))
- (if (and (macroexp-compiling-p)
- (not cl--not-toplevel) (not (boundp 'for-effect))) ;Horrible kludge.
- (let ((comp (or (memq 'compile when) (memq :compile-toplevel when)))
- (cl--not-toplevel t))
- (if (or (memq 'load when) (memq :load-toplevel when))
- (if comp (cons 'progn (mapcar #'cl--compile-time-too body))
- `(if nil nil ,@body))
- (progn (if comp (eval (cons 'progn body) lexical-binding)) nil)))
- (and (or (memq 'eval when) (memq :execute when))
- (cons 'progn body))))
-
-(defun cl--compile-time-too (form)
- (or (and (symbolp (car-safe form)) (get (car-safe form) 'byte-hunk-handler))
- (setq form (macroexpand
- form (cons '(cl-eval-when) macroexpand-all-environment))))
- (cond ((eq (car-safe form) 'progn)
- (cons 'progn (mapcar #'cl--compile-time-too (cdr form))))
- ((eq (car-safe form) 'cl-eval-when)
- (let ((when (nth 1 form)))
- (if (or (memq 'eval when) (memq :execute when))
- `(cl-eval-when (compile ,@when) ,@(cddr form))
- form)))
- (t (eval form lexical-binding) form)))
+ (let ((when-comp (or (memq 'compile when) (memq :compile-toplevel when)))
+ (when-eval (or (memq 'eval when) (memq :execute when)
+ (memq 'load when) (memq :load-toplevel when))))
+ (cond
+ ((and (macroexp-compiling-p) when-comp)
+ (if when-eval
+ `(eval-and-compile . ,body)
+ `(eval-when-compile . ,body)))
+ (when-eval
+ (macroexp-progn body)))))
;;;###autoload
(defmacro cl-load-time-value (form &optional _read-only)
Information forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#78056
; Package
emacs
.
(Sun, 27 Apr 2025 07:16:01 GMT)
Full text and
rfc822 format available.
Message #11 received at 78056 <at> debbugs.gnu.org (full text, mbox):
On 2025-04-27 07:13, Stefan Monnier wrote:
>>>> (cl-typep '(foo) 'cons-car-foo)
>>>> => (invalid-function #<symbol lambda at 125>)
>>>>
>>>> Without compile in the `cl-eval-when' in `cl-deftype', there is no side effect.
>
> To fix this problem, `cl-eval-when` would need to do the same kind of
> `byte-run-strip-symbol-positions` dance as is done for
> `eval-when-compile` and `eval-and-compile`.
>
> But I suggest the patch below instead, which starts by acknowledging
> that `cl-eval-when` doesn't actually distinguish if it's used at
> top-level (it has an ugly hack which tries to do that, but only for those
> `cl-eval-when` nested inside another `cl-eval-when`, which his
> extremely rare, and even in those cases it's right only some of the
> time).
>
> So the patch throws away the ugly hack and just reduces `cl-eval-when`
> to one of `eval-when-compile`, `eval-and-compile`, `progn`, or nil.
>
> It might be worthwhile to improve our macro-expansion machinery to let
> (compiler-)macros know if they're used at top-level or not, but that's
> a larger undertaking and it will be easy to retro-fit it into this macro
> if/when we do that.
>
> Comments, objections?
I don't have enough expertise to judge the merits of this patch, but it
seems to me a very good thing to bring `cl-eval-when' back to the standard
`eval-when-compile' and `eval-and-compile' cases as much as possible, if
only to improve the consistency of the code and simplify its maintenance.
Thanks!
Information forwarded
to
bug-gnu-emacs <at> gnu.org
:
bug#78056
; Package
emacs
.
(Sun, 27 Apr 2025 16:04:03 GMT)
Full text and
rfc822 format available.
Message #14 received at 78056 <at> debbugs.gnu.org (full text, mbox):
On 2025-04-27 09:15, David Ponce wrote:
> On 2025-04-27 07:13, Stefan Monnier wrote:
>>>>> (cl-typep '(foo) 'cons-car-foo)
>>>>> => (invalid-function #<symbol lambda at 125>)
>>>>>
>>>>> Without compile in the `cl-eval-when' in `cl-deftype', there is no side effect.
>>
>> To fix this problem, `cl-eval-when` would need to do the same kind of
>> `byte-run-strip-symbol-positions` dance as is done for
>> `eval-when-compile` and `eval-and-compile`.
>>
>> But I suggest the patch below instead, which starts by acknowledging
>> that `cl-eval-when` doesn't actually distinguish if it's used at
>> top-level (it has an ugly hack which tries to do that, but only for those
>> `cl-eval-when` nested inside another `cl-eval-when`, which his
>> extremely rare, and even in those cases it's right only some of the
>> time).
>>
>> So the patch throws away the ugly hack and just reduces `cl-eval-when`
>> to one of `eval-when-compile`, `eval-and-compile`, `progn`, or nil.
>>
>> It might be worthwhile to improve our macro-expansion machinery to let
>> (compiler-)macros know if they're used at top-level or not, but that's
>> a larger undertaking and it will be easy to retro-fit it into this macro
>> if/when we do that.
>>
>> Comments, objections?
>
> I don't have enough expertise to judge the merits of this patch, but it
> seems to me a very good thing to bring `cl-eval-when' back to the standard
> `eval-when-compile' and `eval-and-compile' cases as much as possible, if
> only to improve the consistency of the code and simplify its maintenance.
>
> Thanks!
I forgot to confirm that the patch fixed the issue :-)
Thanks!
This bug report was last modified 6 days ago.
Previous Next
GNU bug tracking system
Copyright (C) 1999 Darren O. Benham,
1997,2003 nCipher Corporation Ltd,
1994-97 Ian Jackson.