Subject: bug#72313: 31.0.50; Warning about cl-member possibly being undefined when using cl-pushnew

From: Stefan Monnier <[email-masked]>
Date: Sat, 27 Jul 2024 03:01:32 -0400

> --8<---------------cut here---------------start------------->8---
> ;;  -*- lexical-binding: t; -*-
> (eval-when-compile
>   (require 'cl-lib))
>
> (defun foo ()
>   (let ((s (list 'a 'b)))
>     (cl-pushnew (list 1 2 3)
>                 s
>                 :test (lambda (_a _b) nil))))
> --8<---------------cut here---------------end--------------->8---

    (macroexpand-all '(cl-pushnew (list 1 2 3) s :test (lambda (_a _b) nil)))
=>
    (setq s
     (let* ((va (list 1 2 3)))
       (if (cl-member va s :test #'(lambda (_a _b) nil)) s (cons va s))))

> My assumption is that (eval-when-compile (require 'cl-lib)) should be
> fine when using only macros from cl-lib which in turn should expand to
> cl-free code,

That's not the case here (and a few other places).
In the past, I've moved some of this kind of code to `cl-preloaded`, so
as to make things easier for programmers (to avoid them having to know
which CL macros emit code which calls CL functions (and when)), but
there are still cases like above, yes.

In practice most complex macros are often best served by emitting code
which itself calls helper functions (e.g. `cl-defstruct` used to not
call a function but I changed it to call `cl-struct-define`).

        Stefan