Subject: bug#65797: `buffer-match-p` should not use `func-arity`

From: Stefan Monnier <[email-masked]>
Date: Fri, 13 Oct 2023 11:57:59 -0400

>> Then how 'bout something like the patch below which changes the
>> `&optional` into an `&rest` but tries to preserve compatibility with the
>> old calling convention.
> Personally, I figured that using &rest would already help with backward
> compatibility to an extent.

I don't have a good intuition for how important backward compatibility
is here, so I went for the "safe" choice.  But maybe we don't need to go
that far.  The patch below keeps the same compatibility hack as we
currently have but doesn't add any new compatibility, so it will break
those uses where `buffer-match-p` is called without additional args but
the predicate function still expects 2 args (where the second is always
nil).  Indeed, that case seemes extremely unlikely.

Eli, Stefan, WDYT?

        Stefan

diff --git a/lisp/subr.el b/lisp/subr.el
index e88815fa58c..b38a29058a4 100644
--- a/lisp/subr.el
+++ b/lisp/subr.el
@@ -7295,13 +7295,13 @@ string-lines
             (setq start (length string)))))
       (nreverse lines))))
 
-(defun buffer-match-p (condition buffer-or-name &optional arg)
+(defun buffer-match-p (condition buffer-or-name &rest args)
   "Return non-nil if BUFFER-OR-NAME matches CONDITION.
 CONDITION is either:
 - the symbol t, to always match,
 - the symbol nil, which never matches,
 - a regular expression, to match a buffer name,
-- a predicate function that takes BUFFER-OR-NAME and ARG as
+- a predicate function that takes BUFFER-OR-NAME plus ARGS as
   arguments, and returns non-nil if the buffer matches,
 - a cons-cell, where the car describes how to interpret the cdr.
   The car can be one of the following:
@@ -7326,9 +7326,14 @@ buffer-match-p
                       ((pred stringp)
                        (string-match-p condition (buffer-name buffer)))
                       ((pred functionp)
-                       (if (eq 1 (cdr (func-arity condition)))
-                           (funcall condition buffer-or-name)
-                         (funcall condition buffer-or-name arg)))
+                       (apply condition buffer-or-name
+                              (cond
+                               ;; Backward compatibility with
+                               ;;  Emacs-29 semantics.
+                               ((and args (null (cdr args))
+                                     (eq 1 (cdr (func-arity condition))))
+                                nil)
+                               (t args))))
                       (`(major-mode . ,mode)
                        (eq
                         (buffer-local-value 'major-mode buffer)
@@ -7350,17 +7355,17 @@ buffer-match-p
                 (throw 'match t)))))))
     (funcall match (list condition))))
 
-(defun match-buffers (condition &optional buffers arg)
+(defun match-buffers (condition &optional buffers &rest args)
   "Return a list of buffers that match CONDITION, or nil if none match.
 See `buffer-match-p' for various supported CONDITIONs.
 By default all buffers are checked, but the optional
 argument BUFFERS can restrict that: its value should be
 an explicit list of buffers to check.
-Optional argument ARG is passed to `buffer-match-p', for
+Optional arguments ARGS are passed to `buffer-match-p', for
 predicate conditions in CONDITION."
   (let (bufs)
     (dolist (buf (or buffers (buffer-list)))
-      (when (buffer-match-p condition (get-buffer buf) arg)
+      (when (apply #'buffer-match-p condition (get-buffer buf) args)
         (push buf bufs)))
     bufs))