[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
bug#60974: 30.0.50; byte-compile-preprocess mutates self evaluating form
From: |
Vibhav Pant |
Subject: |
bug#60974: 30.0.50; byte-compile-preprocess mutates self evaluating forms in expanded macro bodies |
Date: |
Fri, 27 Jan 2023 18:14:39 +0530 |
User-agent: |
Evolution 3.46.3 |
On Sat, 2023-01-21 at 00:43 -0500, Stefan Monnier wrote:
> > The attached patch should fix this, thoughts?
>
> It's not really an option:
> - it's expensive
> - it breaks code when it doesn't form a tree, e.g.
>
> (list '#1=(a b #1#) 'c 'd)
>
> Instead, we need to find out where in the code we perform the
> side effect and change just that part.
>
>
> Stefan
>
Ah, right. Theother way I could think of a fix is setq-ing `form` to a
shallow copy of the original form, with only the place(s) changed. This
patch tries to do that by using `pcase-let` to destructure forms.
--
Vibhav Pant
vibhavp@gmail.com
GPG: 7ED1 D48C 513C A024 BE3A 785F E3FB 28CB 6AB5 9598
diff --git a/lisp/emacs-lisp/cconv.el b/lisp/emacs-lisp/cconv.el
index e715bd90a00..f6160a13579 100644
--- a/lisp/emacs-lisp/cconv.el
+++ b/lisp/emacs-lisp/cconv.el
@@ -477,20 +477,37 @@ cconv-convert
branch))
cond-forms)))
- (`(function (lambda ,args . ,body) . ,_)
+ (`(function (lambda ,args . ,body) . ,rest)
(let* ((docstring (if (eq :documentation (car-safe (car body)))
(cconv-convert (cadr (pop body)) env extend)))
(bf (if (stringp (car body)) (cdr body) body))
(if (when (eq 'interactive (car-safe (car bf)))
(gethash form cconv--interactive-form-funs)))
(cif (when if (cconv-convert if env extend)))
- (_ (pcase cif
- (`#'(lambda () ,form) (setf (cadr (car bf)) form) (setq cif
nil))
- ('nil nil)
- ;; The interactive form needs special treatment, so the form
- ;; inside the `interactive' won't be used any further.
- (_ (setf (cadr (car bf)) nil))))
- (cf (cconv--convert-function args body env form docstring)))
+ (cf nil))
+ (pcase cif
+ (`#'(lambda () ,form)
+ (pcase-let ((`((,f1 . (,_ . ,f2)) . ,f3) bf))
+ (setq bf `((,f1 . (,form . ,f2)) . ,f3)))
+ (setq cif nil))
+ ('nil (setq bf nil))
+ ;; The interactive form needs special treatment, so the form
+ ;; inside the `interactive' won't be used any further.
+ (_ (pcase-let ((`((,f1 . (,_ . ,f2)) . ,f3) bf))
+ (setq bf `((,f1 . (nil . ,f2)) . ,f3)))))
+ (when bf
+ ;; If we modified bf, re-build body and form as
+ ;; copies with the modified bits.
+ (setq body (if (stringp (car body))
+ (cons (car body) bf)
+ bf)
+ form `(function (lambda ,args . ,body) . ,rest))
+ ;; Also, remove the current old entry on the alist, replacing
+ ;; it with the new one.
+ (let ((entry (pop cconv-freevars-alist)))
+ (push (cons body (cdr entry)) cconv-freevars-alist)))
+ (setq cf (cconv--convert-function args body env form docstring))
+
(if (not cif)
;; Normal case, the interactive form needs no special treatment.
cf
signature.asc
Description: This is a digitally signed message part
bug#60974: [PATCH] 30.0.50; byte-compile-preprocess mutates self evaluating forms in expanded macro bodies, Vibhav Pant, 2023/01/20