Correctly unload variable aliases.

* src/eval.c (Finternal_delete_indirect_variable): Add function.
* lisp/loadhist.el (loadhist-unload-element): Use it for variable
aliases.
* test/src/eval-tests.el (eval-tests--internal-delete-indirect-variable):
Test function `internal-delete-indirect-variable'.
* test/lisp/loadhist-tests.el (loadhist-test-unload-feature-alias):
* test/lisp/loadhist-resources/loadhist--alias.el: Test unloading of
features that define variable aliases.  (Bug#76748)
This commit is contained in:
Jens Schmidt 2025-03-14 23:07:11 +01:00 committed by Stefan Monnier
parent b8104dadbf
commit 7f2e4508ce
5 changed files with 74 additions and 3 deletions

View file

@ -211,9 +211,13 @@ unloading."
(kill-local-variable x)))
(if (and (boundp x) (timerp (symbol-value x)))
(cancel-timer (symbol-value x)))
;; Get rid of the default binding if we can.
(unless (local-variable-if-set-p x)
(makunbound x)))
(cond
;; "Unbind" indirect variable.
((not (eq (indirect-variable x) x))
(internal-delete-indirect-variable x))
;; Get rid of the default binding if we can.
((not (local-variable-if-set-p x))
(makunbound x))))
(cl-defmethod loadhist-unload-element ((x (head define-type)))
(let* ((name (cdr x)))

View file

@ -720,6 +720,24 @@ signal a `cyclic-variable-indirection' error. */)
return base_variable;
}
DEFUN ("internal-delete-indirect-variable", Finternal_delete_indirect_variable, Sinternal_delete_indirect_variable,
1, 1, 0,
doc: /* Internal use only.
Undeclare SYMBOL as variable alias, then unbind it.
Return SYMBOL. */)
(register Lisp_Object symbol)
{
CHECK_SYMBOL (symbol);
if (XSYMBOL (symbol)->u.s.redirect != SYMBOL_VARALIAS)
xsignal2 (Qerror,
build_string ("Cannot undeclare a variable that is not an alias"),
symbol);
XSYMBOL (symbol)->u.s.redirect = SYMBOL_PLAINVAL;
Fput (symbol, Qvariable_documentation, Qnil);
Fset (symbol, Qunbound);
return symbol;
}
static union specbinding *
default_toplevel_binding (Lisp_Object symbol)
{
@ -4488,6 +4506,7 @@ alist of active lexical bindings. */);
defsubr (&Sdefvar_1);
defsubr (&Sdefvaralias);
DEFSYM (Qdefvaralias, "defvaralias");
defsubr (&Sinternal_delete_indirect_variable);
defsubr (&Sdefconst);
defsubr (&Sdefconst_1);
defsubr (&Sinternal__define_uninitialized_variable);

View file

@ -0,0 +1,28 @@
;;; loadhist--alias.el --- Dummy package for loadhist-tests -*- lexical-binding: t; -*-
;; Copyright (C) 2025 Free Software Foundation, Inc.
;; Author: Jens Schmidt <jschmidt4gnu@vodafonemail.de>
;; This file is part of GNU Emacs.
;; GNU Emacs is free software: you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation, either version 3 of the License, or
;; (at your option) any later version.
;; GNU Emacs is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;; You should have received a copy of the GNU General Public License
;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
;;; Code:
(defvaralias 'loadhist--alias-last-input-event 'last-input-event
"Alias on built-in variable.")
(provide 'loadhist--alias)
;;; loadhist--alias.el ends here

View file

@ -101,4 +101,12 @@
(should (null (get 'loadhist--bar-dec 'function-history)))
(should (null (get 'loadhist--foo-inc 'function-history))))
(ert-deftest loadhist-test-unload-feature-alias ()
"Check that bug#76748 has been fixed."
(add-to-list 'load-path (expand-file-name
"loadhist-resources/"
loadhist--tests-dir))
(load "loadhist--alias" nil t)
(unload-feature 'loadhist--alias))
;;; loadhist-tests.el ends here

View file

@ -282,6 +282,18 @@ expressions works for identifiers starting with period."
(should-error (defvaralias 'eval-tests--my-c 'eval-tests--my-d)
:type 'cyclic-variable-indirection))
(ert-deftest eval-tests--internal-delete-indirect-variable ()
(defvar eval-tests--i-d-i-v-var 'foo)
(defvaralias 'eval-tests--i-d-i-v-var1 'eval-tests--i-d-i-v-var "Doc string.")
(internal-delete-indirect-variable 'eval-tests--i-d-i-v-var1)
(should (eq (indirect-variable 'eval-tests--i-d-i-v-var1)
'eval-tests--i-d-i-v-var1))
(should-not (boundp 'eval-tests--i-d-i-v-var1))
(should-not (get 'eval-tests--i-d-i-v-var1 'variable-documentation))
(should-error (internal-delete-indirect-variable 'eval-tests--i-d-i-v-var)))
(defvar eval-tests/global-var 'global-value)
(defvar-local eval-tests/buffer-local-var 'default-value)
(ert-deftest eval-tests/default-value ()