]> git.eshelyaron.com Git - emacs.git/commitdiff
Correctly unload variable aliases.
authorJens Schmidt <jschmidt4gnu@vodafonemail.de>
Fri, 14 Mar 2025 22:07:11 +0000 (23:07 +0100)
committerEshel Yaron <me@eshelyaron.com>
Mon, 17 Mar 2025 11:05:33 +0000 (12:05 +0100)
* 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)

lisp/loadhist.el
src/eval.c
test/lisp/loadhist-resources/loadhist--alias.el [new file with mode: 0644]
test/lisp/loadhist-tests.el
test/src/eval-tests.el

index 2298ae73736585528e1513f97bb5e20ee33fadb1..d063fb6cc43f6bc837d531b7fe4e6ea8d9957cb5 100644 (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)))
index ef1db469f904021756b4ac8514f22839afe7c2fb..42ad74c70de72cc6ce314ff920e5e4957e155774 100644 (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)
 {
@@ -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 (file)
index 0000000..96f1b77
--- /dev/null
@@ -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
index 0f1cedf9c7f85ef6db9baeedcab4d16415f8047c..3bc8bbb01896e0902237d19f0bff412b91791463 100644 (file)
   (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
index c5a46b62ee2c107815df149000457093f78d75fc..64a108f87449ac87b3a883d0da18203cf82cead0 100644 (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 ()