From: Stefan Monnier Date: Mon, 6 May 2019 16:37:00 +0000 (-0400) Subject: * lisp/custom.el: Avoid adding vars to load-history multiple times X-Git-Tag: emacs-27.0.90~2954^2~4 X-Git-Url: http://git.eshelyaron.com/gitweb/?a=commitdiff_plain;h=63091313490beee4c5ed9767195c2a3df98f0332;p=emacs.git * lisp/custom.el: Avoid adding vars to load-history multiple times Avoid the abuse of (eval `(defvar ...)) which tends to end up adding redundant entries in `load-history`, as discussed in https://lists.gnu.org/r/help-gnu-emacs/2019-03/msg00237.html (custom-initialize-default): Don't add to load-history. (custom-declare-variable): Use internal--define-uninitialized-variable and only add the var to load-history once. Do it before calling `initialize` so the special-variable-p flag is set. * src/eval.c (Finternal__define_uninitialized_variable): New function. (Fdefvar, Fdefconst): Use it. (syms_of_eval): Defsubr' it. --- diff --git a/lisp/custom.el b/lisp/custom.el index 53b8045f058..29bf9e570a8 100644 --- a/lisp/custom.el +++ b/lisp/custom.el @@ -56,8 +56,14 @@ Otherwise, if symbol has a `saved-value' property, it will evaluate the car of that and use it as the default binding for symbol. Otherwise, EXP will be evaluated and used as the default binding for symbol." - (eval `(defvar ,symbol ,(let ((sv (get symbol 'saved-value))) - (if sv (car sv) exp))))) + (condition-case nil + (default-toplevel-value symbol) ;Test presence of default value. + (void-variable + ;; The var is not initialized yet. + (set-default-toplevel-value + symbol (eval (let ((sv (get symbol 'saved-value))) + (if sv (car sv) exp)) + t))))) (defun custom-initialize-set (symbol exp) "Initialize SYMBOL based on EXP. @@ -188,18 +194,13 @@ set to nil, as the value is no longer rogue." (t (custom-handle-keyword symbol keyword value 'custom-variable)))))) + ;; Set the docstring, record the var on load-history, as well + ;; as set the special-variable-p flag. + (internal--define-uninitialized-variable symbol doc) (put symbol 'custom-requests requests) ;; Do the actual initialization. (unless custom-dont-initialize (funcall initialize symbol default))) - ;; Use defvar to set the docstring as well as the special-variable-p flag. - ;; FIXME: We should reproduce more of `defvar's behavior, such as the warning - ;; when the var is currently let-bound. - (if (not (default-boundp symbol)) - ;; Don't use defvar to avoid setting a default-value when undesired. - (when doc (put symbol 'variable-documentation doc)) - (eval `(defvar ,symbol nil ,@(when doc (list doc))))) - (push symbol current-load-list) (run-hooks 'custom-define-hook) symbol) diff --git a/src/eval.c b/src/eval.c index 3fd9a40a3a2..567c32e0d75 100644 --- a/src/eval.c +++ b/src/eval.c @@ -715,6 +715,25 @@ DEFUN ("set-default-toplevel-value", Fset_default_toplevel_value, return Qnil; } +DEFUN ("internal--define-uninitialized-variable", + Finternal__define_uninitialized_variable, + Sinternal__define_uninitialized_variable, 1, 2, 0, + doc: /* Define SYMBOL as a variable, with DOC as its docstring. +This is like `defvar' and `defconst' but without affecting the variable's +value. */) + (Lisp_Object symbol, Lisp_Object doc) +{ + XSYMBOL (symbol)->u.s.declared_special = true; + if (!NILP (doc)) + { + if (!NILP (Vpurify_flag)) + doc = Fpurecopy (doc); + Fput (symbol, Qvariable_documentation, doc); + } + LOADHIST_ATTACH (symbol); + return Qnil; +} + DEFUN ("defvar", Fdefvar, Sdefvar, 1, UNEVALLED, 0, doc: /* Define SYMBOL as a variable, and return SYMBOL. You are not required to define a variable in order to use it, but @@ -754,32 +773,25 @@ usage: (defvar SYMBOL &optional INITVALUE DOCSTRING) */) { if (!NILP (XCDR (tail)) && !NILP (XCDR (XCDR (tail)))) error ("Too many arguments"); + Lisp_Object exp = XCAR (tail); tem = Fdefault_boundp (sym); + tail = XCDR (tail); /* Do it before evaluating the initial value, for self-references. */ - XSYMBOL (sym)->u.s.declared_special = true; + Finternal__define_uninitialized_variable (sym, CAR (tail)); if (NILP (tem)) - Fset_default (sym, eval_sub (XCAR (tail))); + Fset_default (sym, eval_sub (exp)); else { /* Check if there is really a global binding rather than just a let binding that shadows the global unboundness of the var. */ union specbinding *binding = default_toplevel_binding (sym); if (binding && EQ (specpdl_old_value (binding), Qunbound)) { - set_specpdl_old_value (binding, eval_sub (XCAR (tail))); + set_specpdl_old_value (binding, eval_sub (exp)); } } - tail = XCDR (tail); - tem = Fcar (tail); - if (!NILP (tem)) - { - if (!NILP (Vpurify_flag)) - tem = Fpurecopy (tem); - Fput (sym, Qvariable_documentation, tem); - } - LOADHIST_ATTACH (sym); } else if (!NILP (Vinternal_interpreter_environment) && (SYMBOLP (sym) && !XSYMBOL (sym)->u.s.declared_special)) @@ -827,19 +839,12 @@ usage: (defconst SYMBOL INITVALUE [DOCSTRING]) */) docstring = XCAR (XCDR (XCDR (args))); } + Finternal__define_uninitialized_variable (sym, docstring); tem = eval_sub (XCAR (XCDR (args))); if (!NILP (Vpurify_flag)) tem = Fpurecopy (tem); - Fset_default (sym, tem); - XSYMBOL (sym)->u.s.declared_special = true; - if (!NILP (docstring)) - { - if (!NILP (Vpurify_flag)) - docstring = Fpurecopy (docstring); - Fput (sym, Qvariable_documentation, docstring); - } - Fput (sym, Qrisky_local_variable, Qt); - LOADHIST_ATTACH (sym); + Fset_default (sym, tem); /* FIXME: set-default-toplevel-value? */ + Fput (sym, Qrisky_local_variable, Qt); /* FIXME: Why? */ return sym; } @@ -4198,6 +4203,7 @@ alist of active lexical bindings. */); defsubr (&Sdefvaralias); DEFSYM (Qdefvaralias, "defvaralias"); defsubr (&Sdefconst); + defsubr (&Sinternal__define_uninitialized_variable); defsubr (&Smake_var_non_special); defsubr (&Slet); defsubr (&SletX);