branch: externals/compat commit 4658ba6ea854af1e1e6154397c996c05c057d1b5 Author: Daniel Mendler <m...@daniel-mendler.de> Commit: Daniel Mendler <m...@daniel-mendler.de>
compat-macs: Restore runtime checks Compat uses runtime checks (boundp, fboundp) to ensure that existing definitions are never overridden, when Compat is loaded on a newer Emacs than it was compiled on. --- NEWS.org | 5 +++-- compat-macs.el | 53 ++++++++++++++++++++++++++++++++--------------------- 2 files changed, 35 insertions(+), 23 deletions(-) diff --git a/NEWS.org b/NEWS.org index 51912c1e5a..861c14b5e9 100644 --- a/NEWS.org +++ b/NEWS.org @@ -7,8 +7,9 @@ compatibility aliases, functions, macros and variables are installed. - Remove deprecated, prefixed compatibility functions. - Remove deprecated features ~compat-help~, ~compat-font-lock~ and ~compat-24~. -- Compat will check that the Emacs version which was used to compile Compat - equals the Emacs version at runtime. +- Compat uses runtime checks (boundp, fboundp) to ensure that existing + definitions are never overridden, when Compat is loaded on a newer Emacs than + it was compiled on. * Release of "Compat" Version 29.1.0.1 diff --git a/compat-macs.el b/compat-macs.el index 0d9a8b4f92..e9e3712cce 100644 --- a/compat-macs.el +++ b/compat-macs.el @@ -31,9 +31,7 @@ (defmacro compat-declare-version (version) "Set the Emacs version that is currently being handled to VERSION." (setq compat--current-version version) - `(unless (equal emacs-version ,emacs-version) - (error ,(format "Compat was compiled with Emacs %s, you are running %%s" emacs-version) - emacs-version))) + nil) (defun compat--format-docstring (type name docstring) "Format DOCSTRING for NAME of TYPE. @@ -118,21 +116,28 @@ REST are attributes and the function BODY." (not (string-prefix-p "compat--" (symbol-name realname))))) (error "%s: Invalid :realname name" realname)) - (let ((def-name ;; Name of the definition. May be nil -> no definition. - (if (not (fboundp name)) ;; If not bound, `name' should be bound. - name - ;; Use `:explicit' name if the function is already defined, - ;; and if version constraint is satisfied. - (and explicit - (version< emacs-version compat--current-version) - (intern (format "compat--%s" name)))))) - `(,@(when def-name - `((,(if (eq type 'macro) 'defmacro 'defun) - ,def-name ,arglist - ,(compat--format-docstring type name docstring) - ,@body))) + (let* ((defname ;; Name of the definition. May be nil -> no definition. + (if (not (fboundp name)) ;; If not bound, `name' should be bound. + name + ;; Use `:explicit' name if the function is already defined, + ;; and if version constraint is satisfied. + (and explicit + (version< emacs-version compat--current-version) + (intern (format "compat--%s" name))))) + (def (and defname + `(,(if (eq type 'macro) 'defmacro 'defun) + ,defname ,arglist + ,(compat--format-docstring type name docstring) + ,@body)))) + ;; An additional fboundp check is performed at runtime to make + ;; sure that we never redefine an existing definition if Compat + ;; is loaded on a newer Emacs version. + `(,@(when def + (if (eq defname name) + `((unless (fboundp ',name) ,def)) + (list def))) ,@(when realname - `((defalias ',realname #',(or def-name name))))))))) + `((defalias ',realname #',(or defname name))))))))) (defmacro compat-defalias (name def &rest attrs) "Define compatibility alias NAME as DEF. @@ -151,8 +156,11 @@ under which the definition is generated. non-nil." (compat--guarded-definition attrs () (lambda () - (unless (fboundp name) - `((defalias ',name ',def)))))) + ;; The fboundp check is performed at runtime to make sure that we never + ;; redefine an existing definition if Compat is loaded on a newer Emacs + ;; version. + `((unless (fboundp ',name) + (defalias ',name ',def)))))) (defmacro compat-defun (name arglist docstring &rest rest) "Define compatibility function NAME with arguments ARGLIST. @@ -216,8 +224,11 @@ definition is generated. (doc-string 3) (indent 2)) (compat--guarded-definition attrs '(:local :constant) (lambda (local constant) - (unless (boundp name) - `((,(if constant 'defconst 'defvar) + ;; The boundp check is performed at runtime to make sure that we never + ;; redefine an existing definition if Compat is loaded on a newer Emacs + ;; version. + `((unless (boundp ',name) + (,(if constant 'defconst 'defvar) ,name ,initval ,(compat--format-docstring 'variable name docstring)) ,@(cond