From e4964de952a8246307faaf9875d2c278f42c53fc Mon Sep 17 00:00:00 2001 From: =?utf8?q?Mattias=20Engdeg=C3=A5rd?= Date: Thu, 22 Sep 2022 14:15:56 +0200 Subject: [PATCH] Don't rewrite `set` to `setq` of lexical variables Only perform the rewrite (set 'VAR X) -> (setq VAR X) for dynamic variables, as `set` isn't supposed to affect lexical vars (and never does so when interpreted). * lisp/emacs-lisp/byte-opt.el (byte-optimize-set): * test/lisp/emacs-lisp/bytecomp-tests.el (bytecomp-tests--xx): New. (bytecomp-tests--test-cases): Add test cases. * test/lisp/emacs-lisp/bytecomp-resources/warn-variable-set-nonvariable.el: Remove obsolete test. --- lisp/emacs-lisp/byte-opt.el | 19 ++++++++++--------- .../warn-variable-set-nonvariable.el | 3 --- test/lisp/emacs-lisp/bytecomp-tests.el | 15 ++++++++++++--- 3 files changed, 22 insertions(+), 15 deletions(-) delete mode 100644 test/lisp/emacs-lisp/bytecomp-resources/warn-variable-set-nonvariable.el diff --git a/lisp/emacs-lisp/byte-opt.el b/lisp/emacs-lisp/byte-opt.el index 0d5f8c26eb2..4ef9cb0a1e4 100644 --- a/lisp/emacs-lisp/byte-opt.el +++ b/lisp/emacs-lisp/byte-opt.el @@ -1531,15 +1531,16 @@ See Info node `(elisp) Integer Basics'." (put 'set 'byte-optimizer #'byte-optimize-set) (defun byte-optimize-set (form) - (let ((var (car-safe (cdr-safe form)))) - (cond - ((and (eq (car-safe var) 'quote) (consp (cdr var))) - `(setq ,(cadr var) ,@(cddr form))) - ((and (eq (car-safe var) 'make-local-variable) - (eq (car-safe (setq var (car-safe (cdr var)))) 'quote) - (consp (cdr var))) - `(progn ,(cadr form) (setq ,(cadr var) ,@(cddr form)))) - (t form)))) + (pcase (cdr form) + ;; Make sure we only turn `set' into `setq' for dynamic variables. + (`((quote ,(and var (guard (and (symbolp var) + (not (macroexp--const-symbol-p var)) + (not (assq var byte-optimize--lexvars)))))) + ,newval) + `(setq ,var ,newval)) + (`(,(and ml `(make-local-variable ,(and v `(quote ,_)))) ,newval) + `(progn ,ml (,(car form) ,v ,newval))) + (_ form))) ;; enumerating those functions which need not be called if the returned ;; value is not used. That is, something like diff --git a/test/lisp/emacs-lisp/bytecomp-resources/warn-variable-set-nonvariable.el b/test/lisp/emacs-lisp/bytecomp-resources/warn-variable-set-nonvariable.el deleted file mode 100644 index 0c76c4d388b..00000000000 --- a/test/lisp/emacs-lisp/bytecomp-resources/warn-variable-set-nonvariable.el +++ /dev/null @@ -1,3 +0,0 @@ -;;; -*- lexical-binding: t -*- -(defun foo () - (set '(a) nil)) diff --git a/test/lisp/emacs-lisp/bytecomp-tests.el b/test/lisp/emacs-lisp/bytecomp-tests.el index 1ca44dc7a48..e7c308213e4 100644 --- a/test/lisp/emacs-lisp/bytecomp-tests.el +++ b/test/lisp/emacs-lisp/bytecomp-tests.el @@ -59,6 +59,8 @@ inner loops respectively." (setq i (1- i))) res)) +(defvar bytecomp-tests--xx nil) + (defconst bytecomp-tests--test-cases '( ;; some functional tests @@ -692,6 +694,16 @@ inner loops respectively." (f (lambda () (let ((y x)) (list y 3 y))))) (funcall f)) + + ;; Test rewriting of `set' to `setq' (only done on dynamic variables). + (let ((xx 1)) (set 'xx 2) xx) + (let ((bytecomp-tests--xx 1)) + (set 'bytecomp-tests--xx 2) + bytecomp-tests--xx) + (let ((aaa 1)) (set (make-local-variable 'aaa) 2) aaa) + (let ((bytecomp-tests--xx 1)) + (set (make-local-variable 'bytecomp-tests--xx) 2) + bytecomp-tests--xx) ) "List of expressions for cross-testing interpreted and compiled code.") @@ -953,9 +965,6 @@ byte-compiled. Run with dynamic binding." (bytecomp--define-warning-file-test "warn-variable-set-constant.el" "attempt to set constant") -(bytecomp--define-warning-file-test "warn-variable-set-nonvariable.el" - "variable reference to nonvariable") - (bytecomp--define-warning-file-test "warn-variable-setq-nonvariable.el" "attempt to set non-variable") -- 2.39.2