aboutsummaryrefslogtreecommitdiffstats
path: root/lisp
diff options
context:
space:
mode:
authorStefan Monnier2022-05-25 17:53:39 -0400
committerStefan Monnier2022-05-26 12:21:32 -0400
commit80ba4c170756049a101b4e6692882ac30ba5e1a5 (patch)
tree6dd293220256c8ce06e474c9457a4e448f7dd7ee /lisp
parent77b5840d4ab37c1485745def5ec0c9b9f6cb137f (diff)
downloademacs-scratch/bug-55156.tar.gz
emacs-scratch/bug-55156.zip
eval.c: New functions `defvar-1` and `defconst-1` (bug#55156)scratch/bug-55156
The bytecode interpreter can't directly call special forms, so the byte-compiler usually converts special forms into some sequence of byte codes (basically, providing a duplicate definition of the special form). There are still two exceptions to this: `defconst` and `defvar`, where the compiler instead generates a convoluted chunk of code like: (funcall '(lambda (x) (defvar <sym> x <doc>)) <value>) where the quote makes sure we keep the function non-compiled, so as to end up running the special form at run time. Get rid of this workaround by introducing `defvar-1` and `defconst-1` which provide a *functional* interface to the functionality of the corresponding special form. * src/eval.c (defvar, Fdefvar_1, Fdefconst_1): New functions, extracted from `Fdefvar` and `Fdefconst`. (Fdefvar, Fdefconst): Use them. (syms_of_eval): `defsubr` the new functions. * lisp/emacs-lisp/bytecomp.el (byte-compile-tmp-var): Delete const. (byte-compile-defvar): Simplify using the new functions. * doc/lispref/variables.texi (Defining Variables): Adjust the doc of `defvar` to reflect the actual semantics implemented.
Diffstat (limited to 'lisp')
-rw-r--r--lisp/emacs-lisp/bytecomp.el23
1 files changed, 10 insertions, 13 deletions
diff --git a/lisp/emacs-lisp/bytecomp.el b/lisp/emacs-lisp/bytecomp.el
index d7140ad9e63..ee530f95d09 100644
--- a/lisp/emacs-lisp/bytecomp.el
+++ b/lisp/emacs-lisp/bytecomp.el
@@ -4943,8 +4943,6 @@ binding slots have been popped."
4943 (push (nth 1 (nth 1 form)) byte-compile-global-not-obsolete-vars)) 4943 (push (nth 1 (nth 1 form)) byte-compile-global-not-obsolete-vars))
4944 (byte-compile-normal-call form)) 4944 (byte-compile-normal-call form))
4945 4945
4946(defconst byte-compile-tmp-var (make-symbol "def-tmp-var"))
4947
4948(defun byte-compile-defvar (form) 4946(defun byte-compile-defvar (form)
4949 ;; This is not used for file-level defvar/consts. 4947 ;; This is not used for file-level defvar/consts.
4950 (when (and (symbolp (nth 1 form)) 4948 (when (and (symbolp (nth 1 form))
@@ -4977,18 +4975,17 @@ binding slots have been popped."
4977 string 4975 string
4978 "third arg to `%s %s' is not a string: %s" 4976 "third arg to `%s %s' is not a string: %s"
4979 fun var string)) 4977 fun var string))
4978 ;; Delegate the actual work to the function version of the
4979 ;; special form, named with a "-1" suffix.
4980 (byte-compile-form-do-effect 4980 (byte-compile-form-do-effect
4981 (if (cddr form) ; `value' provided 4981 (cond
4982 ;; Quote with `quote' to prevent byte-compiling the body, 4982 ((eq fun 'defconst) `(defconst-1 ',var ,@(nthcdr 2 form)))
4983 ;; which would lead to an inf-loop. 4983 ((not (cddr form)) `',var) ; A simple (defvar foo) just returns foo.
4984 `(funcall '(lambda (,byte-compile-tmp-var) 4984 (t `(defvar-1 ',var
4985 (,fun ,var ,byte-compile-tmp-var ,@(nthcdr 3 form))) 4985 ;; Don't eval `value' if `defvar' wouldn't eval it either.
4986 ,value) 4986 ,(if (macroexp-const-p value) value
4987 (if (eq fun 'defconst) 4987 `(if (boundp ',var) nil ,value))
4988 ;; This will signal an appropriate error at runtime. 4988 ,@(nthcdr 3 form)))))))
4989 `(eval ',form)
4990 ;; A simple (defvar foo) just returns foo.
4991 `',var)))))
4992 4989
4993(defun byte-compile-autoload (form) 4990(defun byte-compile-autoload (form)
4994 (and (macroexp-const-p (nth 1 form)) 4991 (and (macroexp-const-p (nth 1 form))