emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

master f3ae26c: Fix local defvar scoping error (bug#46387)


From: Mattias Engdegård
Subject: master f3ae26c: Fix local defvar scoping error (bug#46387)
Date: Wed, 10 Feb 2021 08:47:47 -0500 (EST)

branch: master
commit f3ae26cb2ae581a84bbaa15a47e9917a799a5682
Author: Mattias Engdegård <mattiase@acm.org>
Commit: Mattias Engdegård <mattiase@acm.org>

    Fix local defvar scoping error (bug#46387)
    
    This bug was introduced by the lexical variable constant propagation
    mechanism.  It was discovered by Michael Heerdegen.
    
    * lisp/emacs-lisp/byte-opt.el (byte-optimize-let-form)
    (byte-optimize-body): Let the effects of a local defvar declaration be
    scoped by let and let*, not any arbitrary Lisp expression body (such
    as progn).
    * test/lisp/emacs-lisp/bytecomp-tests.el (bytecomp-tests--get-vars)
    (bytecomp-local-defvar): New test.
---
 lisp/emacs-lisp/byte-opt.el            |  4 ++--
 test/lisp/emacs-lisp/bytecomp-tests.el | 31 +++++++++++++++++++++++++++++++
 2 files changed, 33 insertions(+), 2 deletions(-)

diff --git a/lisp/emacs-lisp/byte-opt.el b/lisp/emacs-lisp/byte-opt.el
index 4fa2c75..8851f0e 100644
--- a/lisp/emacs-lisp/byte-opt.el
+++ b/lisp/emacs-lisp/byte-opt.el
@@ -698,7 +698,8 @@ Same format as `byte-optimize--lexvars', with shared 
structure and contents.")
               (append new-lexvars byte-optimize--lexvars))
         ;; Walk the body expressions, which may mutate some of the records,
         ;; and generate new bindings that exclude unused variables.
-        (let* ((opt-body (byte-optimize-body (cdr form) for-effect))
+        (let* ((byte-optimize--dynamic-vars byte-optimize--dynamic-vars)
+               (opt-body (byte-optimize-body (cdr form) for-effect))
                (bindings nil))
           (dolist (var let-vars)
             ;; VAR is (NAME EXPR [KEEP [VALUE]])
@@ -730,7 +731,6 @@ Same format as `byte-optimize--lexvars', with shared 
structure and contents.")
   ;; all-for-effect is true.  returns a new list of forms.
   (let ((rest forms)
        (result nil)
-        (byte-optimize--dynamic-vars byte-optimize--dynamic-vars)
        fe new)
     (while rest
       (setq fe (or all-for-effect (cdr rest)))
diff --git a/test/lisp/emacs-lisp/bytecomp-tests.el 
b/test/lisp/emacs-lisp/bytecomp-tests.el
index bc623d3..0b70c11 100644
--- a/test/lisp/emacs-lisp/bytecomp-tests.el
+++ b/test/lisp/emacs-lisp/bytecomp-tests.el
@@ -1168,6 +1168,37 @@ mountpoint (Bug#44631)."
       (with-demoted-errors "Error cleaning up directory: %s"
         (delete-directory directory :recursive)))))
 
+(defun bytecomp-tests--get-vars ()
+  (list (ignore-errors (symbol-value 'bytecomp-tests--var1))
+        (ignore-errors (symbol-value 'bytecomp-tests--var2))))
+
+(ert-deftest bytecomp-local-defvar ()
+  "Check that local `defvar' declarations work correctly, both
+interpreted and compiled."
+  (let ((lexical-binding t))
+    (let ((fun '(lambda ()
+                  (defvar bytecomp-tests--var1)
+                  (let ((bytecomp-tests--var1 'a)    ; dynamic
+                        (bytecomp-tests--var2 'b))   ; still lexical
+                    (ignore bytecomp-tests--var2)    ; avoid warning
+                    (bytecomp-tests--get-vars)))))
+      (should (listp fun))      ; Guard against overzealous refactoring!
+      (should (equal (funcall (eval fun t)) '(a nil)))
+      (should (equal (funcall (byte-compile fun)) '(a nil)))
+      )
+
+    ;; `progn' does not constitute a lexical scope for `defvar' (bug#46387).
+    (let ((fun '(lambda ()
+                  (progn
+                    (defvar bytecomp-tests--var1)
+                    (defvar bytecomp-tests--var2))
+                  (let ((bytecomp-tests--var1 'c)
+                        (bytecomp-tests--var2 'd))
+                    (bytecomp-tests--get-vars)))))
+      (should (listp fun))
+      (should (equal (funcall (eval fun t)) '(c d)))
+      (should (equal (funcall (byte-compile fun)) '(c d))))))
+
 ;; Local Variables:
 ;; no-byte-compile: t
 ;; End:



reply via email to

[Prev in Thread] Current Thread [Next in Thread]