From: Jens Schmidt Date: Fri, 14 Mar 2025 22:07:11 +0000 (+0100) Subject: Correctly unload variable aliases. X-Git-Url: http://git.eshelyaron.com/gitweb/?a=commitdiff_plain;h=75cb6ed08acabd7cbc4c3e1099770a1bb9e59bb2;p=emacs.git 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) (cherry picked from commit 7f2e4508cebe76a885b72ca4789ae839d5bd45e1) --- diff --git a/lisp/loadhist.el b/lisp/loadhist.el index 2298ae73736..d063fb6cc43 100644 --- a/lisp/loadhist.el +++ b/lisp/loadhist.el @@ -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))) diff --git a/src/eval.c b/src/eval.c index ef1db469f90..42ad74c70de 100644 --- a/src/eval.c +++ b/src/eval.c @@ -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) { @@ -4489,6 +4507,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); diff --git a/test/lisp/loadhist-resources/loadhist--alias.el b/test/lisp/loadhist-resources/loadhist--alias.el new file mode 100644 index 00000000000..96f1b77c48d --- /dev/null +++ b/test/lisp/loadhist-resources/loadhist--alias.el @@ -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 + +;; 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 . + +;;; Code: + +(defvaralias 'loadhist--alias-last-input-event 'last-input-event + "Alias on built-in variable.") + +(provide 'loadhist--alias) +;;; loadhist--alias.el ends here diff --git a/test/lisp/loadhist-tests.el b/test/lisp/loadhist-tests.el index 0f1cedf9c7f..3bc8bbb0189 100644 --- a/test/lisp/loadhist-tests.el +++ b/test/lisp/loadhist-tests.el @@ -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 diff --git a/test/src/eval-tests.el b/test/src/eval-tests.el index c5a46b62ee2..64a108f8744 100644 --- a/test/src/eval-tests.el +++ b/test/src/eval-tests.el @@ -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 ()