GNU bug report logs - #78995
[PATCH] ;;;autoload-expand for special macros

Previous Next

Package: emacs;

Reported by: JD Smith <jdtsmith <at> gmail.com>

Date: Fri, 11 Jul 2025 19:29:02 UTC

Severity: normal

Tags: patch

Fixed in version 31

Done: "J.D. Smith" <jdtsmith <at> gmail.com>

To reply to this bug, email your comments to 78995 AT debbugs.gnu.org.
There is no need to reopen the bug first.

Toggle the display of automated, internal messages from the tracker.

View this report as an mbox folder, status mbox, maintainer mbox


Report forwarded to bug-gnu-emacs <at> gnu.org:
bug#78995; Package emacs. (Fri, 11 Jul 2025 19:29:02 GMT) Full text and rfc822 format available.

Acknowledgement sent to JD Smith <jdtsmith <at> gmail.com>:
New bug report received and forwarded. Copy sent to bug-gnu-emacs <at> gnu.org. (Fri, 11 Jul 2025 19:29:02 GMT) Full text and rfc822 format available.

Message #5 received at submit <at> debbugs.gnu.org (full text, mbox):

From: JD Smith <jdtsmith <at> gmail.com>
To: bug-gnu-emacs <at> gnu.org
Subject: [PATCH] ;;;autoload-expand for special macros
Date: Fri, 11 Jul 2025 15:28:03 -0400
[Message part 1 (text/plain, inline)]
As mentioned over on emacs-devel, it's sometimes a problem that `loaddefs-gen' hard-codes the list of special macros it is willing to expand:

(memq car '(easy-mmode-define-global-mode define-global-minor-mode
			    define-globalized-minor-mode defun defmacro
			    easy-mmode-define-minor-mode define-minor-mode
			    define-inline cl-defun cl-defmacro cl-defgeneric
			    cl-defstruct pcase-defmacro iter-defun cl-iter-defun))

This makes it challenging to wrap things like `define-minor-mode' into a new macro, and autoload the resulting forms.  This small patch adds a new variant of the autoload cookie:

;;;autoload-expand
(my-autoloadable-macro-to-expand ...)

which allows package authors to "opt-in" to macro expansion of the following form during autoload generation.  It would be useful primarily for special macros that are not in the hard-coded list above, but which expand to other special macros that are.

Docs can be added if this looks good.

[autoload-expand.patch (application/octet-stream, attachment)]
[Message part 3 (text/plain, inline)]


Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78995; Package emacs. (Sat, 12 Jul 2025 06:11:02 GMT) Full text and rfc822 format available.

Message #8 received at 78995 <at> debbugs.gnu.org (full text, mbox):

From: Eli Zaretskii <eliz <at> gnu.org>
To: JD Smith <jdtsmith <at> gmail.com>, Stefan Monnier <monnier <at> iro.umontreal.ca>,
 Philip Kaludercic <philipk <at> posteo.net>
Cc: 78995 <at> debbugs.gnu.org
Subject: Re: bug#78995: [PATCH] ;;;autoload-expand for special macros
Date: Sat, 12 Jul 2025 09:10:05 +0300
> From: JD Smith <jdtsmith <at> gmail.com>
> Date: Fri, 11 Jul 2025 15:28:03 -0400
> 
>  (defun loaddefs-generate--make-autoload (form file &optional expansion)
>    "Turn FORM into an autoload or defvar for source file FILE.
> -Returns nil if FORM is not a special autoload form (i.e. a function definition
> -or macro definition or a defcustom).
> -If EXPANSION is non-nil, we're processing the macro expansion of an
> -expression, in which case we want to handle forms differently."
> +Returns nil if FORM is not a special autoload form (i.e. a function
> +definition or macro definition or a defcustom).  If EXPANSION is
> +non-nil, we're processing the macro expansion of an expression, in which
> +case we want to handle forms differently.  If it the symbol `force',
                                                 ^^^^^^^^^^^^^
"it is the symbol".

Also, I wonder why you decided to refill the existing text.  A doc
string is easier readable if each argument's description starts on a
new line, because then it's easier to scan the doc string if you are
looking for the description of a specific argument.

And finally, the last sentence, which you added, doesn't really
explain the effect of the special value 'force' -- can we do a better
job describing that?

> -                              (or local-outfile main-outfile))))
> +                              (or local-outfile main-outfile)))
> +		   (expansion (and (looking-at "-expand[ \t]*") 'force)))

And this part seems to be completely undocumented?




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78995; Package emacs. (Sat, 12 Jul 2025 15:01:01 GMT) Full text and rfc822 format available.

Message #11 received at 78995 <at> debbugs.gnu.org (full text, mbox):

From: JD Smith <jdtsmith <at> gmail.com>
To: Eli Zaretskii <eliz <at> gnu.org>
Cc: Philip Kaludercic <philipk <at> posteo.net>, 78995 <at> debbugs.gnu.org,
 Stefan Monnier <monnier <at> iro.umontreal.ca>
Subject: Re: bug#78995: [PATCH] ;;;autoload-expand for special macros
Date: Sat, 12 Jul 2025 10:59:45 -0400
[Message part 1 (text/plain, inline)]
Thanks, improved doc-strings in the attached.  If this is looking good I can also update the `Autoload' section of the elisp manual, near "If you write a function definition with an unusual macro...".  I also noticed that `:autoload-end' is not mentioned there, and probably should be (this keyword marker halts further processing of forms in the macro expansion).

One question on nesting of macros: I'm wondering whether an ;;;###autoload-expand should result in using `EXPANSION=force' in all recursive calls to `loaddefs-generate--make-autoload'.  I.e. should all macros be _recursively_ expanded with `force'?  This would allow nesting, e.g. a macro wrapping a macro which itself wraps `define-minor-mode'.  But it would also expand all other macros encountered in the expansion, which could be problematic.  My instinct is that one level of such forced macro expansion is all that can be safely supported.

[autoload-expand.patch (application/octet-stream, attachment)]

Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78995; Package emacs. (Sat, 12 Jul 2025 16:11:01 GMT) Full text and rfc822 format available.

Message #14 received at 78995 <at> debbugs.gnu.org (full text, mbox):

From: Stefan Monnier <monnier <at> iro.umontreal.ca>
To: JD Smith <jdtsmith <at> gmail.com>
Cc: 78995 <at> debbugs.gnu.org
Subject: Re: bug#78995: [PATCH] ;;;autoload-expand for special macros
Date: Sat, 12 Jul 2025 12:09:55 -0400
> This makes it challenging to wrap things like `define-minor-mode' into a new
> macro, and autoload the resulting forms.  This small patch adds a new
> variant of the autoload cookie:
>
> ;;;autoload-expand
> (my-autoloadable-macro-to-expand ...)

I suspect this will often fail to work because autoloads are often
generated by a fresh new session where `my-autoloadable-macro-to-expand`
will not yet be defined.

So at the very least, your patch should make sure to signal an error
when the cookie is of the form `;;;autoload-expand` by the head is not
currently defined as a macro.

I've been wanting to add the feature you propose, but this "macro is not
defined" has gotten in the way until now.  I think we need to add
something like a file-local `autoload-requires-for-macros`.


        Stefan





Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78995; Package emacs. (Sat, 12 Jul 2025 16:13:02 GMT) Full text and rfc822 format available.

Message #17 received at 78995 <at> debbugs.gnu.org (full text, mbox):

From: Stefan Monnier <monnier <at> iro.umontreal.ca>
To: JD Smith <jdtsmith <at> gmail.com>
Cc: Eli Zaretskii <eliz <at> gnu.org>, 78995 <at> debbugs.gnu.org,
 Philip Kaludercic <philipk <at> posteo.net>
Subject: Re: bug#78995: [PATCH] ;;;autoload-expand for special macros
Date: Sat, 12 Jul 2025 12:12:42 -0400
> One question on nesting of macros: I'm wondering whether
> an ;;;###autoload-expand should result in using `EXPANSION=force' in all
> recursive calls to `loaddefs-generate--make-autoload'.  I.e. should all
> macros be _recursively_ expanded with `force'?  This would allow nesting,
> e.g. a macro wrapping a macro which itself wraps `define-minor-mode'.
> But it would also expand all other macros encountered in the expansion,
> which could be problematic.  My instinct is that one level of such forced
> macro expansion is all that can be safely supported.

Another way might be to replace the `;;;###autoload-expand` marker with
an list of of macros which should be expanded (i.e. a way to extent the
hardcoded list).


        Stefan





Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78995; Package emacs. (Sat, 12 Jul 2025 17:27:01 GMT) Full text and rfc822 format available.

Message #20 received at 78995 <at> debbugs.gnu.org (full text, mbox):

From: "J.D. Smith" <jdtsmith <at> gmail.com>
To: Stefan Monnier <monnier <at> iro.umontreal.ca>
Cc: 78995 <at> debbugs.gnu.org
Subject: Re: bug#78995: [PATCH] ;;;autoload-expand for special macros
Date: Sat, 12 Jul 2025 13:26:04 -0400
[Message part 1 (text/plain, inline)]
Stefan Monnier <monnier <at> iro.umontreal.ca> writes:

>> This makes it challenging to wrap things like `define-minor-mode' into a new
>> macro, and autoload the resulting forms.  This small patch adds a new
>> variant of the autoload cookie:
>>
>> ;;;autoload-expand
>> (my-autoloadable-macro-to-expand ...)
>
> I suspect this will often fail to work because autoloads are often
> generated by a fresh new session where `my-autoloadable-macro-to-expand`
> will not yet be defined.

Good point.  That chicken-and-egg problem was definitely in the back of
my mind, and is why I didn't attempt to create an expandable list to
replace the list of hard-coded special macros.

> I've been wanting to add the feature you propose, but this "macro is not
> defined" has gotten in the way until now.  I think we need to add
> something like a file-local `autoload-requires-for-macros`.

How about this solution?  If the car of the following form is not a
macro (and not a function), attempt to load the file itself (temporarily
expanding `load-path' to include the file's containing directory).  If
that fails to define the macro, warn the user, and simply proceed
without expansion.

[autoload-expand.patch (text/x-patch, inline)]
diff --git a/lisp/emacs-lisp/loaddefs-gen.el b/lisp/emacs-lisp/loaddefs-gen.el
index 0f136df1fe2..f7919a7a377 100644
--- a/lisp/emacs-lisp/loaddefs-gen.el
+++ b/lisp/emacs-lisp/loaddefs-gen.el
@@ -147,7 +147,10 @@ loaddefs-generate--make-autoload
 Returns nil if FORM is not a special autoload form (i.e. a function definition
 or macro definition or a defcustom).
 If EXPANSION is non-nil, we're processing the macro expansion of an
-expression, in which case we want to handle forms differently."
+expression, in which case we want to handle forms differently.  If
+EXPANSION is the symbol `force' and the following form is a macro call,
+it will be expanded prior to generating autoload forms, similar to what
+is done automatically for special macros like `define-minor-mode'."
   (let ((car (car-safe form)) expand)
     (cond
      ((and expansion (eq car 'defalias))
@@ -196,12 +199,13 @@ loaddefs-generate--make-autoload
                                       (cdr form)))))
           (when exps (cons 'progn exps)))))
 
-     ;; For complex cases, try again on the macro-expansion.
-     ((and (memq car '(easy-mmode-define-global-mode define-global-minor-mode
-                       define-globalized-minor-mode defun defmacro
-		       easy-mmode-define-minor-mode define-minor-mode
-                       define-inline cl-defun cl-defmacro cl-defgeneric
-                       cl-defstruct pcase-defmacro iter-defun cl-iter-defun))
+     ;; For complex cases and forced expansions, try again on the macro-expansion.
+     ((and (or (eq expansion 'force)
+	       (memq car '(easy-mmode-define-global-mode define-global-minor-mode
+			    define-globalized-minor-mode defun defmacro
+			    easy-mmode-define-minor-mode define-minor-mode
+			    define-inline cl-defun cl-defmacro cl-defgeneric
+			    cl-defstruct pcase-defmacro iter-defun cl-iter-defun)))
            (macrop car)
 	   (setq expand (let ((load-true-file-name file)
                               (load-file-name file))
@@ -381,6 +385,10 @@ loaddefs-generate--parse-file
 setting of `generated-autoload-file' in FILE, and
 by ;;;###foo-autoload statements.
 
+The special statement ;;;###[foo-]autoload-expand causes the following
+form to be macro-expanded prior to generating autoloads; see
+`loaddefs-generate--make-autoload'.
+
 If PACKAGE-DATA is `only', return only the package data.  If t,
 include the package data with the rest of the data.  Otherwise,
 don't include."
@@ -465,16 +473,38 @@ loaddefs-generate--parse-file
                                 (expand-file-name
                                  (concat aname "-loaddefs.el")
                                  (file-name-directory file))
-                              (or local-outfile main-outfile))))
+                              (or local-outfile main-outfile)))
+		   (expansion (and (looking-at "-expand[ \t]*") 'force)))
+	      (when expansion
+		(goto-char (match-end 0)))
               (if (eolp)
                   ;; We have a form following.
                   (let* ((form (prog1
                                    (read (current-buffer))
                                  (unless (bolp)
                                    (forward-line 1))))
-                         (autoload (or (loaddefs-generate--make-autoload
-                                        form load-name)
-                                       form)))
+                         (car (car form))
+                         autoload)
+                    (when expansion
+                      ;; We encountered ;;;###autoload-expand, so the
+                      ;; following form should be a macro.  Check that
+                      ;; it is defined.  If it is undefined (and not a
+                      ;; function), load the file to attempt to define
+                      ;; it.  If it remains undefined, warn and simply
+                      ;; ignore the expand request.
+                      (unless (or (macrop car) (functionp car))
+                        (let ((load-path (cons (file-name-directory file) load-path)))
+                         (message "loaddefs-gen: loading file %s" file)
+                         (condition-case e (load file)
+                           (error
+                            (warn "loaddefs-gen: load error\n\t%s" e)))))
+                      (unless (macrop car)
+                        (warn "loaddefs-gen: macro undefined, skipping expansion\n\t%s"
+                              car)
+                        (setq expansion nil)))
+                    (setq autoload (or (loaddefs-generate--make-autoload
+                                        form load-name expansion)
+                                       form))
                     ;; We get back either an autoload form, or a tree
                     ;; structure of `(progn ...)' things, so unravel that.
                     (let ((forms (if (eq (car autoload) 'progn)

Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78995; Package emacs. (Sat, 12 Jul 2025 17:52:01 GMT) Full text and rfc822 format available.

Message #23 received at 78995 <at> debbugs.gnu.org (full text, mbox):

From: Stefan Monnier <monnier <at> iro.umontreal.ca>
To: "J.D. Smith" <jdtsmith <at> gmail.com>
Cc: 78995 <at> debbugs.gnu.org
Subject: Re: bug#78995: [PATCH] ;;;autoload-expand for special macros
Date: Sat, 12 Jul 2025 13:51:09 -0400
>> I've been wanting to add the feature you propose, but this "macro is not
>> defined" has gotten in the way until now.  I think we need to add
>> something like a file-local `autoload-requires-for-macros`.
> How about this solution?  If the car of the following form is not a
> macro (and not a function), attempt to load the file itself (temporarily
> expanding `load-path' to include the file's containing directory).  If
> that fails to define the macro, warn the user, and simply proceed
> without expansion.

I don't think it's good enough.  Many of the use-cases I've bumped into
use macros defined in another file (or even another package).

I think we should aim to provide a mechanism that lets us reduce the
size of the hardcoded list (ideally to nothing).


        Stefan





Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78995; Package emacs. (Sat, 12 Jul 2025 20:00:03 GMT) Full text and rfc822 format available.

Message #26 received at 78995 <at> debbugs.gnu.org (full text, mbox):

From: "J.D. Smith" <jdtsmith <at> gmail.com>
To: Stefan Monnier <monnier <at> iro.umontreal.ca>
Cc: 78995 <at> debbugs.gnu.org
Subject: Re: bug#78995: [PATCH] ;;;autoload-expand for special macros
Date: Sat, 12 Jul 2025 15:59:44 -0400
Stefan Monnier <monnier <at> iro.umontreal.ca> writes:

>>> I've been wanting to add the feature you propose, but this "macro is not
>>> defined" has gotten in the way until now.  I think we need to add
>>> something like a file-local `autoload-requires-for-macros`.
>> How about this solution?  If the car of the following form is not a
>> macro (and not a function), attempt to load the file itself (temporarily
>> expanding `load-path' to include the file's containing directory).  If
>> that fails to define the macro, warn the user, and simply proceed
>> without expansion.
>
> I don't think it's good enough.  Many of the use-cases I've bumped into
> use macros defined in another file (or even another package).

Doesn't a file usually need to require such files/packages in order to
make use of their macros?  Or is the concern that those other
files/packages would not be in the current directory or on the
load-path?  I think package-install installs all requirements first, so
that shouldn't happen for it.

Or perhaps the issue arises in cases like multi-file packages where
`declare-function' is used because you know the load order.  I.e. if:

1. A.el always requires B.el and is its entry point,
2. B.el uses a macro from A.el with an ;;;###autoload-expand, and
3. B.el does _not_ require A.el, only (possibly) mentioning it via
   `declare-function`.

Then loading B.el is, as you say, not good enough.  This is tricky to
work around.

> I think we should aim to provide a mechanism that lets us reduce the
> size of the hardcoded list (ideally to nothing).

There are actually _multiple_ hard-coded lists in
`loaddefs-generate--make-autoload':

1. Macros to expand (by name) and recurse on the expansion.
2. "Function-like operators", which get an `(autoload ...)' form
  created for them.
3. Macros which are known to produce interactive function definitions
   (to set the INTERACTIVE arg for the generated autoload).

What about just mentioning in the docs that using ;;;###autoload-expand
successfully requires that the macro to be expanded is defined upon
loading the containing file?  There is a prominent warning if loading
the file fails to define the macro, so developers should be aware (or
made aware by their users).  They can always, e.g., factor out their
macro to a common file they can require.  The "fallback" is equivalent
to the current behavior: copy the full form into the autoload file.

Otherwise, if a documentation solution is not good enough, we could
create an additional file-local variable that could be consulted if the
user of ;;;###autoload-expand needs to give it some help, e.g.:

- `autoload-macro-expansion-files': a file-local list of additional
  file(s) to load prior to macro expansion, if any macros in calls
  directly preceded by ;;;###autoload-expand are undefined.  A symbol
  `file' in this list indicates the current file.  Defaults to `(file)'.




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78995; Package emacs. (Sat, 12 Jul 2025 22:45:02 GMT) Full text and rfc822 format available.

Message #29 received at 78995 <at> debbugs.gnu.org (full text, mbox):

From: Stefan Monnier <monnier <at> iro.umontreal.ca>
To: "J.D. Smith" <jdtsmith <at> gmail.com>
Cc: 78995 <at> debbugs.gnu.org
Subject: Re: bug#78995: [PATCH] ;;;autoload-expand for special macros
Date: Sat, 12 Jul 2025 18:43:56 -0400
>> I don't think it's good enough.  Many of the use-cases I've bumped into
>> use macros defined in another file (or even another package).
> Doesn't a file usually need to require such files/packages in order to
> make use of their macros?

Duh!  You're right.

> Or perhaps the issue arises in cases like multi-file packages where
> `declare-function' is used because you know the load order.  I.e. if:

No, no, these are "evil" and they get what they deserve.

>> I think we should aim to provide a mechanism that lets us reduce the
>> size of the hardcoded list (ideally to nothing).
>
> There are actually _multiple_ hard-coded lists in
> `loaddefs-generate--make-autoload':
>
> 1. Macros to expand (by name) and recurse on the expansion.
> 2. "Function-like operators", which get an `(autoload ...)' form
>   created for them.
> 3. Macros which are known to produce interactive function definitions
>    (to set the INTERACTIVE arg for the generated autoload).

The only list that I've found a need to extend is the (1) above, so
I wouldn't worry too much about the other two.

[ Declaring specific macros as "to be expanded for autoload" (as opposed
  to marking specific autoloaded macro calls), would still be overall
  better, since it would solve the question of "what about macros that
  expand to something that also needs expanding".  ]


        Stefan





Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78995; Package emacs. (Sun, 13 Jul 2025 02:26:01 GMT) Full text and rfc822 format available.

Message #32 received at 78995 <at> debbugs.gnu.org (full text, mbox):

From: "J.D. Smith" <jdtsmith <at> gmail.com>
To: Stefan Monnier <monnier <at> iro.umontreal.ca>
Cc: 78995 <at> debbugs.gnu.org
Subject: Re: bug#78995: [PATCH] ;;;autoload-expand for special macros
Date: Sat, 12 Jul 2025 22:25:05 -0400
Stefan Monnier <monnier <at> iro.umontreal.ca> writes:

> The only list that I've found a need to extend is the (1) above, so
> I wouldn't worry too much about the other two.
>
> [ Declaring specific macros as "to be expanded for autoload" (as opposed
>   to marking specific autoloaded macro calls), would still be overall
>   better, since it would solve the question of "what about macros that
>   expand to something that also needs expanding".  ]

That's a good point.  It would relieve us of the binary choice of
"expand just this form" vs. "expand any and all macros this form expands
to", which isn't ideal.  But I wonder what the best approach is?  A
file-local variable, which extends the (1) list only for that file?

We _could_ do both: an ;;;###autoload-expand magic comment for "expand
this one", and a optional file-local variable, something like
`autoload-extra-expand-macros', naming additional macros to expand at
any depth[1] (if needed).  We could even allow elements of the list to
look like (MACRO . FILE) for an additional FILE to define MACRO load
(for the evil people), defaulting to `(file)' (meaning: this file).

That's some duplication of purpose, and you don't technically need the
magic form, but formatting file-local variables is a pain if you don't
need them.

[1] Would we possibly have to guard against recursive macro definitions?
    An advantage of "just this next form" expansion is you don't have to
    worry about that.




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78995; Package emacs. (Sun, 13 Jul 2025 02:49:01 GMT) Full text and rfc822 format available.

Message #35 received at 78995 <at> debbugs.gnu.org (full text, mbox):

From: Stefan Monnier <monnier <at> iro.umontreal.ca>
To: "J.D. Smith" <jdtsmith <at> gmail.com>
Cc: 78995 <at> debbugs.gnu.org
Subject: Re: bug#78995: [PATCH] ;;;autoload-expand for special macros
Date: Sat, 12 Jul 2025 22:47:44 -0400
>> The only list that I've found a need to extend is the (1) above, so
>> I wouldn't worry too much about the other two.
>>
>> [ Declaring specific macros as "to be expanded for autoload" (as opposed
>>   to marking specific autoloaded macro calls), would still be overall
>>   better, since it would solve the question of "what about macros that
>>   expand to something that also needs expanding".  ]
>
> That's a good point.  It would relieve us of the binary choice of
> "expand just this form" vs. "expand any and all macros this form expands
> to", which isn't ideal.  But I wonder what the best approach is?

FWIW, I've come to the opinion that what you propose and what I want
match different use-cases.  The one I care about is when a package
provides a (typically autoloaded) macro like `define-minor-mode`, for
use by other packages.  But what you propose matches the use-case where
a package defines its own macro for it own internal use, usually with
no intention to autoload it.

> A file-local variable, which extends the (1) list only for that file?

I'm thinking we should replace the hardcoded list with a symbol
property.  When defining macros like `define-minor-mode` we'd set this
`autoload-macroexpand` property to a non-nil value, and `autoload.el`
would simply check the property instead of looking inside the hardcoded
list with `memq`.

This would work only for predefined or autoloaded macros (where the
`autoload-macroexpand` setting would be also pre-defined/loaded), so
it wouldn't work conveniently for a locally-defined and locally-used
macro, since you'd then need to somehow set the property and define or
autoload the macro before `autoload.el` gets to the macro calls.

So I think your approach might be a good solution for the case of local
macros.  I don't know how often we need such a thing, tho.  I can't
remember bumping into it, but it might be because I'd intuitively avoid
it, knowing we don't have support for it.

I assume there's a concrete use-case which motivated your patch.
Do you mind sharing it?


        Stefan





Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78995; Package emacs. (Sun, 13 Jul 2025 13:48:02 GMT) Full text and rfc822 format available.

Message #38 received at 78995 <at> debbugs.gnu.org (full text, mbox):

From: "J.D. Smith" <jdtsmith <at> gmail.com>
To: Stefan Monnier <monnier <at> iro.umontreal.ca>
Cc: 78995 <at> debbugs.gnu.org
Subject: Re: bug#78995: [PATCH] ;;;autoload-expand for special macros
Date: Sun, 13 Jul 2025 09:47:48 -0400
Stefan Monnier <monnier <at> iro.umontreal.ca> writes:


>> A file-local variable, which extends the (1) list only for that file?
>
> I'm thinking we should replace the hardcoded list with a symbol
> property.  When defining macros like `define-minor-mode` we'd set this
> `autoload-macroexpand` property to a non-nil value, and `autoload.el`
> would simply check the property instead of looking inside the hardcoded
> list with `memq`.

Oh, this is much better!  It relieves the _user_ of the macro the burden
of remembering to "auto-load it correctly."  For macros which are
defined in every session, you're done.  No special autoload-expand magic
comment needed. It also makes it possible to entirely eliminate
hard-coded list #1.  You'd just need to insert, e.g.:

  (put 'defun 'autoload-macroexpand t)

where the special macros are _defined_.  This would be a a bit more
self-documenting too.

We'd leave the "function-like operator" hard-coded list, but it could
probably be trimmed down with the new `autoload-macroexpand' feature.
For example, `transient-define-prefix' boils down to a defalias, which
is already supported.

> This would work only for predefined or autoloaded macros (where the
> `autoload-macroexpand` setting would be also pre-defined/loaded), so
> it wouldn't work conveniently for a locally-defined and locally-used
> macro, since you'd then need to somehow set the property and define or
> autoload the macro before `autoload.el` gets to the macro calls.

We could be aggressive about it.  If the car of some form encountered
during file scanning (including expansion) is a macro, we check its
`autoload-macroexpand' property and act accordingly.  But if it not
already a known special-form, function, or macro, we load the file to
see if that defines it.  If it _remains_ undefined, we just include the
whole form in the autoload file, just as we do now (generating a
warning).  But if loading the file _did_ define it as a macro, we check
its `autoload-macroexpand' property, and proceed as before.

I was curious how many existing ;;;###autoloads this would affect, since
I almost always see it used with `defun' or `define-minor-mode'.  I
looked through the entire emacs-30 lisp codebase[1] and could only find
`define-erc-module' as the car of a top-level autoload form which wasn't
already a known function, macro, or special form.  I repeated this
exercise among my 171 installed packages, and found only:

  Unknown autoload car: cape-char--define
  Unknown autoload car: define-erc-module

Importantly, in all of these cases, they are actually using adorned
magic comments, like:

  ;;;###autoload (autoload 'cape-tex "cape-char" nil t)
  (cape-char--define tex "TeX" ?\\ ?^ ?_)

so not relevant to our proposal (except that they could be improved by
it.)

> I assume there's a concrete use-case which motivated your patch.
> Do you mind sharing it?

I have a large package in development which has a flexible extension
system.  I'd like to enable "3rd-party" extensions with a convenience
`define-extension' macro.  In addition to defining a minor mode, this
macro will generate various `(put some-extension-mode ...)' statements,
which themselves need to be auto-loaded, as they are used to determine
when to load the extension (including, possibly, at package load time).

[1] Here's the distribution of pure ;;;###autoload forms in the emacs-30
    codebase:

     defun: 3226
     defcustom: 181
     define-minor-mode: 173
     define-derived-mode: 157
     defmacro: 130
     defalias: 101
     put: 88
     defvar: 74
     define-obsolete-function-alias: 27
     defvar-local: 20
     define-overloadable-function: 19
     cl-defgeneric: 19
     defconst: 15
     define-globalized-minor-mode: 15
     progn: 12
     defclass: 8
     add-to-list: 8
     cl-defun: 8
     defsubst: 7
     cl-defmacro: 5
     define-mail-user-agent: 4
     or: 3
     pcase-defmacro: 3
     define-global-minor-mode: 2
     make-variable-buffer-local: 2
     eval-after-load: 2
     dolist: 2
     define-key: 2
     unless: 1
     autoload: 1
     def-edebug-elem-spec: 1
     defvar-keymap: 1
     define-inline: 1
     when: 1
     define-compilation-mode: 1
     define-skeleton: 1
     let: 1
     fset: 1
     setq: 1

   Created with:

   rg -IA 1 -t elisp '^;;;###autoload *$' | perl -ne '$AL{$1}++ if /^\(([^ ]+) /; END { foreach $k (reverse sort { $AL{$a} <=> $AL{$b} } keys %AL) {print "$k: $AL{$k}\n"}}' 




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78995; Package emacs. (Sun, 13 Jul 2025 15:20:01 GMT) Full text and rfc822 format available.

Message #41 received at 78995 <at> debbugs.gnu.org (full text, mbox):

From: Stefan Monnier <monnier <at> iro.umontreal.ca>
To: "J.D. Smith" <jdtsmith <at> gmail.com>
Cc: 78995 <at> debbugs.gnu.org
Subject: Re: bug#78995: [PATCH] ;;;autoload-expand for special macros
Date: Sun, 13 Jul 2025 11:19:08 -0400
>>> A file-local variable, which extends the (1) list only for that file?
>> I'm thinking we should replace the hardcoded list with a symbol
>> property.  When defining macros like `define-minor-mode` we'd set this
>> `autoload-macroexpand` property to a non-nil value, and `autoload.el`
>> would simply check the property instead of looking inside the hardcoded
>> list with `memq`.
>
> Oh, this is much better!  It relieves the _user_ of the macro the burden
> of remembering to "auto-load it correctly."  For macros which are
> defined in every session, you're done.  No special autoload-expand magic
> comment needed. It also makes it possible to entirely eliminate
> hard-coded list #1.  You'd just need to insert, e.g.:
>
>   (put 'defun 'autoload-macroexpand t)
>
> where the special macros are _defined_.  This would be a a bit more
> self-documenting too.

Yes, tho we'd probably define a `declare` thingy so you wouldn't write
the `put` but you'd write

    (defmacro define-minor-mode ...
      (declare (...
                (autoload macroexpand)
                ...))
      ...)

> We'd leave the "function-like operator" hard-coded list, but it could
> probably be trimmed down with the new `autoload-macroexpand' feature.
> For example, `transient-define-prefix' boils down to a defalias, which
> is already supported.

Ah, yes, I had not noticed that `transient-define-prefix` had been added
there, and now that I see it, it does make it seem like my impression
that it was unimportant may have been wrong.
Usually macroexpanding those things is enough (the macro can be defined
appropriately).  We could still refine the above with something like:

    (defmacro transient-define-prefix ...
      (declare (...
                (autoload function)
                ...))
      ...)

tho this probably needs more thought/design because we need more info
(where's the name of the defined thing, whether it's a macro or
a function, what's the list of arguments, ...).

>> This would work only for predefined or autoloaded macros (where the
>> `autoload-macroexpand` setting would be also pre-defined/loaded), so
>> it wouldn't work conveniently for a locally-defined and locally-used
>> macro, since you'd then need to somehow set the property and define or
>> autoload the macro before `autoload.el` gets to the macro calls.
>
> We could be aggressive about it.  If the car of some form encountered
> during file scanning (including expansion) is a macro, we check its
> `autoload-macroexpand' property and act accordingly.  But if it not
> already a known special-form, function, or macro, we load the file to
> see if that defines it.

Oh, yeah, neat.

> Importantly, in all of these cases, they are actually using adorned
> magic comments, like:
>
>   ;;;###autoload (autoload 'cape-tex "cape-char" nil t)
>   (cape-char--define tex "TeX" ?\\ ?^ ?_)
>
> so not relevant to our proposal (except that they could be improved by
> it.)

Yes, these are the ones that "document" a need for the new feature.


        Stefan


diff --git a/lisp/emacs-lisp/byte-run.el b/lisp/emacs-lisp/byte-run.el
index 6412c8cde22..654b67ada1b 100644
--- a/lisp/emacs-lisp/byte-run.el
+++ b/lisp/emacs-lisp/byte-run.el
@@ -286,6 +286,11 @@
 	    (list 'put (list 'quote name)
 		  ''edebug-form-spec (list 'quote spec)))))
 
+(defalias 'byte-run--set-autoload-macro
+  #'(lambda (name _args spec)
+     (list 'put (list 'quote name)
+	   ''autoload-macro (list 'quote spec))))
+
 (defalias 'byte-run--set-no-font-lock-keyword
   #'(lambda (name _args val)
       (list 'function-put (list 'quote name)
@@ -365,8 +370,10 @@ macro-declarations-alist
   (cons
    (list 'debug #'byte-run--set-debug)
    (cons
-    (list 'no-font-lock-keyword #'byte-run--set-no-font-lock-keyword)
-    defun-declarations-alist))
+    (list 'autoload-macro #'byte-run--set-autoload-macro)
+    (cons
+     (list 'no-font-lock-keyword #'byte-run--set-no-font-lock-keyword)
+     defun-declarations-alist)))
   "List associating properties of macros to their macro expansion.
 Each element of the list takes the form (PROP FUN) where FUN is a function.
 For each (PROP . VALUES) in a macro's declaration, the FUN corresponding
diff --git a/lisp/emacs-lisp/loaddefs-gen.el b/lisp/emacs-lisp/loaddefs-gen.el
index 8a131bf885f..b8dfe095589 100644
--- a/lisp/emacs-lisp/loaddefs-gen.el
+++ b/lisp/emacs-lisp/loaddefs-gen.el
@@ -198,19 +198,20 @@
           (when exps (cons 'progn exps)))))
 
      ;; For complex cases, try again on the macro-expansion.
-     ((and (memq car '( define-globalized-minor-mode defun defmacro
+     ((and (or (eq 'expand (get car 'autoload-macro))
+               (memq car '( define-globalized-minor-mode defun defmacro
                         define-minor-mode define-inline
                         cl-defun cl-defmacro cl-defgeneric
                         cl-defstruct pcase-defmacro iter-defun cl-iter-defun
                         ;; Obsolete; keep until the alias is removed.
                         easy-mmode-define-global-mode
                         easy-mmode-define-minor-mode
-                        define-global-minor-mode))
+                            define-global-minor-mode)))
            (macrop car)
 	   (setq expand (let ((load-true-file-name file)
                               (load-file-name file))
                           (macroexpand form)))
-	   (memq (car expand) '(progn prog1 defalias)))
+	   (not (eq car (car expand))))
       ;; Recurse on the expansion.
       (loaddefs-generate--make-autoload expand file 'expansion))
 





Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78995; Package emacs. (Sun, 13 Jul 2025 19:02:02 GMT) Full text and rfc822 format available.

Message #44 received at 78995 <at> debbugs.gnu.org (full text, mbox):

From: "J.D. Smith" <jdtsmith <at> gmail.com>
To: Stefan Monnier <monnier <at> iro.umontreal.ca>
Cc: 78995 <at> debbugs.gnu.org
Subject: Re: bug#78995: [PATCH] ;;;autoload-expand for special macros
Date: Sun, 13 Jul 2025 15:01:07 -0400
Stefan Monnier <monnier <at> iro.umontreal.ca> writes:

>> You'd just need to insert, e.g.:
>>
>>   (put 'defun 'autoload-macroexpand t)
>>
>> where the special macros are _defined_.  This would be a a bit more
>> self-documenting too.
>
> Yes, tho we'd probably define a `declare` thingy so you wouldn't write
> the `put` but you'd write
>
>     (defmacro define-minor-mode ...
>       (declare (...
>                 (autoload macroexpand)

Wow, this is even nicer!  Never knew those `delare's were so simple. 

>> We'd leave the "function-like operator" hard-coded list, but it could
>> probably be trimmed down with the new `autoload-macroexpand' feature.
>> For example, `transient-define-prefix' boils down to a defalias, which
>> is already supported.
>
> Ah, yes, I had not noticed that `transient-define-prefix` had been added
> there, and now that I see it, it does make it seem like my impression
> that it was unimportant may have been wrong.
> Usually macroexpanding those things is enough (the macro can be defined
> appropriately).  We could still refine the above with something like:
>
>     (defmacro transient-define-prefix ...
>       (declare (...
>                 (autoload function)

I mean `defalias' is supported because `defun' expands to it.  Isn't
that enough?  I guess some macros are complex enough you want to take
the quick short cut and turn them right into an `(autoload ...)'
statement, without having to design them carefully?

> tho this probably needs more thought/design because we need more info
> (where's the name of the defined thing, whether it's a macro or
> a function, what's the list of arguments, ...).

The code in `--make-autoload' seems to think it knows how to handle all
those "function-like operators".  But list 1 and list 2 seem to be
disjoint.  E.g. `transient-define-prefix' is on list 2, but _not_ on
list 1.  So it would like to be treated as a function operator, but not
expanded.

Actually I'm confused about that logic.  Take `define-minor-mode'.  It's
on list 1 (expand the macro) and list 2 (treat it as a function
operator).  I don't see how it could ever get list 2 treatment, since it
always would have been expanded first by the list 1 logic above.  There
are many macros in the 1 & 2 category:

   ;; Expand but don't treat as a special function (1, not 2):
   (defun defmacro define-inline
     cl-defgeneric
     cl-defstruct
     pcase-defmacro
     iter-defun
     cl-iter-defun)
   ;; Only treat as a special function op (2, not 1):
   (define-skeleton
     define-derived-mode
     define-compilation-mode
     define-generic-mode
     defun*
     defmacro*
     define-overloadable-function
     transient-define-prefix
     transient-define-suffix
     transient-define-infix
     transient-define-argument)
   ;; Expand _and_ treat as a special function op (1 & 2):
   (define-skeleton
     define-derived-mode
     define-compilation-mode
     define-generic-mode
     easy-mmode-define-global-mode
     define-global-minor-mode
     define-globalized-minor-mode
     easy-mmode-define-minor-mode
     define-minor-mode cl-defun
     defun*
     cl-defmacro
     defmacro*
     define-overloadable-function
     transient-define-prefix
     transient-define-suffix
     transient-define-infix
     transient-define-argument
     defun defmacro define-inline
     cl-defgeneric
     cl-defstruct
     pcase-defmacro
     iter-defun
     cl-iter-defun)

What am I missing?




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78995; Package emacs. (Sun, 13 Jul 2025 22:50:02 GMT) Full text and rfc822 format available.

Message #47 received at 78995 <at> debbugs.gnu.org (full text, mbox):

From: Stefan Monnier <monnier <at> iro.umontreal.ca>
To: "J.D. Smith" <jdtsmith <at> gmail.com>
Cc: 78995 <at> debbugs.gnu.org
Subject: Re: bug#78995: [PATCH] ;;;autoload-expand for special macros
Date: Sun, 13 Jul 2025 18:49:30 -0400
>>     (defmacro define-minor-mode ...
>>       (declare (...
>>                 (autoload macroexpand)
>
> Wow, this is even nicer!  Never knew those `delare's were so simple. 

🙂

[ Of course, third-party code would have to use `put` in the short term
  for backward compatibility reasons.  🙁 ]

>>     (defmacro transient-define-prefix ...
>>       (declare (...
>>                 (autoload function)
>
> I mean `defalias' is supported because `defun' expands to it.  Isn't
> that enough?

Yes, I think we could mark `transient-define-prefix` as `expand`.
My understanding is that currently putting it in "list 1" wouldn't work
simply because it's not autoloaded.

> The code in `--make-autoload' seems to think it knows how to handle all
> those "function-like operators".  But list 1 and list 2 seem to be
> disjoint.  E.g. `transient-define-prefix' is on list 2, but _not_ on
> list 1.  So it would like to be treated as a function operator, but not
> expanded.

As mentioned above, I think it's just because of a lack of autoloading.

>    ;; Expand _and_ treat as a special function op (1 & 2):
>    (define-skeleton
>      define-derived-mode
>      define-compilation-mode
>      define-generic-mode
>      easy-mmode-define-global-mode
>      define-global-minor-mode
>      define-globalized-minor-mode
>      easy-mmode-define-minor-mode
>      define-minor-mode cl-defun
>      defun*
>      cl-defmacro
>      defmacro*
>      define-overloadable-function
>      transient-define-prefix
>      transient-define-suffix
>      transient-define-infix
>      transient-define-argument
>      defun defmacro define-inline
>      cl-defgeneric
>      cl-defstruct
>      pcase-defmacro
>      iter-defun
>      cl-iter-defun)

I don't see `cl-defstruct` in list 2 (same for several others), so
I think the above list isn't right.
But yes, some are in both lists and it's mostly "historical accidents".
IIRC `easy-mmode-define-minor-mode` started in list 2 and was later
added to list 1 so as to get a better result (e.g. more complete
docstring) in those cases where the macro happens to be defined.

But I think your trick of evaluating the file (to cause the macros
to be defined) should allow us to focus on list 1 and leave only the
strict minimum in list 2.


        Stefan





Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78995; Package emacs. (Mon, 14 Jul 2025 00:06:02 GMT) Full text and rfc822 format available.

Message #50 received at 78995 <at> debbugs.gnu.org (full text, mbox):

From: "J.D. Smith" <jdtsmith <at> gmail.com>
To: Stefan Monnier <monnier <at> iro.umontreal.ca>
Cc: 78995 <at> debbugs.gnu.org
Subject: Re: bug#78995: [PATCH] ;;;autoload-expand for special macros
Date: Sun, 13 Jul 2025 20:05:07 -0400
Stefan Monnier <monnier <at> iro.umontreal.ca> writes:

> I don't see `cl-defstruct` in list 2 (same for several others), so
> I think the above list isn't right.

Oops, wrong set function.  It's:

   ;; Expand and treat as function op:
   (easy-mmode-define-global-mode
     define-global-minor-mode
     define-globalized-minor-mode
     easy-mmode-define-minor-mode
     define-minor-mode cl-defun
     cl-defmacro)

> some are in both lists and it's mostly "historical accidents".

Makes sense.

> But I think your trick of evaluating the file (to cause the macros
> to be defined) should allow us to focus on list 1 and leave only the
> strict minimum in list 2.

I will work up a patch using this approach unless you'd like to (will be
a few days min).  I think we are in agreement that a simple (autoload
macroexpand) will suffice.  We could leave list 2 as-is for now, with a
note that it can be trimmed once `declare' for list 1 is fully
operational.

Probably would also need to loop in package authors, e.g. for transient,
to ensure they are aware of the change.




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78995; Package emacs. (Mon, 14 Jul 2025 02:33:02 GMT) Full text and rfc822 format available.

Message #53 received at 78995 <at> debbugs.gnu.org (full text, mbox):

From: Stefan Monnier <monnier <at> iro.umontreal.ca>
To: "J.D. Smith" <jdtsmith <at> gmail.com>
Cc: 78995 <at> debbugs.gnu.org
Subject: Re: bug#78995: [PATCH] ;;;autoload-expand for special macros
Date: Sun, 13 Jul 2025 22:31:58 -0400
> I will work up a patch using this approach

Sounds good.  🙂

> I think we are in agreement that a simple (autoload macroexpand) will
> suffice.  We could leave list 2 as-is for now, with a note that it can
> be trimmed once `declare' for list 1 is fully operational.
>
> Probably would also need to loop in package authors, e.g. for transient,
> to ensure they are aware of the change.

I think we can start by removing those entries that we can turn into
`declare` directly in Emacs (e.g. not those for Transient).
And then wait for the relevant package authors to start using the new
functionality before we remove the rest, bit by bit.


        Stefan





Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78995; Package emacs. (Wed, 16 Jul 2025 03:37:01 GMT) Full text and rfc822 format available.

Message #56 received at 78995 <at> debbugs.gnu.org (full text, mbox):

From: "J.D. Smith" <jdtsmith <at> gmail.com>
To: 78995 <at> debbugs.gnu.org, Stefan Monnier <monnier <at> iro.umontreal.ca>
Subject: Re: bug#78995: [PATCH] ;;;autoload-expand for special macros
Date: Tue, 15 Jul 2025 23:35:54 -0400
[Message part 1 (text/plain, inline)]
Here is an update on progress.  The attached is working reasonably well,
reproducing lisp/loaddefs.el with a few changes (see attached).  I went
with (declare ((autoload . macro-expand))) on the notion that there
might be other autoload-related declarations in the future, but open to
suggestion.

I've now fully eliminated list 1 in favor of declare statements, but
also had to handle the case of _aliased_ macros, e.g. all the
[easy-mmode]-define-global[ized]-minor-mode yada yada.

There are a couple things I need to check on.

1. Non-repeatable loaddefs:

When you re-run make and it needs to regenerate lisp/loaddefs.el, it
appears easy-mmode is _not_ loaded by whatever emacs process conducts
that subsequent autoload-generation round.  Consequently,
`define-minor-mode' isn't loaded, so calls to it produce only partial
autoload entries (via, I believe, list 2).  Maybe that's why list 2
duplicates entries from list 1, as a backup against this non-repeatable
build.  But it seems strange to have different packages loaded on
different passes of the same Makefile target.  You can confirm this by:

% mv lisp/loaddefs.el lisp/loaddefs_orig.el
% make
% diff -u lisp/loaddefs_orig.el lisp/loaddefs.el

I'm not clear if this has anything to do with this patch, or could even
be a pre-existing build bug.  Once you are in this situation, you
basically have to `make bootstrap' to get the full and complete autoload
statements to appear again in loaddefs.

2. Some files are now being loaded during autoloads generation:

I noticed a few files among bundled lisp packages that now get loaded,
because they autoload undefined macros:

   loaddefs-gen: loading file frameset (cl-defun)
   Loading frameset...
     INFO     Scraping 1565 files for loaddefs...15% 
   loaddefs-gen: loading file ede/cpp-root (defclass)
   Loading ede/cpp-root...
     INFO     Scraping 1565 files for loaddefs...25% 
     INFO     Scraping 1565 files for loaddefs...47% 
     INFO     Scraping 1565 files for loaddefs...64% 
   loaddefs-gen: loading file tramp-adb (tramp--with-startup)
   Loading tramp-adb...
     INFO     Scraping 1565 files for loaddefs...80% 
   loaddefs-gen: loading file grep (define-compilation-mode)
   Loading grep...

These mostly seem to be innocuous in that after loading them, it becomes
clear that these particular autoloaded macros don't request
macro-expansion, so nothing different happens.  But it does represent a
few new "internal" load calls during autoload generation.  I think list
1 is now "doing more work" because of this pre-load mechanism.

Thoughts and suggestions very welcome.

[autoload-expand_2.patch (text/x-patch, attachment)]
[loaddefs.diff (text/x-patch, attachment)]

Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78995; Package emacs. (Wed, 23 Jul 2025 21:21:02 GMT) Full text and rfc822 format available.

Message #59 received at 78995 <at> debbugs.gnu.org (full text, mbox):

From: "J.D. Smith" <jdtsmith <at> gmail.com>
To: 78995 <at> debbugs.gnu.org
Cc: Stefan Monnier <monnier <at> iro.umontreal.ca>
Subject: Re: bug#78995: [PATCH] ;;;autoload-expand for special macros
Date: Wed, 23 Jul 2025 17:20:13 -0400
[Message part 1 (text/plain, inline)]
Stefan, can you take a look at this?

I think I now understand why there are slight differences in the
loaddefs.el file generated by my declare-based, eager-loading patch.
There is a /bug/ in the fallback "list 3" generation of autoloads,
leading to incorrect autoload statements being written out.

The `INTERACTIVE' arg to `autoload' is supposed to be formed as follows:

  If INTERACTIVE is a list, it is interpreted as a list of modes the
  function is applicable for.

The current code mistakenly injects the actual ARG-DESCRIPTOR list into
the autoload file, for those (few) macros which are not expanded but
fall through to list 2, possibly just `cl-defun's.  You might see for
example the full `(let...` descriptors for `erc` in your loaddefs.el
file.

That's a bug I believe, and will presumably mess with the mode-specific
M-S-x type functionality. So by expanding more eagerly with `(declare
(autoload macro-expand))', this bug was "eliminated".  The attached
fixes it for any cases which still use fall-through to list 2.

Thoughts?


[autoload-bug.patch (text/x-patch, attachment)]

Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78995; Package emacs. (Thu, 24 Jul 2025 14:10:02 GMT) Full text and rfc822 format available.

Message #62 received at 78995 <at> debbugs.gnu.org (full text, mbox):

From: "J.D. Smith" <jdtsmith <at> gmail.com>
To: 78995 <at> debbugs.gnu.org
Cc: Stefan Monnier <monnier <at> iro.umontreal.ca>
Subject: Re: bug#78995: [PATCH] ;;;autoload-expand for special macros
Date: Thu, 24 Jul 2025 10:09:07 -0400
[Message part 1 (text/plain, inline)]
"J.D. Smith" <jdtsmith <at> gmail.com> writes:

> Here is an update on progress.  The attached is working reasonably well,
> reproducing lisp/loaddefs.el with a few changes (see attached).  I went
> with (declare ((autoload . macro-expand))) on the notion that there
> might be other autoload-related declarations in the future, but open to
> suggestion.

Please have a look at this latest patch, which I believe solves the
mentioned problems.

Changes:

1. I implemented the list 2 bug fix for autoload's INTERACTIVE argument
   described above, correctly keeping interactive arg specs out of the
   loaddefs files.

2. I moved the autoload macro-expand declare up front everywhere it's
   used[1], to ensure the macro-expand request will be included in
   *-loaddefs.el files.  This is important for packages which manage
   their own *-loaddefs.el files (e.g. `cl-macs').
   
3. I have kept list 2 around[2], and count presence on this list, or the
   list of 4 specially-handled macros (defgroup, defcustom, deftheme,
   defclass) as "we know about this car".  No file load will be
   attempted for such special macros, so only proper "user-defined
   UNKNOWN macros" will result in a load attempt.

With these, the loaddefs.el file changes only modestly (see attached),
and (almost) no files have load attempted.

About that almost.  There is one small order-of-operation issue yet to
be solved, for packages which do clever things.  Take any of the
`net/tramp-*.el` files.  They all require `tramp-compat`, which requires
`tramp-loaddefs', which is itself an autoload file the build process is
generating.  For example, tramp's autoload file eventually includes the
macro `tramp--with-startup'.  When one of tramp's autoloads use an
unknown macro like this, there will be an attempt to load the file,
implicitly requiring that yet-to-exist `tramp-loaddefs.el' file,
resulting in a (handled) error.  Classic chicken and egg.

    INFO     Scraping 1543 files for loaddefs...70% 
  loaddefs-gen: loading file tramp-adb (for tramp--with-startup)
  Loading /Users/jdsmith/code/emacs/emacs-mac/lisp/net/tramp-adb.el (source)...
  Warning (emacs): loaddefs-gen: load error
  	(file-missing Cannot open load file No such file or directory tramp-loaddefs)
  loaddefs-gen: loading file tramp-androidsu (for tramp--with-startup)
  Loading /Users/jdsmith/code/emacs/emacs-mac/lisp/net/tramp-androidsu.el (source)...
  Warning (emacs): loaddefs-gen: load error
  	(file-missing Cannot open load file No such file or directory tramp-loaddefs)
  ...

In this case these are harmless warnings, since in fact
`tramp--with-startup' is /not/ requesting macro-expand, so failing to
define it doesn't matter.  Subsequent builds do not show this error.
But this could be alarming to people, so we probably need a solution.

[1] Note that the order of declare entries already matters, because some
    of them generate forms which include `:autoload-end', and this
    token, once encountered _anywhere_, puts an absolute stop to
    emitting additional declare-generated forms into loaddefs.
    E.g. `(declare (debug ...))' does this.  This, by the way, is why
    /some/ macros have their (e.g.) `indent' declares passed through to
    the loaddefs files, and others do not.

[2] Some of these macros aren't yet suited for full expansion anyway.
    For example `define-derived-mode' includes a bunch of unwanted forms
    if it gets the expansion treatment.  So for now, leaving the
    shortcut list 2 intact seems to be the lesser evil.

[autoload-expand_3.patch (text/x-patch, attachment)]
[loaddefs_2.diff (text/x-patch, attachment)]

Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78995; Package emacs. (Sat, 26 Jul 2025 17:14:02 GMT) Full text and rfc822 format available.

Message #65 received at 78995 <at> debbugs.gnu.org (full text, mbox):

From: Stefan Monnier <monnier <at> iro.umontreal.ca>
To: "J.D. Smith" <jdtsmith <at> gmail.com>
Cc: 78995 <at> debbugs.gnu.org
Subject: Re: bug#78995: [PATCH] ;;;autoload-expand for special macros
Date: Sat, 26 Jul 2025 13:13:40 -0400
[ Sorry for the long delay.  ]

>> Here is an update on progress.  The attached is working reasonably well,
>> reproducing lisp/loaddefs.el with a few changes (see attached).  I went
>> with (declare ((autoload . macro-expand))) on the notion that there
>> might be other autoload-related declarations in the future, but open to
>> suggestion.

[ I don't have an opinion on the naming here but I don't understand your
  argument: wouldn't a declaration name of `autoload` be *more* likely
  to conflict with another future autoload-related declaration?  ]

>   Warning (emacs): loaddefs-gen: load error
>   	(file-missing Cannot open load file No such file or directory tramp-loaddefs)
>   ...
>
> In this case these are harmless warnings, since in fact
> `tramp--with-startup' is /not/ requesting macro-expand, so failing to
> define it doesn't matter.  Subsequent builds do not show this error.
> But this could be alarming to people, so we probably need a solution.

Yeah, it's one of those nasty issues.  One way to look at it is that the
crux of the matter is that we use `;;;###autoload` for 2 different
purpose:

A. To copy the code into the loaddefs file.
B. To arrange for the file to be autoloaded when the corresponding thingy
   is used.

(B) is the one that deserves the name "autoload" while (A) might be
better named "preload".

Your `;;;###autoload-expand` was a fix for that core problem, in a sense.

The distinction between the two is not that clear when you consider that
a `;;;###autoload` cookie placed on a `defun` may arrange to autoload
that file when calling that function but it may *also* preload some
`put`s extracted from the `declare`.

Maybe a "general" solution would be to introduce a `;;;###preload`.
Not sure it's worth the trouble, tho.

Also, I'm not sure how "general" this would be, since the same problem
will tend to happen with any package which `;;;###autoload` a call to
a macro that's not predefined if that package uses its own
`FOO-loaddefs.el`, even if that macro is defined in some other library.

So, the general problem is: your patch will sometimes `eval-buffer` for
a buffer which doesn't expect to be evaluated before its package's
`FOO-loaddefs.el` has been created.   I suspect that in most cases this
can be fixed by replacing

    (require 'foo-loaddefs)
by
    (require 'foo-loaddefs nil t)

It's not ideal, but I think it's acceptable.  Maybe it won't always be
sufficient either.  E.g. in `cl-lib` we solved this problem (for
a different reason) with:

    (unless (load "cl-loaddefs" 'noerror 'quiet)
      ;; When bootstrapping, cl-loaddefs hasn't been built yet!
      (require 'cl-macs)
      (require 'cl-seq)
      ;; FIXME: Arguably we should also load `cl-extra', except that this
      ;; currently causes more bootstrap troubles, and `cl-extra' is
      ;; rarely used, so instead we explicitly (require 'cl-extra) at
      ;; those rare places where we do need it.
      )

BTW, in the specific case of Tramp, I see:

    (defmacro tramp--with-startup (&rest body)
      "Schedule BODY to be executed at the end of tramp.el."
      `(add-hook 'tramp--startup-hook (lambda nil ,@body)))

so I think `tramp--with-startup` *is* one of the macros that would
benefit from your new `(autoload macro-expand)` declaration.

> [1] Note that the order of declare entries already matters, because some
>     of them generate forms which include `:autoload-end', and this
>     token, once encountered _anywhere_, puts an absolute stop to
>     emitting additional declare-generated forms into loaddefs.
>     E.g. `(declare (debug ...))' does this.  This, by the way, is why
>     /some/ macros have their (e.g.) `indent' declares passed through to
>     the loaddefs files, and others do not.

Really?  Sounds like a bug.  Are you sure?

    (macroexpand '(defmacro my-foo () (declare (debug t) (indent 1)) (help)))

gives me:

    (prog1 (defalias 'my-foo (cons 'macro #'(lambda nil (help))))
     (progn :autoload-end (put 'my-foo 'edebug-form-spec 't))
     (function-put 'my-foo 'lisp-indent-function 1))

and AFAIK the `:autoload-end` truncation is done with

      (let ((end (memq :autoload-end form)))
	(when end             ;Cut-off anything after the :autoload-end marker.
          (setq form (copy-sequence form))
          (setcdr (memq :autoload-end form) nil))

so it should only truncate to:

    (prog1 (defalias 'my-foo (cons 'macro #'(lambda nil (help))))
     (progn :autoload-end)
     (function-put 'my-foo 'lisp-indent-function 1))

and thus keep the subsequent `indent` declaration intact.

> [2] Some of these macros aren't yet suited for full expansion anyway.
>     For example `define-derived-mode' includes a bunch of unwanted forms
>     if it gets the expansion treatment.  So for now, leaving the
>     shortcut list 2 intact seems to be the lesser evil.

Interesting.

> +(defalias 'byte-run--set-autoload
> +  #'(lambda (name _args spec)
> +      (list 'function-put (list 'quote name)
> +	    ''autoload (list 'quote spec))))

I think the choice of `autoload` as name of symbol property is too
generic and runs too high a risk of clashing with other uses.

> (defconst loaddefs--function-like-operators

"operators" doesn't sound quite right.
Maybe "loaddefs--defining-macros"?

>  If EXPANSION is non-nil, we're processing the macro expansion of an
> -expression, in which case we want to handle forms differently."
> +expression, in which case we want to handle forms differently.  Note
> +that macros can request expansion by including `(autoload macro-expand)'
> +among their `declare' forms."

Nitpick: I'd start "Note..." on its own line.  We're not trying to
justify-fill the text.  🙂

> @@ -196,30 +212,35 @@ loaddefs-generate--make-autoload
>                                        (cdr form)))))
>            (when exps (cons 'progn exps)))))
>  
> -     ;; For complex cases, try again on the macro-expansion.
> -     ((and (memq car '(easy-mmode-define-global-mode define-global-minor-mode
> -                       define-globalized-minor-mode defun defmacro
> -		       easy-mmode-define-minor-mode define-minor-mode
> -                       define-inline cl-defun cl-defmacro cl-defgeneric
> -                       cl-defstruct pcase-defmacro iter-defun cl-iter-defun))
> -           (macrop car)
> -	   (setq expand (let ((load-true-file-name file)
> -                              (load-file-name file))
> -                          (macroexpand form)))
> -	   (memq (car expand) '(progn prog1 defalias)))
> +     ;; For macros which request it, try again on their expansion.
> +     ((progn
> +        ;; If the car is entirely unknown, we load the file first to
> +        ;; give packages a chance to define their macros.
> +        (unless (or (null car) (macrop car) (functionp car) (special-form-p car)

I'd test (and (symbolp car) (not (fboundp car)))

> +                    (memq car '(defclass defcustom deftheme defgroup))

This deserves a comment in the code.

> +                    (alist-get file load-history)

`alist-get` defaults to testing with `eq` so it won't work well with
a string key.  🙁
I'd go with `assoc`.

> +        (and (macrop car)
> +	     (eq 'macro-expand ; a macro can declare (autoload macro-expand)
> +		 (or (get car 'autoload)
> +		     (get (car-safe (last (function-alias-p car))) 'autoload)))

I'd have expected `function-get` here.

> -     ;; For special function-like operators, use the `autoload' function.
> -     ((memq car '(define-skeleton define-derived-mode
> -                   define-compilation-mode define-generic-mode
> -		   easy-mmode-define-global-mode define-global-minor-mode
> -		   define-globalized-minor-mode
> -		   easy-mmode-define-minor-mode define-minor-mode
> -		   cl-defun defun* cl-defmacro defmacro*
> -                   define-overloadable-function
> -                   transient-define-prefix transient-define-suffix
> -                   transient-define-infix transient-define-argument))
> +     ;; For special function-like operators, use the `autoload'
> +     ;; function.
> +     ((memq car loaddefs--function-like-operators)
>        (let* ((macrop (memq car '(defmacro cl-defmacro defmacro*)))
>  	     (name (nth 1 form))
>  	     (args (pcase car

If we swap this case with the preceding one we can remove the

    (memq car loaddefs--function-like-operators)

from the `unless` of that case.
[ And it probably results in a diff that's harder to read, so thanks for
  not doing it this time.  🙂 ]

> @@ -257,8 +278,8 @@ loaddefs-generate--make-autoload
>                        t)
>                   (and (eq (car-safe (car body)) 'interactive)
>                        ;; List of modes or just t.
> -                      (or (if (nthcdr 1 (car body))
> -                              (list 'quote (nthcdr 1 (car body)))
> +                      (or (if (nthcdr 2 (car body))
> +                              (list 'quote (nthcdr 2 (car body)))
>                              t))))
>              ,(if macrop ''macro nil)))))

I think you can just push this to `master` as  separate patch, thank you.

> @@ -19835,7 +19836,7 @@
>  loaddefs.el output file, and the rest are the directories to
>  use.")
>   (load "theme-loaddefs.el" t)
> -(register-definition-prefixes "loaddefs-gen" '("autoload-" "generated-autoload-" "loaddefs-generate--" "no-update-autoloads"))
> +(register-definition-prefixes "loaddefs-gen" '("autoload-" "generated-autoload-" "loaddefs-" "my/tmp-lddg-list2" "no-update-autoloads"))

Maybe better use `autoload-` rather than `loaddefs-` as prefix for the
new definitions.
[ I don't see `my/tmp-lddg-list2` in the patch you sent, so I assume it
  was something temporary.  ]


        Stefan





Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78995; Package emacs. (Sun, 27 Jul 2025 01:47:02 GMT) Full text and rfc822 format available.

Message #68 received at 78995 <at> debbugs.gnu.org (full text, mbox):

From: "J.D. Smith" <jdtsmith <at> gmail.com>
To: Stefan Monnier <monnier <at> iro.umontreal.ca>
Cc: 78995 <at> debbugs.gnu.org
Subject: Re: bug#78995: [PATCH] ;;;autoload-expand for special macros
Date: Sat, 26 Jul 2025 21:46:46 -0400
[Message part 1 (text/plain, inline)]
Stefan Monnier <monnier <at> iro.umontreal.ca> writes:

Thanks for your feedback.

>>> I went with (declare ((autoload . macro-expand))) on the notion that
>>> there might be other autoload-related declarations in the future,
>>> but open to suggestion.
>
> [ I don't have an opinion on the naming here but I don't understand your
>   argument: wouldn't a declaration name of `autoload` be *more* likely
>   to conflict with another future autoload-related declaration?  ]

I suppose I had imagined multiple flags, à la:

  (autoload (macro-expand something-else))

but maybe that's frowned on.  In which case we should just go with
`(autoload-macro . expand)'.

> One way to look at it is that the crux of the matter is that we use
> `;;;###autoload` for 2 different purpose:
>
> A. To copy the code into the loaddefs file.
> B. To arrange for the file to be autoloaded when the corresponding thingy
>    is used.
>
> (B) is the one that deserves the name "autoload" while (A) might be
> better named "preload".

That's a sensible way of looking at it.

> The distinction between the two is not that clear when you consider that
> a `;;;###autoload` cookie placed on a `defun` may arrange to autoload
> that file when calling that function but it may *also* preload some
> `put`s extracted from the `declare`.
>
> Maybe a "general" solution would be to introduce a `;;;###preload`.
> Not sure it's worth the trouble, tho.

Could be considered radical.  I guess the contract would be that all
`;;;###preload's would happen before all `;;;autoload's?  I can imagine
people confusing these two (similar to use-package's :init vs. :config).

> Also, I'm not sure how "general" this would be, since the same problem
> will tend to happen with any package which `;;;###autoload` a call to
> a macro that's not predefined if that package uses its own
> `FOO-loaddefs.el`, even if that macro is defined in some other library.

It would be general if it were universally adopted, and autoload
scanning proceeded across all files, first generating "stub" loaddefs
for preloads, then, in a subsequent pass, doing the autoloads.

The main issue as I see it is we are now (for the first time) possibly
/loading/ files, vs. just scanning them passively.  I think the
situation where this distinction matters is quite rare.  Note that the
only file(s) where a load are attempted now are for TRAMP.

> So, the general problem is: your patch will sometimes `eval-buffer` for
> a buffer which doesn't expect to be evaluated before its package's
> `FOO-loaddefs.el` has been created.   I suspect that in most cases this
> can be fixed by replacing
>
>     (require 'foo-loaddefs)
> by
>     (require 'foo-loaddefs nil t)
>
> It's not ideal, but I think it's acceptable.

What about big packages (like tramp) that maintain and load their own
autoloads, and would like to request macro expansion for some of their
package-defined macros, and then also /use/ that macro in autoloads?
E.g. imagine if `tramp--with-startup' wanted to be expanded instead of
included as-is ("preloaded").  That's a pretty specific case, obviously.

> BTW, in the specific case of Tramp, I see:
>
>     (defmacro tramp--with-startup (&rest body)
>       "Schedule BODY to be executed at the end of tramp.el."
>       `(add-hook 'tramp--startup-hook (lambda nil ,@body)))
>
> so I think `tramp--with-startup` *is* one of the macros that would
> benefit from your new `(autoload macro-expand)` declaration.

Ah right, my imagining above was not so misguided then.  Maybe the tramp
maintainer will want to expand that simple macro away now.  I guess
package authors have to decide:

- Do you want to include ("preload") your full macro and any autoloaded
  uses of it (as is) in *-loaddefs.el?  You should be sure to require
  your package's custom autoload file with suppressed errors, in case it
  doesn't yet exist during build.

- Would you prefer your package's macro is expanded at autoload
  generation time instead?  You should require it "for real", and
  declare it (autoload-macro expand).

- You can't get both behaviors.

>> [1] Note that the order of declare entries already matters, 
>
> Really?  Sounds like a bug.  Are you sure?

You're right, it was a transitory bug.  I've moved them all back to the
end (since they are most recently added that seems to make sense).

>> (defconst loaddefs--function-like-operators
>
> "operators" doesn't sound quite right.
> Maybe "loaddefs--defining-macros"?

Yeah I agree, I was picking up the comment below that:

     ;; For special function-like operators, use the `autoload'
     ;; function.

But I like your version better (and have changed the comment).

>> +Note that macros can request expansion by including `(autoload
>> macro-expand)' +among their `declare' forms."
>
> Nitpick: I'd start "Note..." on its own line.  We're not trying to
> justify-fill the text.  🙂

Done (even an extra blank to call it out). 

>> +        ;; If the car is entirely unknown, we load the file first to
>> +        ;; give packages a chance to define their macros.
>> +        (unless (or (null car) (macrop car) (functionp car) (special-form-p car)
>
> I'd test (and (symbolp car) (not (fboundp car)))

For whatever reason, I get lots of nil cars.  So how about:

          (unless (or (not (symbolp car)) (fboundp car) (null car)
                      ... ;; try to load the file

Is

(eq (fboundp x) (or (macrop x) (functionp x) (special-form-p x))) ∀x∈ (symbolp x)?

>> +                    (memq car '(defclass defcustom deftheme defgroup))
> This deserves a comment in the code.

Done.

> I'd go with `assoc`.

Thanks.

>> +        (and (macrop car)
>> +	     (eq 'macro-expand ; a macro can declare (autoload macro-expand)
>> +		 (or (get car 'autoload)
>> +		     (get (car-safe (last (function-alias-p car))) 'autoload)))
>
> I'd have expected `function-get` here.

I was honestly vague on the difference.  Seems like `function-get'
should maybe chase aliases for you...

> If we swap this case with the preceding one we can remove the
>
>     (memq car loaddefs--function-like-operators)
>
> from the `unless` of that case.
> [ And it probably results in a diff that's harder to read, so thanks for
>   not doing it this time.  🙂 ]

Good idea. I only recently decided this was necessary.  Though it isn't
really needed anymore with this change, I think keeping a defconst is a
good idea.

>> @@ -257,8 +278,8 @@ loaddefs-generate--make-autoload
>>                        t)
>>                   (and (eq (car-safe (car body)) 'interactive)
>>                        ;; List of modes or just t.
>> -                      (or (if (nthcdr 1 (car body))
>> -                              (list 'quote (nthcdr 1 (car body)))
>> +                      (or (if (nthcdr 2 (car body))
>> +                              (list 'quote (nthcdr 2 (car body)))
>>                              t))))
>>              ,(if macrop ''macro nil)))))
>
> I think you can just push this to `master` as  separate patch, thank you.

I've attached a separate patch here (I don't have commit privileges).

>> @@ -19835,7 +19836,7 @@
>>  loaddefs.el output file, and the rest are the directories to
>>  use.")
>>   (load "theme-loaddefs.el" t)
>> -(register-definition-prefixes "loaddefs-gen" '("autoload-" "generated-autoload-" "loaddefs-generate--" "no-update-autoloads"))
>> +(register-definition-prefixes "loaddefs-gen" '("autoload-" "generated-autoload-" "loaddefs-" "my/tmp-lddg-list2" "no-update-autoloads"))
>
> Maybe better use `autoload-` rather than `loaddefs-` as prefix for the
> new definitions.
> [ I don't see `my/tmp-lddg-list2` in the patch you sent, so I assume it
>   was something temporary.  ]

This last file was an inadvertent inclusion.

Please take a look at the attached patches, and give a try with your own
user macro declaring autoload-expand if you can.  If this all looks good
I can add to the docs and NEWS.

[no-arg-descriptor-in-autoload.patch (text/x-patch, attachment)]
[autoload-expand_4.patch (text/x-patch, attachment)]

Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78995; Package emacs. (Sun, 27 Jul 2025 07:13:02 GMT) Full text and rfc822 format available.

Message #71 received at 78995 <at> debbugs.gnu.org (full text, mbox):

From: Michael Albinus <michael.albinus <at> gmx.de>
To: "J.D. Smith" <jdtsmith <at> gmail.com>
Cc: 78995 <at> debbugs.gnu.org, Stefan Monnier <monnier <at> iro.umontreal.ca>
Subject: Re: bug#78995: [PATCH] ;;;autoload-expand for special macros
Date: Sun, 27 Jul 2025 09:12:24 +0200
"J.D. Smith" <jdtsmith <at> gmail.com> writes:

Hi,

>> BTW, in the specific case of Tramp, I see:
>>
>>     (defmacro tramp--with-startup (&rest body)
>>       "Schedule BODY to be executed at the end of tramp.el."
>>       `(add-hook 'tramp--startup-hook (lambda nil ,@body)))
>>
>> so I think `tramp--with-startup` *is* one of the macros that would
>> benefit from your new `(autoload macro-expand)` declaration.
>
> Ah right, my imagining above was not so misguided then.  Maybe the tramp
> maintainer will want to expand that simple macro away now.

I give this explanation to Stefan, he added this macro to Tramp years
ago (commit 07d8827946f9) :-)

--8<---------------cut here---------------start------------->8---
    Functionally split tramp-loaddefs.el into two parts: one part run
    while loading it at the very beginning of loading tramp.el (holding plain
    autoloads and declarations), and another run at the very end of loading
    tramp.el (holding setup code).
    This should reduce infinite-recursion problems while loading.
--8<---------------cut here---------------end--------------->8---

See also bug#59194, which waits for me understanding what to do.

Best regards, Michael.




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78995; Package emacs. (Sun, 27 Jul 2025 13:13:02 GMT) Full text and rfc822 format available.

Message #74 received at 78995 <at> debbugs.gnu.org (full text, mbox):

From: Stefan Monnier <monnier <at> iro.umontreal.ca>
To: "J.D. Smith" <jdtsmith <at> gmail.com>
Cc: 78995 <at> debbugs.gnu.org, Michael Albinus <michael.albinus <at> gmx.de>
Subject: Re: bug#78995: [PATCH] ;;;autoload-expand for special macros
Date: Sun, 27 Jul 2025 09:11:47 -0400
> I suppose I had imagined multiple flags, à la:
>
>   (autoload (macro-expand something-else))
>
> but maybe that's frowned on.

It's not frowned upon no. You could also have

    (autoload macro-expand something-else)

>> Maybe a "general" solution would be to introduce a `;;;###preload`.
>> Not sure it's worth the trouble, tho.
> Could be considered radical.  I guess the contract would be that all
> `;;;###preload's would happen before all `;;;autoload's?  I can imagine
> people confusing these two (similar to use-package's :init vs. :config).

Yeah, I'd rather not go there (I think it might have made sense to
distinguish the two at the beginning, but now that it's been conflated
for so many years it'd be much harder to introduce the distinction).

>>> +        ;; If the car is entirely unknown, we load the file first to
>>> +        ;; give packages a chance to define their macros.
>>> +        (unless (or (null car) (macrop car) (functionp car) (special-form-p car)
>>
>> I'd test (and (symbolp car) (not (fboundp car)))
>
> For whatever reason, I get lots of nil cars.

Hmm... then there's something I'm missing.
I wonder in which case(s) `car` is nil here.

> So how about:
>
>           (unless (or (not (symbolp car)) (fboundp car) (null car)
>                       ... ;; try to load the file

Fine by me, tho I'd still like to understand why we need to care about `nil`.
We could also add `nil` to the (defclass defcustom deftheme defgroup) list.

> Is
>
> (eq (fboundp x) (or (macrop x) (functionp x) (special-form-p x))) ∀x∈ (symbolp x)?

No.  E.g. `x` could be bound to a keymap, or to a string (old-style
keyboard macro), or potentially to anything else (integer, hash-table,
you name it: that's not useful in the `symbol-function` cell but that
doesn't mean it can't happen).

>> I'd have expected `function-get` here.
> I was honestly vague on the difference.  Seems like `function-get'
> should maybe chase aliases for you...

It does.

>> I think you can just push this to `master` as  separate patch, thank you.
> I've attached a separate patch here (I don't have commit privileges).

Hmm...  According to
https://savannah.gnu.org/project/memberlist.php?group=emacs,
John-David T. Smith does have commit privileges.  I know "Smith" is not
exactly rare, but...

I'll gladly push it, if you prefer, of course.


        Stefan





Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78995; Package emacs. (Sun, 27 Jul 2025 13:15:02 GMT) Full text and rfc822 format available.

Message #77 received at 78995 <at> debbugs.gnu.org (full text, mbox):

From: Stefan Monnier <monnier <at> iro.umontreal.ca>
To: Michael Albinus <michael.albinus <at> gmx.de>
Cc: 78995 <at> debbugs.gnu.org, "J.D. Smith" <jdtsmith <at> gmail.com>
Subject: Re: bug#78995: [PATCH] ;;;autoload-expand for special macros
Date: Sun, 27 Jul 2025 09:14:33 -0400
>> Ah right, my imagining above was not so misguided then.  Maybe the tramp
>> maintainer will want to expand that simple macro away now.
>
> I give this explanation to Stefan, he added this macro to Tramp years
> ago (commit 07d8827946f9) :-)
>
> --8<---------------cut here---------------start------------->8---
>     Functionally split tramp-loaddefs.el into two parts: one part run
>     while loading it at the very beginning of loading tramp.el (holding plain
>     autoloads and declarations), and another run at the very end of loading
>     tramp.el (holding setup code).
>     This should reduce infinite-recursion problems while loading.
> --8<---------------cut here---------------end--------------->8---
>
> See also bug#59194, which waits for me understanding what to do.

[ It did look like something I'd seen before but I had no recollection
  of actually writing it.  ]

Damn!  So now I'm the one who needs to figure out how to keep it working
in Emacs<31 while trying to make it behave with the new
"autoload-expand".


        Stefan





Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78995; Package emacs. (Sun, 27 Jul 2025 18:00:02 GMT) Full text and rfc822 format available.

Message #80 received at 78995 <at> debbugs.gnu.org (full text, mbox):

From: "J.D. Smith" <jdtsmith <at> gmail.com>
To: Stefan Monnier <monnier <at> iro.umontreal.ca>
Cc: 78995 <at> debbugs.gnu.org, Michael Albinus <michael.albinus <at> gmx.de>
Subject: Re: bug#78995: [PATCH] ;;;autoload-expand for special macros
Date: Sun, 27 Jul 2025 13:59:05 -0400
Stefan Monnier <monnier <at> iro.umontreal.ca> writes:

>>> Ah right, my imagining above was not so misguided then.  Maybe the tramp
>>> maintainer will want to expand that simple macro away now.
>>
>> I give this explanation to Stefan, he added this macro to Tramp years
>> ago (commit 07d8827946f9) :-)
>>
>> --8<---------------cut here---------------start------------->8---
>>     Functionally split tramp-loaddefs.el into two parts: one part run
>>     while loading it at the very beginning of loading tramp.el (holding plain
>>     autoloads and declarations), and another run at the very end of loading
>>     tramp.el (holding setup code).
>>     This should reduce infinite-recursion problems while loading.
>> --8<---------------cut here---------------end--------------->8---
>>
>> See also bug#59194, which waits for me understanding what to do.
>
> [ It did look like something I'd seen before but I had no recollection
>   of actually writing it.  ]
>
> Damn!  So now I'm the one who needs to figure out how to keep it working
> in Emacs<31 while trying to make it behave with the new
> "autoload-expand".


Maybe it is as simple as requiring a (new?) file that defines the macro
directly, and whenever you require tramp-loaddefs, using NOERROR=t?

Then in Emacs 31, the first file with an ;;;###autoload followed by
usage of TRAMP's macro will be loaded, causing the macro to be defined.
If you want, you can declare `(autoload-macro expand)' when you define
the macro (I think old Emacs version will just ignore it?). This will
mean:

- In Emacs 31: the macro itself is never mentioned, but the add-hook and
  any other forms are instead copied into tramp-loaddefs.

- In earlier Emacs, the macro and then calls to it are both included in
  tramp-loaddefs, just as they are now.

I think either setup works (though on-demand expansion may be "safer",
since it doesn't depend on load order any more.)




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78995; Package emacs. (Sun, 27 Jul 2025 19:15:01 GMT) Full text and rfc822 format available.

Message #83 received at 78995 <at> debbugs.gnu.org (full text, mbox):

From: "J.D. Smith" <jdtsmith <at> gmail.com>
To: Stefan Monnier <monnier <at> iro.umontreal.ca>
Cc: 78995 <at> debbugs.gnu.org, Michael Albinus <michael.albinus <at> gmx.de>
Subject: Re: bug#78995: [PATCH] ;;;autoload-expand for special macros
Date: Sun, 27 Jul 2025 15:14:21 -0400
[Message part 1 (text/plain, inline)]
Stefan Monnier <monnier <at> iro.umontreal.ca> writes:

>> For whatever reason, I get lots of nil cars.
>
> Hmm... then there's something I'm missing.
> I wonder in which case(s) `car` is nil here.

One big category of nil car's resulted from all the :autoload-end's
around.  Because only the tail /after/ that keyword is trimmed (a
classic singly linked list issue), the keyword itself remains in the
form, and was still being (pointlessly) recursed on.  Easy fix.

That leaves a number with explicit nil cars in their expansion, for
whatever reason:

   Got nil car:
   nil "display-line-numbers" expansion
   Got nil car:
   nil "elec-pair" expansion
   Got nil car:
   nil "emacs-lock" expansion
   Got nil car:
   nil "hi-lock" expansion
   Got nil car:
   nil "hilit-chg" expansion
   Got nil car:
   nil "ruler-mode" expansion
   Got nil car:
   nil "saveplace" expansion
   Got nil car:
   nil "tab-line" expansion
     INFO     Scraping 1566 files for loaddefs...17% 
   Got nil car:
   nil "visual-wrap" expansion
   Got nil car:
   nil "whitespace" expansion
   Got nil car:
   nil "window-tool-bar" expansion
     INFO     Scraping 1566 files for loaddefs...39% 
     INFO     Scraping 1566 files for loaddefs...64% 
   Got nil car:
   nil "goto-addr" expansion
   loaddefs-gen: loading file tramp-adb (for tramp--with-startup)
   Loading tramp-adb...
   Source file ‘code/emacs/emacs-mac/lisp/net/tramp-loaddefs.el’ newer than byte-compiled file; using older file
   Source file ‘code/emacs/emacs-mac/lisp/emacs-lisp/cl-loaddefs.el’ newer than byte-compiled file; using older file
     INFO     Scraping 1566 files for loaddefs...80% 
   Got nil car:
   nil "cwarn" expansion
   Got nil car:
   nil "subword" expansion
   Got nil car:
   nil "subword" expansion
     INFO     Scraping 1566 files for loaddefs...92% 
   Got nil car:
   nil "word-wrap-mode" expansion

Probably define-minor-mode includes some bare symbols in the expansion?
Are there good reasons for including non-forms in an autoload file?
Bare strings or symbols?

BTW, I also realized there actually /was/ a small reason to put the
`autoload-macro' cond form first, before the special cases: all presence
on that list does is avoid /loading/ the file, if any symbol-car's
happen to be undefined (which is of course unlikely for such a
hard-coded list of special macros).  The recursing on expansion still
happens, if requested.  Putting ours first is a form of eating our own
dog food.  If all the defining-macros are cleaned up so that expansions
are sensible, the special case can be entirely omitted in favor of
direct expansion.  Letting the macros advertise their own interactive
forms = fewer bugs (of the nthcdr sort I had to correct).

Right now, autoloads proceed through the special case for:

 - define-derived-mode
 - cl-defun (I guess because cl-macs.el is not loaded?)
 - define-overloadable-function
 - define-skeleton
 - define-compilation-mode

>>> I'd have expected `function-get` here.
>> I was honestly vague on the difference.  Seems like `function-get'
>> should maybe chase aliases for you...
>
> It does.

Oh nice.  Not obvious from its code.  I've simplified accordingly. 

>>> I think you can just push this to `master` as  separate patch, thank you.
>> I've attached a separate patch here (I don't have commit privileges).
>
> Hmm...  According to
> https://savannah.gnu.org/project/memberlist.php?group=emacs,
> John-David T. Smith does have commit privileges.  I know "Smith" is not
> exactly rare, but...

Huh, maybe I've just never exercised them.  Or maybe I assumed there
would be a ceremony of some kind :).

> I'll gladly push it, if you prefer, of course.

No, it's a good chance to learn.  Will want to iterate on docs first, if
you think its ready (I think it is).  I took the chance to clean up the
declare forms to simplify the diff as well.

Have you had a chance to test it "in the wild" with a custom macro?

[autoload-expand_5.patch (text/x-patch, attachment)]

Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78995; Package emacs. (Tue, 29 Jul 2025 21:19:02 GMT) Full text and rfc822 format available.

Message #86 received at 78995 <at> debbugs.gnu.org (full text, mbox):

From: Stefan Monnier <monnier <at> iro.umontreal.ca>
To: "J.D. Smith" <jdtsmith <at> gmail.com>
Cc: 78995 <at> debbugs.gnu.org, Michael Albinus <michael.albinus <at> gmx.de>
Subject: Re: bug#78995: [PATCH] ;;;autoload-expand for special macros
Date: Tue, 29 Jul 2025 17:18:33 -0400
>> Damn!  So now I'm the one who needs to figure out how to keep it working
>> in Emacs<31 while trying to make it behave with the new
>> "autoload-expand".
> Maybe it is as simple as requiring a (new?) file that defines the macro
> directly, and whenever you require tramp-loaddefs, using NOERROR=t?

I *think* it's simpler than that: just add the `declare` thingy and the
NOERROR=t.


        Stefan


diff --git a/lisp/net/tramp-compat.el b/lisp/net/tramp-compat.el
index 9787e3a6553..f003bbebf31 100644
--- a/lisp/net/tramp-compat.el
+++ b/lisp/net/tramp-compat.el
@@ -29,7 +29,7 @@
 
 ;;; Code:
 
-(require 'tramp-loaddefs)
+(require 'tramp-loaddefs nil t) ;; Don't error while building the autoloads.
 (require 'ansi-color)
 (require 'auth-source)
 (require 'format-spec)
diff --git a/lisp/net/tramp.el b/lisp/net/tramp.el
index 2208ce880d7..485c18fc4a2 100644
--- a/lisp/net/tramp.el
+++ b/lisp/net/tramp.el
@@ -105,6 +105,7 @@ tramp-completion-file-name-regexp
 
   (defmacro tramp--with-startup (&rest body)
     "Schedule BODY to be executed at the end of tramp.el."
+    (declare (autoload macro-expand))
     `(add-hook 'tramp--startup-hook (lambda () ,@body)))
 
   (eval-and-compile





Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78995; Package emacs. (Tue, 29 Jul 2025 21:31:01 GMT) Full text and rfc822 format available.

Message #89 received at 78995 <at> debbugs.gnu.org (full text, mbox):

From: Stefan Monnier <monnier <at> iro.umontreal.ca>
To: "J.D. Smith" <jdtsmith <at> gmail.com>
Cc: 78995 <at> debbugs.gnu.org, Michael Albinus <michael.albinus <at> gmx.de>
Subject: Re: bug#78995: [PATCH] ;;;autoload-expand for special macros
Date: Tue, 29 Jul 2025 17:29:49 -0400
> One big category of nil car's resulted from all the :autoload-end's around.

Oh, what you mean is that nil is when the element is not a cons cell?
Indeed that makes sense.
[ Cons cells with a nil element would be surprising, OTOH.  ]

> That leaves a number with explicit nil cars in their expansion, for
> whatever reason:

I think these have `nil` in the list of forms (that follows a `progn`),
but not in the `car` of one of the forms, right?  So again, it's when
`form` is not a cons-cell.
In any case, indeed those non-cons situations justify the "not nil" check.

> Probably define-minor-mode includes some bare symbols in the expansion?
> Are there good reasons for including non-forms in an autoload file?
> Bare strings or symbols?

No, they can be removed, but if we compile the `.el`, then the
compiler takes care of it for us.

>> I'll gladly push it, if you prefer, of course.
> No, it's a good chance to learn.  Will want to iterate on docs first, if
> you think its ready (I think it is).

I was thinking to do it in the single-hunk bug fix, which I do think is
ready (it just needs a commit message).

> Have you had a chance to test it "in the wild" with a custom macro?

No, not yet.  But I think the transient macros are a good test case.


        Stefan





Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78995; Package emacs. (Wed, 30 Jul 2025 00:37:02 GMT) Full text and rfc822 format available.

Message #92 received at 78995 <at> debbugs.gnu.org (full text, mbox):

From: "J.D. Smith" <jdtsmith <at> gmail.com>
To: Stefan Monnier <monnier <at> iro.umontreal.ca>
Cc: 78995 <at> debbugs.gnu.org, Michael Albinus <michael.albinus <at> gmx.de>
Subject: Re: bug#78995: [PATCH] ;;;autoload-expand for special macros
Date: Tue, 29 Jul 2025 20:36:11 -0400
Stefan Monnier <monnier <at> iro.umontreal.ca> writes:

>>> Damn!  So now I'm the one who needs to figure out how to keep it working
>>> in Emacs<31 while trying to make it behave with the new
>>> "autoload-expand".
>> Maybe it is as simple as requiring a (new?) file that defines the macro
>> directly, and whenever you require tramp-loaddefs, using NOERROR=t?
>
> I *think* it's simpler than that: just add the `declare` thingy and the
> NOERROR=t.

Ahah, I see that tramp-compat is required, so this should work.  It's
`(autoload-macro expand)' btw.




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78995; Package emacs. (Wed, 30 Jul 2025 01:42:02 GMT) Full text and rfc822 format available.

Message #95 received at 78995 <at> debbugs.gnu.org (full text, mbox):

From: "J.D. Smith" <jdtsmith <at> gmail.com>
To: Stefan Monnier <monnier <at> iro.umontreal.ca>
Cc: 78995 <at> debbugs.gnu.org, Michael Albinus <michael.albinus <at> gmx.de>
Subject: Re: bug#78995: [PATCH] ;;;autoload-expand for special macros
Date: Tue, 29 Jul 2025 21:41:12 -0400
[Message part 1 (text/plain, inline)]
Stefan Monnier <monnier <at> iro.umontreal.ca> writes:

>> One big category of nil car's resulted from all the :autoload-end's around.
>
> Oh, what you mean is that nil is when the element is not a cons cell?
> Indeed that makes sense.
> [ Cons cells with a nil element would be surprising, OTOH.  ]

Yep, like :autoload-end :). 

>> That leaves a number with explicit nil cars in their expansion, for
>> whatever reason:
>
> I think these have `nil` in the list of forms (that follows a `progn`),
> but not in the `car` of one of the forms, right?  So again, it's when
> `form` is not a cons-cell.
> In any case, indeed those non-cons situations justify the "not nil" check.

Yes, but I just wonder what such non-conses are doing in the expansion.
Maybe just doc strings or some such.

>> No, it's a good chance to learn.  Will want to iterate on docs first, if
>> you think its ready (I think it is).
>
> I was thinking to do it in the single-hunk bug fix, which I do think is
> ready (it just needs a commit message).

Is the commit message in need of expansion?  I worked up some quick docs
and included in the patch; see attached.

>> Have you had a chance to test it "in the wild" with a custom macro?
>
> No, not yet.  But I think the transient macros are a good test case.

Good idea.  Michael, if you can try this along with a patch like the one
Stefan proposed for tramp (correcting the declare form name) that would
be useful.  Assuming it all works as expected, you'll notice
`tramp-loaddefs.el' no longer contains the macro and the calls to it,
but rather only the expanded forms it generates.

[autoload-expand_6.patch (text/x-patch, attachment)]

Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78995; Package emacs. (Wed, 30 Jul 2025 08:01:02 GMT) Full text and rfc822 format available.

Message #98 received at 78995 <at> debbugs.gnu.org (full text, mbox):

From: Michael Albinus <michael.albinus <at> gmx.de>
To: "J.D. Smith" <jdtsmith <at> gmail.com>
Cc: 78995 <at> debbugs.gnu.org, Stefan Monnier <monnier <at> iro.umontreal.ca>
Subject: Re: bug#78995: [PATCH] ;;;autoload-expand for special macros
Date: Wed, 30 Jul 2025 10:00:00 +0200
"J.D. Smith" <jdtsmith <at> gmail.com> writes:

Hi,

> Good idea.  Michael, if you can try this along with a patch like the one
> Stefan proposed for tramp (correcting the declare form name) that would
> be useful.  Assuming it all works as expected, you'll notice
> `tramp-loaddefs.el' no longer contains the macro and the calls to it,
> but rather only the expanded forms it generates.

Before doing so, I've tried Stefan's patch with Emacs 28. There are
compilation warnings.

--8<---------------cut here---------------start------------->8---
# gmake -C lisp distclean ; gmake -C lisp EMACS=/usr/local/src/emacs-28/src/emacs
gmake: Entering directory '/home/albinus/src/tramp/lisp'
rm -f .\#* \#* .*~ *~ *.aux *.cp *.cps *.diff *.dvi *.elc *.fn *.fns *.html *.info *.ky *.kys *.log *.pdf *.pg *.tmp *.toc *.tp *.vr *.vrs
rm -f tramp-loaddefs.el
gmake: Leaving directory '/home/albinus/src/tramp/lisp'
gmake: Entering directory '/home/albinus/src/tramp/lisp'
/usr/local/src/emacs-28/src/emacs -Q -batch -L /home/albinus/src/tramp/lisp -l autoload						    \
  --eval "(setq generate-autoload-cookie \";;;###tramp-autoload\")" \
  --eval "(setq generated-autoload-file				    \
	    (expand-file-name \"tramp-loaddefs.el\"))"		    \
  --eval "(setq make-backup-files nil)"				    \
  -f batch-update-autoloads .
  SCRAPE   .
  INFO     Scraping files for tramp-loaddefs.el... 
  INFO     Scraping files for tramp-loaddefs.el...done
/usr/local/src/emacs-28/src/emacs -Q -batch -L /home/albinus/src/tramp/lisp -l bytecomp -f batch-byte-compile tramp-loaddefs.el
/usr/local/src/emacs-28/src/emacs -Q -batch -L /home/albinus/src/tramp/lisp -l bytecomp -f batch-byte-compile trampver.el
/usr/local/src/emacs-28/src/emacs -Q -batch -L /home/albinus/src/tramp/lisp -l bytecomp -f batch-byte-compile tramp-compat.el
tramp-loaddefs.el: Warning: Unknown macro property autoload-macro in tramp--with-startup
/usr/local/src/emacs-28/src/emacs -Q -batch -L /home/albinus/src/tramp/lisp -l bytecomp -f batch-byte-compile tramp.el
tramp-loaddefs.el: Warning: Unknown macro property autoload-macro in tramp--with-startup

In toplevel form:
tramp.el:109:50: Warning: Unknown macro property autoload-macro in
    tramp--with-startup
/usr/local/src/emacs-28/src/emacs -Q -batch -L /home/albinus/src/tramp/lisp -l bytecomp -f batch-byte-compile tramp-adb.el
tramp-loaddefs.el: Warning: Unknown macro property autoload-macro in tramp--with-startup
/usr/local/src/emacs-28/src/emacs -Q -batch -L /home/albinus/src/tramp/lisp -l bytecomp -f batch-byte-compile tramp-androidsu.el
tramp-loaddefs.el: Warning: Unknown macro property autoload-macro in tramp--with-startup
/usr/local/src/emacs-28/src/emacs -Q -batch -L /home/albinus/src/tramp/lisp -l bytecomp -f batch-byte-compile tramp-cache.el
tramp-loaddefs.el: Warning: Unknown macro property autoload-macro in tramp--with-startup
/usr/local/src/emacs-28/src/emacs -Q -batch -L /home/albinus/src/tramp/lisp -l bytecomp -f batch-byte-compile tramp-cmds.el
tramp-loaddefs.el: Warning: Unknown macro property autoload-macro in tramp--with-startup
/usr/local/src/emacs-28/src/emacs -Q -batch -L /home/albinus/src/tramp/lisp -l bytecomp -f batch-byte-compile tramp-container.el
tramp-loaddefs.el: Warning: Unknown macro property autoload-macro in tramp--with-startup
/usr/local/src/emacs-28/src/emacs -Q -batch -L /home/albinus/src/tramp/lisp -l bytecomp -f batch-byte-compile tramp-crypt.el
tramp-loaddefs.el: Warning: Unknown macro property autoload-macro in tramp--with-startup
/usr/local/src/emacs-28/src/emacs -Q -batch -L /home/albinus/src/tramp/lisp -l bytecomp -f batch-byte-compile tramp-ftp.el
tramp-loaddefs.el: Warning: Unknown macro property autoload-macro in tramp--with-startup
/usr/local/src/emacs-28/src/emacs -Q -batch -L /home/albinus/src/tramp/lisp -l bytecomp -f batch-byte-compile tramp-fuse.el
tramp-loaddefs.el: Warning: Unknown macro property autoload-macro in tramp--with-startup
/usr/local/src/emacs-28/src/emacs -Q -batch -L /home/albinus/src/tramp/lisp -l bytecomp -f batch-byte-compile tramp-integration.el
tramp-loaddefs.el: Warning: Unknown macro property autoload-macro in tramp--with-startup
/usr/local/src/emacs-28/src/emacs -Q -batch -L /home/albinus/src/tramp/lisp -l bytecomp -f batch-byte-compile tramp-message.el
tramp-loaddefs.el: Warning: Unknown macro property autoload-macro in tramp--with-startup
/usr/local/src/emacs-28/src/emacs -Q -batch -L /home/albinus/src/tramp/lisp -l bytecomp -f batch-byte-compile tramp-rclone.el
tramp-loaddefs.el: Warning: Unknown macro property autoload-macro in tramp--with-startup
/usr/local/src/emacs-28/src/emacs -Q -batch -L /home/albinus/src/tramp/lisp -l bytecomp -f batch-byte-compile tramp-sh.el
tramp-loaddefs.el: Warning: Unknown macro property autoload-macro in tramp--with-startup
/usr/local/src/emacs-28/src/emacs -Q -batch -L /home/albinus/src/tramp/lisp -l bytecomp -f batch-byte-compile tramp-smb.el
tramp-loaddefs.el: Warning: Unknown macro property autoload-macro in tramp--with-startup
/usr/local/src/emacs-28/src/emacs -Q -batch -L /home/albinus/src/tramp/lisp -l bytecomp -f batch-byte-compile tramp-sshfs.el
tramp-loaddefs.el: Warning: Unknown macro property autoload-macro in tramp--with-startup
/usr/local/src/emacs-28/src/emacs -Q -batch -L /home/albinus/src/tramp/lisp -l bytecomp -f batch-byte-compile tramp-sudoedit.el
tramp-loaddefs.el: Warning: Unknown macro property autoload-macro in tramp--with-startup
/usr/local/src/emacs-28/src/emacs -Q -batch -L /home/albinus/src/tramp/lisp -l bytecomp -f batch-byte-compile tramp-uu.el
/usr/local/src/emacs-28/src/emacs -Q -batch -L /home/albinus/src/tramp/lisp -l bytecomp -f batch-byte-compile tramp-archive.el
tramp-loaddefs.el: Warning: Unknown macro property autoload-macro in tramp--with-startup
/usr/local/src/emacs-28/src/emacs -Q -batch -L /home/albinus/src/tramp/lisp -l bytecomp -f batch-byte-compile tramp-gvfs.el
tramp-loaddefs.el: Warning: Unknown macro property autoload-macro in tramp--with-startup
gmake: Leaving directory '/home/albinus/src/tramp/lisp'
--8<---------------cut here---------------end--------------->8---

And also at runtime.

--8<---------------cut here---------------start------------->8---
# /usr/local/src/emacs-28/src/emacs -Q -L /home/albinus/src/tramp/lisp /ssh::
For information about GNU Emacs and the GNU system, type C-h C-a.
../home/albinus/src/tramp/lisp/tramp-loaddefs.el: Warning: Unknown macro property autoload-macro in tramp--with-startup
Waiting for git... [2 times]
Tramp: Opening connection for gandalf using ssh...done
Tramp: Setup connection for gandalf using ssh...done
--8<---------------cut here---------------end--------------->8---

Best regards, Michael.




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78995; Package emacs. (Wed, 30 Jul 2025 12:35:02 GMT) Full text and rfc822 format available.

Message #101 received at 78995 <at> debbugs.gnu.org (full text, mbox):

From: "J.D. Smith" <jdtsmith <at> gmail.com>
To: Michael Albinus <michael.albinus <at> gmx.de>
Cc: 78995 <at> debbugs.gnu.org, Stefan Monnier <monnier <at> iro.umontreal.ca>
Subject: Re: bug#78995: [PATCH] ;;;autoload-expand for special macros
Date: Wed, 30 Jul 2025 08:34:13 -0400
Michael Albinus <michael.albinus <at> gmx.de> writes:

> "J.D. Smith" <jdtsmith <at> gmail.com> writes:
>
> Hi,
>
>> Good idea.  Michael, if you can try this along with a patch like the one
>> Stefan proposed for tramp (correcting the declare form name) that would
>> be useful.  Assuming it all works as expected, you'll notice
>> `tramp-loaddefs.el' no longer contains the macro and the calls to it,
>> but rather only the expanded forms it generates.
>
> Before doing so, I've tried Stefan's patch with Emacs 28. There are
> compilation warnings.
>    ...
> And also at runtime.

That would seem to make it difficult to add new declare forms and
simultaneously support older versions of Emacs.  How have such issues
been dealt with in the past?  Do you have a version or branch of TRAMP
that is only deployed on master?




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78995; Package emacs. (Wed, 30 Jul 2025 15:40:01 GMT) Full text and rfc822 format available.

Message #104 received at 78995 <at> debbugs.gnu.org (full text, mbox):

From: Stefan Monnier <monnier <at> iro.umontreal.ca>
To: "J.D. Smith" <jdtsmith <at> gmail.com>
Cc: 78995 <at> debbugs.gnu.org, Michael Albinus <michael.albinus <at> gmx.de>
Subject: Re: bug#78995: [PATCH] ;;;autoload-expand for special macros
Date: Wed, 30 Jul 2025 11:38:55 -0400
>>> Good idea.  Michael, if you can try this along with a patch like the one
>>> Stefan proposed for tramp (correcting the declare form name) that would
>>> be useful.  Assuming it all works as expected, you'll notice
>>> `tramp-loaddefs.el' no longer contains the macro and the calls to it,
>>> but rather only the expanded forms it generates.
>>
>> Before doing so, I've tried Stefan's patch with Emacs 28. There are
>> compilation warnings.
>>    ...
>> And also at runtime.
>
> That would seem to make it difficult to add new declare forms and
> simultaneously support older versions of Emacs.  How have such issues
> been dealt with in the past?  Do you have a version or branch of TRAMP
> that is only deployed on master?

I think it's not that bad: just adding the ERROR=t is sufficient.
The `autoload-macro` declaration can be kept for later, once Tramp drops
support for Emacs<31.

I suspect the same will apply for Transient: we'll want to make sure the
new functionality works well for it, but we'll have to keep the old
ad-hoc solution until it drops support for Emacs<31.


        Stefan





Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78995; Package emacs. (Wed, 30 Jul 2025 15:45:02 GMT) Full text and rfc822 format available.

Message #107 received at 78995 <at> debbugs.gnu.org (full text, mbox):

From: Michael Albinus <michael.albinus <at> gmx.de>
To: "J.D. Smith" <jdtsmith <at> gmail.com>
Cc: 78995 <at> debbugs.gnu.org, Stefan Monnier <monnier <at> iro.umontreal.ca>
Subject: Re: bug#78995: [PATCH] ;;;autoload-expand for special macros
Date: Wed, 30 Jul 2025 17:44:15 +0200
"J.D. Smith" <jdtsmith <at> gmail.com> writes:

Hi,
>> Before doing so, I've tried Stefan's patch with Emacs 28. There are
>> compilation warnings.
>>    ...
>> And also at runtime.
>
> That would seem to make it difficult to add new declare forms and
> simultaneously support older versions of Emacs.  How have such issues
> been dealt with in the past?  Do you have a version or branch of TRAMP
> that is only deployed on master?

No, there's only one Tramp branch, which is deployed on master and on
GNU ELPA.

Tramp uses an own declare form `tramp-suppress-trace'. In order to make
it happen, there's the code

--8<---------------cut here---------------start------------->8---
(eval-and-compile
  (defalias 'tramp-byte-run--set-suppress-trace
    #'(lambda (f _args val)
	(list 'function-put (list 'quote f)
	      ''tramp-suppress-trace val)))

  (add-to-list
   'defun-declarations-alist
   (list 'tramp-suppress-trace #'tramp-byte-run--set-suppress-trace))))
--8<---------------cut here---------------end--------------->8---

Perhaps this trick could be used?

Best regards, Michael.




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78995; Package emacs. (Wed, 30 Jul 2025 15:55:03 GMT) Full text and rfc822 format available.

Message #110 received at 78995 <at> debbugs.gnu.org (full text, mbox):

From: "J.D. Smith" <jdtsmith <at> gmail.com>
To: Michael Albinus <michael.albinus <at> gmx.de>
Cc: 78995 <at> debbugs.gnu.org, Stefan Monnier <monnier <at> iro.umontreal.ca>
Subject: Re: bug#78995: [PATCH] ;;;autoload-expand for special macros
Date: Wed, 30 Jul 2025 11:54:18 -0400
Michael Albinus <michael.albinus <at> gmx.de> writes:
>
> Tramp uses an own declare form `tramp-suppress-trace'. In order to make
> it happen, there's the code
>

We are already adding the new declare form to `macro-declarations-alist', but the problem is, this code will not exist in Emacs <31.  I guess we could recommend:

 (add-to-list macro-declarations-alist (list autoload-macro ignore))

in the meantime.  But just skipping the declare (for now) as Stefan
suggests is I guess the simpler approach.  People who want to use it
will need to require v>=31.




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78995; Package emacs. (Wed, 30 Jul 2025 17:52:02 GMT) Full text and rfc822 format available.

Message #113 received at 78995 <at> debbugs.gnu.org (full text, mbox):

From: Michael Albinus <michael.albinus <at> gmx.de>
To: "J.D. Smith" <jdtsmith <at> gmail.com>
Cc: 78995 <at> debbugs.gnu.org, Stefan Monnier <monnier <at> iro.umontreal.ca>
Subject: Re: bug#78995: [PATCH] ;;;autoload-expand for special macros
Date: Wed, 30 Jul 2025 19:51:02 +0200
"J.D. Smith" <jdtsmith <at> gmail.com> writes:

Hi,

>> Tramp uses an own declare form `tramp-suppress-trace'. In order to make
>> it happen, there's the code
>
> We are already adding the new declare form to
> `macro-declarations-alist', but the problem is, this code will not
> exist in Emacs <31.

I meant to do this in tramp.el or tramp-compat.el

Best regards, Michael.




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78995; Package emacs. (Wed, 30 Jul 2025 18:26:01 GMT) Full text and rfc822 format available.

Message #116 received at 78995 <at> debbugs.gnu.org (full text, mbox):

From: "J.D. Smith" <jdtsmith <at> gmail.com>
To: Michael Albinus <michael.albinus <at> gmx.de>
Cc: 78995 <at> debbugs.gnu.org, Stefan Monnier <monnier <at> iro.umontreal.ca>
Subject: Re: bug#78995: [PATCH] ;;;autoload-expand for special macros
Date: Wed, 30 Jul 2025 14:25:35 -0400
Michael Albinus <michael.albinus <at> gmx.de> writes:

> "J.D. Smith" <jdtsmith <at> gmail.com> writes:
>
> Hi,
>
>>> Tramp uses an own declare form `tramp-suppress-trace'. In order to make
>>> it happen, there's the code
>>
>> We are already adding the new declare form to
>> `macro-declarations-alist', but the problem is, this code will not
>> exist in Emacs <31.
>
> I meant to do this in tramp.el or tramp-compat.el

Aha.  One idea would be for tramp-compat to including something like:

    ;; Remove when Emacs >=31 is required
    (require 'loaddefs-gen)
    (cl-symbol-macrolet
        ((amac (alist-get 'autoload-macro macro-declarations-alist)))
      (unless amac (setq amac #'ignore)))   

to silence the warning, yet remain harmless once Emacs 31 is in the
wild.




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78995; Package emacs. (Thu, 31 Jul 2025 05:25:02 GMT) Full text and rfc822 format available.

Message #119 received at 78995 <at> debbugs.gnu.org (full text, mbox):

From: Michael Albinus <michael.albinus <at> gmx.de>
To: "J.D. Smith" <jdtsmith <at> gmail.com>
Cc: 78995 <at> debbugs.gnu.org, Stefan Monnier <monnier <at> iro.umontreal.ca>
Subject: Re: bug#78995: [PATCH] ;;;autoload-expand for special macros
Date: Thu, 31 Jul 2025 07:23:51 +0200
"J.D. Smith" <jdtsmith <at> gmail.com> writes:

Hi,

> Aha.  One idea would be for tramp-compat to including something like:
>
>     ;; Remove when Emacs >=31 is required
>     (require 'loaddefs-gen)
>     (cl-symbol-macrolet
>         ((amac (alist-get 'autoload-macro macro-declarations-alist)))
>       (unless amac (setq amac #'ignore)))   
>
> to silence the warning, yet remain harmless once Emacs 31 is in the
> wild.

Feel free to add this to Tramp in master. I'm busy these days; will
check over the weekend.

Best regards, Michael.




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78995; Package emacs. (Fri, 01 Aug 2025 14:40:02 GMT) Full text and rfc822 format available.

Message #122 received at 78995 <at> debbugs.gnu.org (full text, mbox):

From: Michael Albinus <michael.albinus <at> gmx.de>
To: "J.D. Smith" <jdtsmith <at> gmail.com>
Cc: 78995 <at> debbugs.gnu.org, Stefan Monnier <monnier <at> iro.umontreal.ca>
Subject: Re: bug#78995: [PATCH] ;;;autoload-expand for special macros
Date: Fri, 01 Aug 2025 16:39:37 +0200
"J.D. Smith" <jdtsmith <at> gmail.com> writes:

Hi,

>>>> Tramp uses an own declare form `tramp-suppress-trace'. In order to make
>>>> it happen, there's the code
>>>
>>> We are already adding the new declare form to
>>> `macro-declarations-alist', but the problem is, this code will not
>>> exist in Emacs <31.
>>
>> I meant to do this in tramp.el or tramp-compat.el
>
> Aha.  One idea would be for tramp-compat to including something like:
>
>     ;; Remove when Emacs >=31 is required
>     (require 'loaddefs-gen)
>     (cl-symbol-macrolet
>         ((amac (alist-get 'autoload-macro macro-declarations-alist)))
>       (unless amac (setq amac #'ignore)))   
>
> to silence the warning, yet remain harmless once Emacs 31 is in the
> wild.

That doesn't work with Emacs 28:

--8<---------------cut here---------------start------------->8---
# make -C lisp EMACS=/home/albinus/src/emacs-28/src/emacs
make: Entering directory '/home/albinus/src/tramp/lisp'
/home/albinus/src/emacs-28/src/emacs -Q -batch -L /home/albinus/src/tramp/lisp -l autoload						    \
  --eval "(setq generate-autoload-cookie \";;;###tramp-autoload\")" \
  --eval "(setq generated-autoload-file				    \
	    (expand-file-name \"tramp-loaddefs.el\"))"		    \
  --eval "(setq make-backup-files nil)"				    \
  -f batch-update-autoloads .
  SCRAPE   .
  INFO     Scraping files for tramp-loaddefs.el... 
  INFO     Scraping files for tramp-loaddefs.el...done
/home/albinus/src/emacs-28/src/emacs -Q -batch -L /home/albinus/src/tramp/lisp -l bytecomp -f batch-byte-compile tramp-loaddefs.el
/home/albinus/src/emacs-28/src/emacs -Q -batch -L /home/albinus/src/tramp/lisp -l bytecomp -f batch-byte-compile trampver.el
/home/albinus/src/emacs-28/src/emacs -Q -batch -L /home/albinus/src/tramp/lisp -l bytecomp -f batch-byte-compile tramp-compat.el

In toplevel form:
tramp-compat.el:33:1: Error: Cannot open load file: No such file or directory, loaddefs-gen
make: *** [Makefile:77: tramp-compat.elc] Error 1
make: Leaving directory '/home/albinus/src/tramp/lisp'
--8<---------------cut here---------------end--------------->8---

Best regards, Michael.




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78995; Package emacs. (Fri, 01 Aug 2025 18:49:03 GMT) Full text and rfc822 format available.

Message #125 received at 78995 <at> debbugs.gnu.org (full text, mbox):

From: "J.D. Smith" <jdtsmith <at> gmail.com>
To: Michael Albinus <michael.albinus <at> gmx.de>
Cc: 78995 <at> debbugs.gnu.org, Stefan Monnier <monnier <at> iro.umontreal.ca>
Subject: Re: bug#78995: [PATCH] ;;;autoload-expand for special macros
Date: Fri, 01 Aug 2025 14:48:06 -0400
Michael Albinus <michael.albinus <at> gmx.de> writes:

> "J.D. Smith" <jdtsmith <at> gmail.com> writes:
>
> Hi,
>
>>>>> Tramp uses an own declare form `tramp-suppress-trace'. In order to make
>>>>> it happen, there's the code
>>>>
>>>> We are already adding the new declare form to
>>>> `macro-declarations-alist', but the problem is, this code will not
>>>> exist in Emacs <31.
>>>
>>> I meant to do this in tramp.el or tramp-compat.el
>>
>> Aha.  One idea would be for tramp-compat to including something like:
>>
>>     ;; Remove when Emacs >=31 is required
>>     (require 'loaddefs-gen)
>>     (cl-symbol-macrolet
>>         ((amac (alist-get 'autoload-macro macro-declarations-alist)))
>>       (unless amac (setq amac #'ignore)))   
>>
>> to silence the warning, yet remain harmless once Emacs 31 is in the
>> wild.
>
> That doesn't work with Emacs 28:
>

Hmm, I guess `loaddefs-gen' was introduced in emacs 29.  But I think you
don't actually need that `require' at all.  Maybe try a simple:

    (unless (alist-get 'autoload-macro macro-declarations-alist)
      (push '(autoload-macro ignore) macro-declarations-alist))




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78995; Package emacs. (Fri, 01 Aug 2025 22:38:02 GMT) Full text and rfc822 format available.

Message #128 received at 78995 <at> debbugs.gnu.org (full text, mbox):

From: "J.D. Smith" <jdtsmith <at> gmail.com>
To: 78995 <at> debbugs.gnu.org,  Stefan Monnier <monnier <at> iro.umontreal.ca>, Eli
 Zaretskii <eliz <at> gnu.org>, Philip Kaludercic <philipk <at> posteo.net>
Subject: Re: bug#78995: [PATCH] ;;;autoload-expand for special macros
Date: Fri, 01 Aug 2025 18:37:28 -0400
[Message part 1 (text/plain, inline)]
JD Smith <jdtsmith <at> gmail.com> writes:

Stefan, Eli, any comments on the documentation (or other) parts of this
patch?  Stefan, do you think the proposed TRAMP solution (add an `ignore'
`macro-declarations-alist' entry for `autoload-macro' for earlier versions of
emacs) makes sense?

[autoload-expand_6.patch (text/x-patch, inline)]
diff --git a/doc/lispref/functions.texi b/doc/lispref/functions.texi
index be3c1e78889..25a01d942b6 100644
--- a/doc/lispref/functions.texi
+++ b/doc/lispref/functions.texi
@@ -2633,6 +2633,11 @@ Declare Form
 This is typically used for macros, though it works for functions too.
 @xref{Indenting Macros}.
 
+@item (autoload-macro @var{value})
+This is used when defining a macro.  If @var{value} is @samp{expand},
+any calls to the macro which follow an autoload comment will first be
+expanded during generation of the autoloads.  @xref{Autoload}.
+
 @item (interactive-only @var{value})
 Set the function's @code{interactive-only} property to @var{value}.
 @xref{The interactive-only property}.
diff --git a/doc/lispref/loading.texi b/doc/lispref/loading.texi
index 750f6e76eff..65a55547a9f 100644
--- a/doc/lispref/loading.texi
+++ b/doc/lispref/loading.texi
@@ -710,8 +710,31 @@ Autoload
   If you write a function definition with an unusual macro that is not
 one of the known and recognized function definition methods, use of an
 ordinary magic autoload comment would copy the whole definition into
-@code{loaddefs.el}.  That is not desirable.  You can put the desired
-@code{autoload} call into @code{loaddefs.el} instead by writing this:
+@code{loaddefs.el}.  That is often not desirable.  In this case, you can
+use the special declare form @code{(autoload-macro expand)} in your
+macro definition (@pxref{Declare Form}).  This indicates to the autoload
+system that calls to your macro following @samp{;;;###autoload} should
+be expanded, similar to how the special functions listed above are
+handled.  For example, a macro which wraps @code{define-minor-mode} can
+request expansion, so that proper @code{autoload} calls for the function
+it defines are generated.
+
+The symbol @code{:autoload-end} can be used in the expansion to prevent
+including unwanted forms in the autoload output.  Its presence causes
+any further elements within the list where it appears to be silently
+skipped.
+
+Note that, if a symbol in the car of an autoloaded form is not defined
+during autoload generation, the file in which the associated
+@samp{;;;###autoload} appears will itself be loaded, to give the macro a
+chance to be defined.  Packages which use special loading mechanisms,
+including requiring their own @samp{foo-autoload.el} file, should
+therefore gracefully handle load errors, since these files may not yet
+exist during autoload generation.  This can be done, e.g., by setting
+the @var{no-error} argument of @code{require} non-@code{nil}).
+
+Alternatively, instead of expansion, you can put the desired
+@code{autoload} call into @code{loaddefs.el} by writing this:
 
 @example
 ;;;###autoload (autoload 'foo "myfile")
diff --git a/lisp/emacs-lisp/byte-run.el b/lisp/emacs-lisp/byte-run.el
index 366423904db..3e521e18567 100644
--- a/lisp/emacs-lisp/byte-run.el
+++ b/lisp/emacs-lisp/byte-run.el
@@ -271,6 +271,11 @@ 'byte-run--set-debug
 	    (list 'put (list 'quote name)
 		  ''edebug-form-spec (list 'quote spec)))))
 
+(defalias 'byte-run--set-autoload-macro
+  #'(lambda (name _args spec)
+      (list 'function-put (list 'quote name)
+	    ''autoload-macro (list 'quote spec))))
+
 (defalias 'byte-run--set-no-font-lock-keyword
   #'(lambda (name _args val)
       (list 'function-put (list 'quote name)
@@ -350,8 +355,10 @@ macro-declarations-alist
   (cons
    (list 'debug #'byte-run--set-debug)
    (cons
-    (list 'no-font-lock-keyword #'byte-run--set-no-font-lock-keyword)
-    defun-declarations-alist))
+    (list 'autoload-macro #'byte-run--set-autoload-macro)
+    (cons
+     (list 'no-font-lock-keyword #'byte-run--set-no-font-lock-keyword)
+     defun-declarations-alist)))
   "List associating properties of macros to their macro expansion.
 Each element of the list takes the form (PROP FUN) where FUN is a function.
 For each (PROP . VALUES) in a macro's declaration, the FUN corresponding
@@ -397,6 +404,7 @@ 'defmacro
            (if declarations
 	       (cons 'prog1 (cons def (car declarations)))
 	     def))))))
+(function-put 'defmacro 'autoload-macro 'expand) ; Since we cannot `declare' it
 
 ;; Now that we defined defmacro we can use it!
 (defmacro defun (name arglist &rest body)
@@ -409,7 +417,7 @@ defun
 The return value is undefined.
 
 \(fn NAME ARGLIST [DOCSTRING] [DECL] [INTERACTIVE] BODY...)"
-  (declare (doc-string 3) (indent 2))
+  (declare (doc-string 3) (indent 2) (autoload-macro expand))
   (or name (error "Cannot define '%s' as a function" name))
   (if (null
        (and (listp arglist)
diff --git a/lisp/emacs-lisp/cl-generic.el b/lisp/emacs-lisp/cl-generic.el
index 3aa26fba3c3..4a85d89d5fa 100644
--- a/lisp/emacs-lisp/cl-generic.el
+++ b/lisp/emacs-lisp/cl-generic.el
@@ -258,7 +258,8 @@ cl-defgeneric
                                cl--generic-edebug-make-name in:method]
                               lambda-doc
                               def-body)]]
-             def-body)))
+             def-body))
+           (autoload-macro expand))
   (let* ((doc (if (stringp (car-safe options-and-methods))
                   (pop options-and-methods)))
          (declarations nil)
diff --git a/lisp/emacs-lisp/cl-macs.el b/lisp/emacs-lisp/cl-macs.el
index 2a0a9e5c6de..1b64f106a1b 100644
--- a/lisp/emacs-lisp/cl-macs.el
+++ b/lisp/emacs-lisp/cl-macs.el
@@ -398,7 +398,8 @@ cl-defun
                      [&optional ("interactive" interactive)]
                      def-body))
            (doc-string 3)
-           (indent 2))
+           (indent 2)
+           (autoload-macro expand))
   `(defun ,name ,@(cl--transform-lambda (cons args body) name)))
 
 ;;;###autoload
@@ -416,7 +417,8 @@ cl-iter-defun
                      [&optional ("interactive" interactive)]
                      def-body))
            (doc-string 3)
-           (indent 2))
+           (indent 2)
+           (autoload-macro expand))
   (require 'generator)
   `(iter-defun ,name ,@(cl--transform-lambda (cons args body) name)))
 
@@ -475,7 +477,8 @@ cl-defmacro
   (declare (debug
             (&define name cl-macro-list cl-declarations-or-string def-body))
            (doc-string 3)
-           (indent 2))
+           (indent 2)
+           (autoload-macro expand))
   `(defmacro ,name ,@(cl--transform-lambda (cons args body) name)))
 
 (def-edebug-elem-spec 'cl-lambda-expr
@@ -3011,7 +3014,8 @@ cl-defstruct
                         sexp])]
              [&optional stringp]
              ;; All the above is for the following def-form.
-             &rest &or symbolp (symbolp &optional def-form &rest sexp))))
+             &rest &or symbolp (symbolp &optional def-form &rest sexp)))
+           (autoload-macro expand))
   (let* ((name (if (consp struct) (car struct) struct))
 	 (warning nil)
 	 (opts (cdr-safe struct))
diff --git a/lisp/emacs-lisp/easy-mmode.el b/lisp/emacs-lisp/easy-mmode.el
index f53db48f0b7..0e428abd0b7 100644
--- a/lisp/emacs-lisp/easy-mmode.el
+++ b/lisp/emacs-lisp/easy-mmode.el
@@ -222,10 +222,11 @@ define-minor-mode
            (indent defun)
            (debug (&define name string-or-null-p
 			   [&optional [&not keywordp] sexp
-			    &optional [&not keywordp] sexp
-			    &optional [&not keywordp] sexp]
+			              &optional [&not keywordp] sexp
+			              &optional [&not keywordp] sexp]
 			   [&rest [keywordp sexp]]
-			   def-body)))
+			   def-body))
+           (autoload-macro expand))
 
   (let* ((last-message (make-symbol "last-message"))
          (mode-name (symbol-name mode))
@@ -487,7 +488,7 @@ define-globalized-minor-mode
 on if the hook has explicitly disabled it.
 
 \(fn GLOBAL-MODE MODE TURN-ON [KEY VALUE]... BODY...)"
-  (declare (doc-string 2) (indent defun))
+  (declare (doc-string 2) (indent defun) (autoload-macro expand))
   (let* ((global-mode-name (symbol-name global-mode))
 	 (mode-name (symbol-name mode))
 	 (pretty-name (easy-mmode-pretty-mode-name mode))
diff --git a/lisp/emacs-lisp/generator.el b/lisp/emacs-lisp/generator.el
index 344e11e245e..59784ff51e8 100644
--- a/lisp/emacs-lisp/generator.el
+++ b/lisp/emacs-lisp/generator.el
@@ -675,7 +675,8 @@ iter-defun
 of values.  Callers can retrieve each value using `iter-next'."
   (declare (indent defun)
            (debug (&define name lambda-list lambda-doc &rest sexp))
-           (doc-string 3))
+           (doc-string 3)
+           (autoload-macro expand))
   (cl-assert lexical-binding)
   (let* ((parsed-body (macroexp-parse-body body))
          (declarations (car parsed-body))
diff --git a/lisp/emacs-lisp/inline.el b/lisp/emacs-lisp/inline.el
index c015e2b57d0..5acd6f17ee2 100644
--- a/lisp/emacs-lisp/inline.el
+++ b/lisp/emacs-lisp/inline.el
@@ -135,7 +135,7 @@ define-inline
 This is like `defmacro', but has several advantages.
 See Info node `(elisp)Defining Functions' for more details."
   ;; FIXME: How can this work with CL arglists?
-  (declare (indent defun) (debug defun) (doc-string 3))
+  (declare (indent defun) (debug defun) (doc-string 3) (autoload-macro expand))
   (let ((doc (if (stringp (car-safe body)) (list (pop body))))
         (declares (if (eq (car-safe (car-safe body)) 'declare) (pop body)))
         (cm-name (intern (format "%s--inliner" name)))
diff --git a/lisp/emacs-lisp/loaddefs-gen.el b/lisp/emacs-lisp/loaddefs-gen.el
index 0f136df1fe2..f9c6f82c31f 100644
--- a/lisp/emacs-lisp/loaddefs-gen.el
+++ b/lisp/emacs-lisp/loaddefs-gen.el
@@ -142,12 +142,29 @@ loaddefs-generate--shorten-autoload
              3)
         form))
 
+;; TODO: some macros can be removed from this list once they
+;;  (declare ((autoload-macro expand) ...)
+(defconst loaddefs--defining-macros
+  '(define-skeleton define-derived-mode
+     define-compilation-mode define-generic-mode
+     easy-mmode-define-global-mode define-global-minor-mode
+     define-globalized-minor-mode
+     easy-mmode-define-minor-mode define-minor-mode
+     cl-defun defun* cl-defmacro defmacro*
+     define-overloadable-function
+     transient-define-prefix transient-define-suffix
+     transient-define-infix transient-define-argument))
+
+(defvar loaddefs--load-error-files nil)
 (defun loaddefs-generate--make-autoload (form file &optional expansion)
   "Turn FORM into an autoload or defvar for source file FILE.
 Returns nil if FORM is not a special autoload form (i.e. a function definition
 or macro definition or a defcustom).
 If EXPANSION is non-nil, we're processing the macro expansion of an
-expression, in which case we want to handle forms differently."
+expression, in which case we want to handle forms differently.
+
+Note that macros can request expansion by including `(autoload-macro
+expand)' among their `declare' forms."
   (let ((car (car-safe form)) expand)
     (cond
      ((and expansion (eq car 'defalias))
@@ -191,35 +208,40 @@ loaddefs-generate--make-autoload
           (setq form (copy-sequence form))
           (setcdr (memq :autoload-end form) nil))
         (let ((exps (delq nil (mapcar (lambda (form)
-                                        (loaddefs-generate--make-autoload
-                                         form file expansion))
+                                        (unless (eq form :autoload-end)
+                                          (loaddefs-generate--make-autoload
+                                           form file expansion)))
                                       (cdr form)))))
           (when exps (cons 'progn exps)))))
 
-     ;; For complex cases, try again on the macro-expansion.
-     ((and (memq car '(easy-mmode-define-global-mode define-global-minor-mode
-                       define-globalized-minor-mode defun defmacro
-		       easy-mmode-define-minor-mode define-minor-mode
-                       define-inline cl-defun cl-defmacro cl-defgeneric
-                       cl-defstruct pcase-defmacro iter-defun cl-iter-defun))
-           (macrop car)
-	   (setq expand (let ((load-true-file-name file)
-                              (load-file-name file))
-                          (macroexpand form)))
-	   (memq (car expand) '(progn prog1 defalias)))
+     ;; For macros which request it, try again on their expansion.
+     ((progn
+        ;; If the car is an unknown symbol, we load the file first to
+        ;; give packages a chance to define their macros.
+        (unless (or (not (symbolp car)) (fboundp car)
+                    ;; Special cases handled below
+                    (memq car loaddefs--defining-macros)
+                    (memq car '(defclass defcustom deftheme defgroup nil))
+                    (assoc file load-history)
+                    (member file loaddefs--load-error-files))
+          (let ((load-path (cons (file-name-directory file) load-path)))
+            (message "loaddefs-gen: loading file %s (for %s)" file car)
+            (condition-case e (load file)
+              (error
+               (push file loaddefs--load-error-files) ; do not attempt again
+               (warn "loaddefs-gen: load error\n\t%s" e)))))
+        (and (macrop car)
+	     (eq 'expand (function-get car 'autoload-macro))
+	     (setq expand (let ((load-true-file-name file)
+				(load-file-name file))
+			    (macroexpand form)))
+	     (not (eq car (car expand)))))
       ;; Recurse on the expansion.
       (loaddefs-generate--make-autoload expand file 'expansion))
 
-     ;; For special function-like operators, use the `autoload' function.
-     ((memq car '(define-skeleton define-derived-mode
-                   define-compilation-mode define-generic-mode
-		   easy-mmode-define-global-mode define-global-minor-mode
-		   define-globalized-minor-mode
-		   easy-mmode-define-minor-mode define-minor-mode
-		   cl-defun defun* cl-defmacro defmacro*
-                   define-overloadable-function
-                   transient-define-prefix transient-define-suffix
-                   transient-define-infix transient-define-argument))
+     ;; For known special macros which define functions, use `autoload'
+     ;; directly.
+     ((memq car loaddefs--defining-macros)
       (let* ((macrop (memq car '(defmacro cl-defmacro defmacro*)))
 	     (name (nth 1 form))
 	     (args (pcase car
diff --git a/lisp/emacs-lisp/pcase.el b/lisp/emacs-lisp/pcase.el
index 73554fd66fd..ab8edf1f569 100644
--- a/lisp/emacs-lisp/pcase.el
+++ b/lisp/emacs-lisp/pcase.el
@@ -537,7 +537,7 @@ pcase-defmacro
 By convention, DOC should use \"EXPVAL\" to stand
 for the result of evaluating EXP (first arg to `pcase').
 \n(fn NAME ARGS [DOC] &rest BODY...)"
-  (declare (indent 2) (debug defun) (doc-string 3))
+  (declare (indent 2) (debug defun) (doc-string 3) (autoload-macro expand))
   ;; Add the function via `fsym', so that an autoload cookie placed
   ;; on a pcase-defmacro will cause the macro to be loaded on demand.
   (let ((fsym (intern (format "%s--pcase-macroexpander" name)))

Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78995; Package emacs. (Sat, 02 Aug 2025 06:53:02 GMT) Full text and rfc822 format available.

Message #131 received at 78995 <at> debbugs.gnu.org (full text, mbox):

From: Eli Zaretskii <eliz <at> gnu.org>
To: "J.D. Smith" <jdtsmith <at> gmail.com>
Cc: philipk <at> posteo.net, 78995 <at> debbugs.gnu.org, monnier <at> iro.umontreal.ca
Subject: Re: bug#78995: [PATCH] ;;;autoload-expand for special macros
Date: Sat, 02 Aug 2025 09:52:32 +0300
> From: "J.D. Smith" <jdtsmith <at> gmail.com>
> Date: Fri, 01 Aug 2025 18:37:28 -0400
> 
> JD Smith <jdtsmith <at> gmail.com> writes:
> 
> Stefan, Eli, any comments on the documentation (or other) parts of this
> patch?

Some, see below.

> --- a/doc/lispref/functions.texi
> +++ b/doc/lispref/functions.texi
> @@ -2633,6 +2633,11 @@ Declare Form
>  This is typically used for macros, though it works for functions too.
>  @xref{Indenting Macros}.
>  
> +@item (autoload-macro @var{value})
> +This is used when defining a macro.  If @var{value} is @samp{expand},
> +any calls to the macro which follow an autoload comment will first be
> +expanded during generation of the autoloads.  @xref{Autoload}.

This can benefit from an index entry.

> --- a/doc/lispref/loading.texi
> +++ b/doc/lispref/loading.texi
> @@ -710,8 +710,31 @@ Autoload
>    If you write a function definition with an unusual macro that is not
>  one of the known and recognized function definition methods, use of an
>  ordinary magic autoload comment would copy the whole definition into
> -@code{loaddefs.el}.  That is not desirable.  You can put the desired
> -@code{autoload} call into @code{loaddefs.el} instead by writing this:
> +@code{loaddefs.el}.  That is often not desirable.  In this case, you can
                                                      ^^^^^^^^^^^^
It is not clear what case is alluded here as "this case".  Suggest
instead to say something like "If you don't want the macro copied to
@file{loaddefs.el}, you can ..."  Or to make a simple sentence like
"If this is not desirable, you can ...".

Btw, please use @file{loaddefs.el}, as @code is wrong when referring
to files.

> +use the special declare form @code{(autoload-macro expand)} in your
> +macro definition (@pxref{Declare Form}).  This indicates to the autoload
> +system that calls to your macro following @samp{;;;###autoload} should
> +be expanded, similar to how the special functions listed above are
> +handled.  For example, a macro which wraps @code{define-minor-mode} can
> +request expansion, so that proper @code{autoload} calls for the function
> +it defines are generated.

This text left me wondering how this is different from not using
autoload-macro.  When you describe some measure to avoid an
undesirable outcome, please always be sure to say what will happen
under if that measure is taken, as opposed to when it isn't.  Here,
you say what autoload-macro does, but saying that the macro is
expanded doesn't help, because it is expanded even if autoload-macro
is not used (right?).

> +The symbol @code{:autoload-end} can be used in the expansion to prevent
> +including unwanted forms in the autoload output.  Its presence causes
> +any further elements within the list where it appears to be silently
> +skipped.

An index entry is missing here.  Also, the description is complex
enough to call for an example as a means to clarify it.

> +Note that, if a symbol in the car of an autoloaded form is not defined
                                 ^^^
"car" should be in @code.

> +during autoload generation, the file in which the associated
> +@samp{;;;###autoload} appears will itself be loaded, to give the macro a
> +chance to be defined.  Packages which use special loading mechanisms,
> +including requiring their own @samp{foo-autoload.el} file, should
> +therefore gracefully handle load errors, since these files may not yet
> +exist during autoload generation.  This can be done, e.g., by setting
> +the @var{no-error} argument of @code{require} non-@code{nil}).

Please add here a cross-reference to where 'require' is defined.

> --- a/lisp/emacs-lisp/byte-run.el
> +++ b/lisp/emacs-lisp/byte-run.el
> @@ -271,6 +271,11 @@ 'byte-run--set-debug
>  	    (list 'put (list 'quote name)
>  		  ''edebug-form-spec (list 'quote spec)))))
>  
> +(defalias 'byte-run--set-autoload-macro
> +  #'(lambda (name _args spec)
> +      (list 'function-put (list 'quote name)
> +	    ''autoload-macro (list 'quote spec))))

Can we have a comment here explaining the reason for the use of
autoload-macro?

>  (defalias 'byte-run--set-no-font-lock-keyword
>    #'(lambda (name _args val)
>        (list 'function-put (list 'quote name)
> @@ -350,8 +355,10 @@ macro-declarations-alist
>    (cons
>     (list 'debug #'byte-run--set-debug)
>     (cons
> -    (list 'no-font-lock-keyword #'byte-run--set-no-font-lock-keyword)
> -    defun-declarations-alist))
> +    (list 'autoload-macro #'byte-run--set-autoload-macro)

And maybe here as well?

> --- a/lisp/emacs-lisp/easy-mmode.el
> +++ b/lisp/emacs-lisp/easy-mmode.el
> @@ -222,10 +222,11 @@ define-minor-mode
>             (indent defun)
>             (debug (&define name string-or-null-p
>  			   [&optional [&not keywordp] sexp
> -			    &optional [&not keywordp] sexp
> -			    &optional [&not keywordp] sexp]
> +			              &optional [&not keywordp] sexp
> +			              &optional [&not keywordp] sexp]
>  			   [&rest [keywordp sexp]]
> -			   def-body)))
> +			   def-body))
> +           (autoload-macro expand))

And here.

> @@ -487,7 +488,7 @@ define-globalized-minor-mode
>  on if the hook has explicitly disabled it.
>  
>  \(fn GLOBAL-MODE MODE TURN-ON [KEY VALUE]... BODY...)"
> -  (declare (doc-string 2) (indent defun))
> +  (declare (doc-string 2) (indent defun) (autoload-macro expand))

And here.

> --- a/lisp/emacs-lisp/inline.el
> +++ b/lisp/emacs-lisp/inline.el
> @@ -135,7 +135,7 @@ define-inline
>  This is like `defmacro', but has several advantages.
>  See Info node `(elisp)Defining Functions' for more details."
>    ;; FIXME: How can this work with CL arglists?
> -  (declare (indent defun) (debug defun) (doc-string 3))
> +  (declare (indent defun) (debug defun) (doc-string 3) (autoload-macro expand))

And here.

> --- a/lisp/emacs-lisp/pcase.el
> +++ b/lisp/emacs-lisp/pcase.el
> @@ -537,7 +537,7 @@ pcase-defmacro
>  By convention, DOC should use \"EXPVAL\" to stand
>  for the result of evaluating EXP (first arg to `pcase').
>  \n(fn NAME ARGS [DOC] &rest BODY...)"
> -  (declare (indent 2) (debug defun) (doc-string 3))
> +  (declare (indent 2) (debug defun) (doc-string 3) (autoload-macro expand))

And here.

> --- a/lisp/emacs-lisp/loaddefs-gen.el
> +++ b/lisp/emacs-lisp/loaddefs-gen.el
> @@ -142,12 +142,29 @@ loaddefs-generate--shorten-autoload
>               3)
>          form))
>  
> +;; TODO: some macros can be removed from this list once they
> +;;  (declare ((autoload-macro expand) ...)
> +(defconst loaddefs--defining-macros
> +  '(define-skeleton define-derived-mode
> +     define-compilation-mode define-generic-mode
> +     easy-mmode-define-global-mode define-global-minor-mode
> +     define-globalized-minor-mode
> +     easy-mmode-define-minor-mode define-minor-mode
> +     cl-defun defun* cl-defmacro defmacro*
> +     define-overloadable-function
> +     transient-define-prefix transient-define-suffix
> +     transient-define-infix transient-define-argument))

Please explain in a comment which macros should appear the above list,
and why.

Thanks.




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78995; Package emacs. (Sat, 02 Aug 2025 17:21:02 GMT) Full text and rfc822 format available.

Message #134 received at 78995 <at> debbugs.gnu.org (full text, mbox):

From: Michael Albinus <michael.albinus <at> gmx.de>
To: "J.D. Smith" <jdtsmith <at> gmail.com>
Cc: 78995 <at> debbugs.gnu.org, Stefan Monnier <monnier <at> iro.umontreal.ca>
Subject: Re: bug#78995: [PATCH] ;;;autoload-expand for special macros
Date: Sat, 02 Aug 2025 19:20:00 +0200
"J.D. Smith" <jdtsmith <at> gmail.com> writes:

Hi,

> Hmm, I guess `loaddefs-gen' was introduced in emacs 29.  But I think you
> don't actually need that `require' at all.  Maybe try a simple:
>
>     (unless (alist-get 'autoload-macro macro-declarations-alist)
>       (push '(autoload-macro ignore) macro-declarations-alist))

That works with Emacs 28, if I put these lines before the
tramp--with-startup macro declaration.

I cannot test with the master branch, because the autoload-macro patch
doesn't seem to be there yet.

Best regards, Michael.




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78995; Package emacs. (Sun, 03 Aug 2025 18:17:02 GMT) Full text and rfc822 format available.

Message #137 received at 78995 <at> debbugs.gnu.org (full text, mbox):

From: "J.D. Smith" <jdtsmith <at> gmail.com>
To: Eli Zaretskii <eliz <at> gnu.org>
Cc: philipk <at> posteo.net, 78995 <at> debbugs.gnu.org, monnier <at> iro.umontreal.ca
Subject: Re: bug#78995: [PATCH] ;;;autoload-expand for special macros
Date: Sun, 03 Aug 2025 14:16:05 -0400
[Message part 1 (text/plain, inline)]
Eli Zaretskii <eliz <at> gnu.org> writes:
>  JD Smith <jdtsmith <at> gmail.com> writes:
>  
>  Stefan, Eli, any comments on the documentation (or other) parts of this
>  patch?
> 
>> Some, see below.

Thanks.

> Can we have a comment here explaining the reason for the use of
> autoload-macro?
> And maybe here as well?
> And here. x 4

I'm not sure what kind of comment you mean.  None of the other declare
forms are commented, either on definition or on use.  Are you thinking
of something simple, like "request macro-expansion during autoload
generation"?

Current patch attached.

[autoload-expand_7.patch (text/x-patch, attachment)]

Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78995; Package emacs. (Sun, 03 Aug 2025 18:19:01 GMT) Full text and rfc822 format available.

Message #140 received at 78995 <at> debbugs.gnu.org (full text, mbox):

From: "J.D. Smith" <jdtsmith <at> gmail.com>
To: Michael Albinus <michael.albinus <at> gmx.de>
Cc: 78995 <at> debbugs.gnu.org, Stefan Monnier <monnier <at> iro.umontreal.ca>
Subject: Re: bug#78995: [PATCH] ;;;autoload-expand for special macros
Date: Sun, 03 Aug 2025 14:18:22 -0400
[Message part 1 (text/plain, inline)]
Michael Albinus <michael.albinus <at> gmx.de> writes:

> "J.D. Smith" <jdtsmith <at> gmail.com> writes:
>
> Hi,
>
>> Hmm, I guess `loaddefs-gen' was introduced in emacs 29.  But I think you
>> don't actually need that `require' at all.  Maybe try a simple:
>>
>>     (unless (alist-get 'autoload-macro macro-declarations-alist)
>>       (push '(autoload-macro ignore) macro-declarations-alist))
>
> That works with Emacs 28, if I put these lines before the
> tramp--with-startup macro declaration.
>
> I cannot test with the master branch, because the autoload-macro patch
> doesn't seem to be there yet.

Great.  I will push it soon and then you can test, or feel free to try
this patch in the meantime.

Thanks.

[autoload-expand_7.patch (text/x-patch, attachment)]

Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78995; Package emacs. (Sun, 03 Aug 2025 19:04:01 GMT) Full text and rfc822 format available.

Message #143 received at 78995 <at> debbugs.gnu.org (full text, mbox):

From: Eli Zaretskii <eliz <at> gnu.org>
To: "J.D. Smith" <jdtsmith <at> gmail.com>
Cc: philipk <at> posteo.net, 78995 <at> debbugs.gnu.org, monnier <at> iro.umontreal.ca
Subject: Re: bug#78995: [PATCH] ;;;autoload-expand for special macros
Date: Sun, 03 Aug 2025 22:03:00 +0300
> From: "J.D. Smith" <jdtsmith <at> gmail.com>
> Cc: philipk <at> posteo.net,  78995 <at> debbugs.gnu.org,  monnier <at> iro.umontreal.ca
> Date: Sun, 03 Aug 2025 14:16:05 -0400
> 
> > Can we have a comment here explaining the reason for the use of
> > autoload-macro?
> > And maybe here as well?
> > And here. x 4
> 
> I'm not sure what kind of comment you mean.

To explain why do we use this declaration there.

> None of the other declare
> forms are commented, either on definition or on use.

This one is much more subtle than the others.

> Are you thinking of something simple, like "request macro-expansion
> during autoload generation"?

No, I mean _why_ we want to request that in those places and not the
others.




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78995; Package emacs. (Sun, 03 Aug 2025 22:54:02 GMT) Full text and rfc822 format available.

Message #146 received at 78995 <at> debbugs.gnu.org (full text, mbox):

From: "J.D. Smith" <jdtsmith <at> gmail.com>
To: Eli Zaretskii <eliz <at> gnu.org>
Cc: philipk <at> posteo.net, 78995 <at> debbugs.gnu.org, monnier <at> iro.umontreal.ca
Subject: Re: bug#78995: [PATCH] ;;;autoload-expand for special macros
Date: Sun, 03 Aug 2025 18:53:34 -0400
[Message part 1 (text/plain, inline)]
Eli Zaretskii <eliz <at> gnu.org> writes:

>> From: "J.D. Smith" <jdtsmith <at> gmail.com>
>> Cc: philipk <at> posteo.net,  78995 <at> debbugs.gnu.org,  monnier <at> iro.umontreal.ca
>> Date: Sun, 03 Aug 2025 14:16:05 -0400
>> 
>> > Can we have a comment here explaining the reason for the use of
>> > autoload-macro?
>> > And maybe here as well?
>> > And here. x 4
>> 
>> I'm not sure what kind of comment you mean.
>
> To explain why do we use this declaration there.
>
>> Are you thinking of something simple, like "request macro-expansion
>> during autoload generation"?
>
> No, I mean _why_ we want to request that in those places and not the
> others.

The short but unsatisfying answer is to preserve the hard-coded list of
macros to expand, which this functionality replaces and extends.  The
former explanation in `loaddefs-generate--make-autoload' was quite
terse:

 ;; For complex cases, try again on the macro-expansion.

I've tried to inject a short explanation everywhere this declaration is
used.  I left the `byte-run--set-autoload-macro' alone, since that's
just a generic property setter, and values other than `expand' may be
used in the future. Latest patch below.

Meta-comments:
==============

Though outside of the scope of this patch, a few mildly bothersome
attributes remain, which I leave here for posterity.

1. It's somewhat arbitrary which macros request expansion

Eventually, I think for all builtin macros, the question should be
asked: "Will calls to this macro likely be marked ;;;###autoload"?  If
the answer is yes, the macro should declare `autoload-macro=expand', so
that these calls get recursively expanded down to their most basic forms
— `defalias', `put', and so on.

2. Some autoloaded macro expansions are not "autoload-hygienic".

Some macros currently /rely/ on skipping directly to `(autoload name
...)' generation via the hard-coded "short-cut" list (see
`loaddefs--defining-macros').  I.e. they do not expect to be expanded,
and are therefore not autoload-hygenic in their expansion
(e.g. neglecting to use `:autoload-end' to elide unwanted forms, for
example).  This is confusing and prone to bugs (e.g. the bug discovered
in this thread related to the MODES arg).

3. Some macros' autoload treatment depend on whether they are defined at
autoload-generation time.

Such macros are both on the short-cut list /and/ request expansion.  So
they are expanded, but only if they are defined at the time autoload
generation occurs.  Most are, but some, e.g. cl-macs, are not.  So they
go through the "short-cut" instead.

IMO, these macros should either have their expansion cleaned up for
autoload hygiene (if necessary) and be pre-loaded during autoload
generation, or they should just not request expansion at all.

[autoload-expand_8.patch (text/x-patch, attachment)]

Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78995; Package emacs. (Sun, 03 Aug 2025 23:18:02 GMT) Full text and rfc822 format available.

Message #149 received at 78995 <at> debbugs.gnu.org (full text, mbox):

From: Stefan Monnier <monnier <at> iro.umontreal.ca>
To: "J.D. Smith" <jdtsmith <at> gmail.com>
Cc: Eli Zaretskii <eliz <at> gnu.org>, 78995 <at> debbugs.gnu.org, philipk <at> posteo.net
Subject: Re: bug#78995: [PATCH] ;;;autoload-expand for special macros
Date: Sun, 03 Aug 2025 19:17:12 -0400
> The short but unsatisfying answer is to preserve the hard-coded list
> of macros to expand, which this functionality replaces and extends.
> The former explanation in `loaddefs-generate--make-autoload' was quite
> terse:
>
>  ;; For complex cases, try again on the macro-expansion.

The reason is always that calls to these macros don't want to be
*preloaded* but only to be *autoloaded*.  By expanding the macro,
`autoload.el` (aka `loaddefs-gen.el`) gets to see the underlying
`defalias` and friends necessary to figure out *how* to autoload it.

In practice this means it's used for macros which define functions (or
macros).

> I've tried to inject a short explanation everywhere this declaration
> is used.  I left the `byte-run--set-autoload-macro' alone, since
> that's just a generic property setter, and values other than `expand'
> may be used in the future. Latest patch below.
>
> Meta-comments:
> ==============
>
> Though outside of the scope of this patch, a few mildly bothersome
> attributes remain, which I leave here for posterity.
>
> 1. It's somewhat arbitrary which macros request expansion
>
> Eventually, I think for all builtin macros, the question should be
> asked: "Will calls to this macro likely be marked ;;;###autoload"?
> If the answer is yes, the macro should declare
> `autoload-macro=expand', so that these calls get recursively expanded
> down to their most basic forms — `defalias', `put', and so on.

It's a judgment call: will it be more common to *preload* or to
*autoload*?

> 2. Some autoloaded macro expansions are not "autoload-hygienic".
> 3. Some macros' autoload treatment depend on whether they are defined
> at autoload-generation time.

I hope your patch will help us fix those issues.


        Stefan





Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78995; Package emacs. (Mon, 04 Aug 2025 12:53:02 GMT) Full text and rfc822 format available.

Message #152 received at 78995 <at> debbugs.gnu.org (full text, mbox):

From: Eli Zaretskii <eliz <at> gnu.org>
To: "J.D. Smith" <jdtsmith <at> gmail.com>
Cc: philipk <at> posteo.net, 78995 <at> debbugs.gnu.org, monnier <at> iro.umontreal.ca
Subject: Re: bug#78995: [PATCH] ;;;autoload-expand for special macros
Date: Mon, 04 Aug 2025 15:51:47 +0300
> From: "J.D. Smith" <jdtsmith <at> gmail.com>
> Cc: philipk <at> posteo.net,  78995 <at> debbugs.gnu.org,  monnier <at> iro.umontreal.ca
> Date: Sun, 03 Aug 2025 18:53:34 -0400
> 
> > No, I mean _why_ we want to request that in those places and not the
> > others.
> 
> The short but unsatisfying answer is to preserve the hard-coded list of
> macros to expand, which this functionality replaces and extends.  The
> former explanation in `loaddefs-generate--make-autoload' was quite
> terse:
> 
>  ;; For complex cases, try again on the macro-expansion.
> 
> I've tried to inject a short explanation everywhere this declaration is
> used.  I left the `byte-run--set-autoload-macro' alone, since that's
> just a generic property setter, and values other than `expand' may be
> used in the future. Latest patch below.

This is much better (thanks!), but I think we need to improve it some
more by saying in the manual that this declaration is an alternative
to hard-coding macros in loaddefs--defining-macros in loaddefs-gen.el.

> +the final form (@code{(put my-mode 'hidden-prop nil)}) will not be

Long forms like the above should be wrapped in @w{..}, to prevent them
from being broken between two lines.

> +copied into the autoload file.

"autoloads file", I guess?

> +Note that, if a symbol in the @code{car} of an autoloaded form is found
> +to be undefined during autoload generation, the file in which the
> +associated @samp{;;;###autoload} appears will itself be loaded, to give
> +the macro a chance to be defined.  Packages which use special loading
> +mechanisms, including loading their own @samp{foo-autoload.el} file,

"foo" should be in @var, since it isn't a literal "foo".  I'd even use
@file{@var{package}-loaddefs.el} instead (note the use of @file).

> +;; The following macros are known to define functions, and are treated
> +;; specially when encountered during autoload generation, translating
> +;; calls to them into appropriate (autoload function ...) forms.
> +;; TODO: some macros can be removed from this list once they
> +;;  (declare ((autoload-macro expand) ...)

I'd prefer to say explicitly that autoload-macro is the alternative
used so as to keep this list as short as possible.

Thanks.




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78995; Package emacs. (Mon, 04 Aug 2025 15:22:01 GMT) Full text and rfc822 format available.

Message #155 received at 78995 <at> debbugs.gnu.org (full text, mbox):

From: "J.D. Smith" <jdtsmith <at> gmail.com>
To: Eli Zaretskii <eliz <at> gnu.org>
Cc: philipk <at> posteo.net, 78995 <at> debbugs.gnu.org, monnier <at> iro.umontreal.ca
Subject: Re: bug#78995: [PATCH] ;;;autoload-expand for special macros
Date: Mon, 04 Aug 2025 11:21:39 -0400
[Message part 1 (text/plain, inline)]
Eli Zaretskii <eliz <at> gnu.org> writes:

>> From: "J.D. Smith" <jdtsmith <at> gmail.com>
>> Cc: philipk <at> posteo.net,  78995 <at> debbugs.gnu.org,  monnier <at> iro.umontreal.ca
>> Date: Sun, 03 Aug 2025 18:53:34 -0400
>> 
>> > No, I mean _why_ we want to request that in those places and not the
>> > others.
>> 
>> The short but unsatisfying answer is to preserve the hard-coded list of
>> macros to expand, which this functionality replaces and extends.  The
>> former explanation in `loaddefs-generate--make-autoload' was quite
>> terse:
>> 
>>  ;; For complex cases, try again on the macro-expansion.
>> 
>> I've tried to inject a short explanation everywhere this declaration is
>> used.  I left the `byte-run--set-autoload-macro' alone, since that's
>> just a generic property setter, and values other than `expand' may be
>> used in the future. Latest patch below.
>
> This is much better (thanks!), but I think we need to improve it some
> more by saying in the manual that this declaration is an alternative
> to hard-coding macros in loaddefs--defining-macros in loaddefs-gen.el.

OK, I have implemented these doc suggestions and a few other minor
improvements in the attached.  I've also tried to make a somewhat
unclear situation w.r.t. the hard-coded macro lists more clear in the
comments.

`loaddefs--defining-macros' is the "shortcut" list for turning a
function-defining macro directly into an (autoload ..) form, whereas
(autoload-macro expand) replaced a /different/ list of macros: those to
be expanded.  So there where 2 main hard-coded lists, and now there is
1.  The lists are closely related, because usually a macro expands into
one or more of the shortcut forms.

I conjecture (but have not verified), that ALL hard-coded lists of
macros can eventually be removed, save some very basic primitives like
defalias (and defmacro?).  Whether that's desirable is less clear.

[autoload-expand_9.patch (text/x-patch, attachment)]

Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78995; Package emacs. (Tue, 05 Aug 2025 07:13:02 GMT) Full text and rfc822 format available.

Message #158 received at 78995 <at> debbugs.gnu.org (full text, mbox):

From: Michael Albinus <michael.albinus <at> gmx.de>
To: "J.D. Smith" <jdtsmith <at> gmail.com>
Cc: Eli Zaretskii <eliz <at> gnu.org>, 78995 <at> debbugs.gnu.org, philipk <at> posteo.net,
 monnier <at> iro.umontreal.ca
Subject: Re: bug#78995: [PATCH] ;;;autoload-expand for special macros
Date: Tue, 05 Aug 2025 09:12:42 +0200
"J.D. Smith" <jdtsmith <at> gmail.com> writes:

Hi,

> OK, I have implemented these doc suggestions and a few other minor
> improvements in the attached.  I've also tried to make a somewhat
> unclear situation w.r.t. the hard-coded macro lists more clear in the
> comments.

Pls don't forget the Tramp change in your patch.

Best regards, Michael.




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78995; Package emacs. (Tue, 05 Aug 2025 13:14:02 GMT) Full text and rfc822 format available.

Message #161 received at 78995 <at> debbugs.gnu.org (full text, mbox):

From: "J.D. Smith" <jdtsmith <at> gmail.com>
To: Michael Albinus <michael.albinus <at> gmx.de>
Cc: Eli Zaretskii <eliz <at> gnu.org>, 78995 <at> debbugs.gnu.org, philipk <at> posteo.net,
 monnier <at> iro.umontreal.ca
Subject: Re: bug#78995: [PATCH] ;;;autoload-expand for special macros
Date: Tue, 05 Aug 2025 09:13:37 -0400
Michael Albinus <michael.albinus <at> gmx.de> writes:

>
> Pls don't forget the Tramp change in your patch.

There are definitely builtin packages that can/should be updated as a
result of this new functionality, e.g. transient.  But I don't think
those changes should be part of this patch, because it's sensible to get
the basic capability in place for people to test before adapting other
packages.

That said, TRAMP may be a special case because of the "chicken-and-egg"
problem represented by tramp-loaddefs.el, and the error generated by
attempting to load that file before it exists.  For now just setting
NOERROR when requiring tramp-loaddefs might be the right approach.

Stefan, what do you think a good approach is for packages which want to
start declaring autoload-macro expand in some of their macros, but
/also/ want to support earlier versions of emacs?  I can't think of an
approach other than each such package including:

   (unless (alist-get 'autoload-macro macro-declarations-alist)
      (push '(autoload-macro ignore) macro-declarations-alist))

somewhere.




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78995; Package emacs. (Sun, 10 Aug 2025 21:24:02 GMT) Full text and rfc822 format available.

Message #164 received at 78995 <at> debbugs.gnu.org (full text, mbox):

From: "J.D. Smith" <jdtsmith <at> gmail.com>
To: Stefan Monnier <monnier <at> iro.umontreal.ca>
Cc: Eli Zaretskii <eliz <at> gnu.org>, 78995 <at> debbugs.gnu.org, philipk <at> posteo.net
Subject: Re: bug#78995: [PATCH] ;;;autoload-expand for special macros
Date: Sun, 10 Aug 2025 17:23:29 -0400
Stefan Monnier <monnier <at> iro.umontreal.ca> writes:

>> 1. It's somewhat arbitrary which macros request expansion
>>
>> Eventually, I think for all builtin macros, the question should be
>> asked: "Will calls to this macro likely be marked ;;;###autoload"?
>> If the answer is yes, the macro should declare
>> `autoload-macro=expand', so that these calls get recursively expanded
>> down to their most basic forms — `defalias', `put', and so on.
>
> It's a judgment call: will it be more common to *preload* or to
> *autoload*?

I suppose an argument for preloading a macro's definition and copying in
;;;###autoload calls to it is if it 1) is very long and involved and
cannot be reduced to a small number of expanded forms, and 2) is
autoloaded many times, thus bloating the autoload file.

The only other scenario I can imagine is if it relies on information
that is not yet known at compile time, but which is known reliably at
load time (network address on emacs start?).  But I'm not aware of any
such builtin macros.  What other preload uses am I missing?

Unless there are any more thoughts on this patch I'll give it a last
look over and apply to master.  I'll patch TRAMP in a separate commit.




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78995; Package emacs. (Sun, 10 Aug 2025 21:42:02 GMT) Full text and rfc822 format available.

Message #167 received at 78995 <at> debbugs.gnu.org (full text, mbox):

From: "J.D. Smith" <jdtsmith <at> gmail.com>
To: Michael Albinus <michael.albinus <at> gmx.de>
Cc: 78995 <at> debbugs.gnu.org, Stefan Monnier <monnier <at> iro.umontreal.ca>
Subject: Re: bug#78995: [PATCH] ;;;autoload-expand for special macros
Date: Sun, 10 Aug 2025 17:41:37 -0400
[Message part 1 (text/plain, inline)]
"J.D. Smith" <jdtsmith <at> gmail.com> writes:

> Michael Albinus <michael.albinus <at> gmx.de> writes:
>
>> "J.D. Smith" <jdtsmith <at> gmail.com> writes:
>>
>> Hi,
>>
>>> Hmm, I guess `loaddefs-gen' was introduced in emacs 29.  But I think you
>>> don't actually need that `require' at all.  Maybe try a simple:
>>>
>>>     (unless (alist-get 'autoload-macro macro-declarations-alist)
>>>       (push '(autoload-macro ignore) macro-declarations-alist))
>>
>> That works with Emacs 28, if I put these lines before the
>> tramp--with-startup macro declaration.
>>
>> I cannot test with the master branch, because the autoload-macro patch
>> doesn't seem to be there yet.
>
> Great.  I will push it soon and then you can test, or feel free to try
> this patch in the meantime.

Here's an updated patch to try with TRAMP, to see if it works as
expected in both old and new Emacs versions.  Note that there are many
places where TRAMP does something more advanced, like:

  ;;;###tramp-autoload
  (when (featurep 'dbusbind)
    (tramp--with-startup
     (dolist (method tramp-gvfs-methods)
     ...

so I think you'll need to keep autoloading the macro definition too.

[tramp-autoload-macro-expand.patch (text/x-patch, attachment)]

Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78995; Package emacs. (Sun, 17 Aug 2025 09:51:01 GMT) Full text and rfc822 format available.

Message #170 received at 78995 <at> debbugs.gnu.org (full text, mbox):

From: Michael Albinus <michael.albinus <at> gmx.de>
To: "J.D. Smith" <jdtsmith <at> gmail.com>
Cc: 78995 <at> debbugs.gnu.org, Stefan Monnier <monnier <at> iro.umontreal.ca>
Subject: Re: bug#78995: [PATCH] ;;;autoload-expand for special macros
Date: Sun, 17 Aug 2025 11:50:10 +0200
"J.D. Smith" <jdtsmith <at> gmail.com> writes:

Hi,

> Here's an updated patch to try with TRAMP, to see if it works as
> expected in both old and new Emacs versions.  Note that there are many
> places where TRAMP does something more advanced, like:
>
>   ;;;###tramp-autoload
>   (when (featurep 'dbusbind)
>     (tramp--with-startup
>      (dolist (method tramp-gvfs-methods)
>      ...
>
> so I think you'll need to keep autoloading the macro definition too.

I've checked it with both Emacs 28 and 31, and it still works w/o
problems. So pls push it to master.

Best regards, Michael.




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78995; Package emacs. (Sun, 17 Aug 2025 15:22:01 GMT) Full text and rfc822 format available.

Message #173 received at 78995 <at> debbugs.gnu.org (full text, mbox):

From: "J.D. Smith" <jdtsmith <at> gmail.com>
To: Michael Albinus <michael.albinus <at> gmx.de>
Cc: 78995 <at> debbugs.gnu.org, Stefan Monnier <monnier <at> iro.umontreal.ca>
Subject: Re: bug#78995: [PATCH] ;;;autoload-expand for special macros
Date: Sun, 17 Aug 2025 11:21:48 -0400
Michael Albinus <michael.albinus <at> gmx.de> writes:

> "J.D. Smith" <jdtsmith <at> gmail.com> writes:
>
> Hi,
>
>> Here's an updated patch to try with TRAMP, to see if it works as
>> expected in both old and new Emacs versions.  Note that there are many
>> places where TRAMP does something more advanced, like:
>>
>>   ;;;###tramp-autoload
>>   (when (featurep 'dbusbind)
>>     (tramp--with-startup
>>      (dolist (method tramp-gvfs-methods)
>>      ...
>>
>> so I think you'll need to keep autoloading the macro definition too.
>
> I've checked it with both Emacs 28 and 31, and it still works w/o
> problems. So pls push it to master.

Great, thanks.  Done, and closing.




bug marked as fixed in version 31, send any further explanations to 78995 <at> debbugs.gnu.org and JD Smith <jdtsmith <at> gmail.com> Request was from "J.D. Smith" <jdtsmith <at> gmail.com> to control <at> debbugs.gnu.org. (Sun, 17 Aug 2025 15:23:01 GMT) Full text and rfc822 format available.

Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78995; Package emacs. (Wed, 20 Aug 2025 11:19:01 GMT) Full text and rfc822 format available.

Message #178 received at 78995 <at> debbugs.gnu.org (full text, mbox):

From: Stefan Monnier <monnier <at> iro.umontreal.ca>
To: "J.D. Smith" <jdtsmith <at> gmail.com>
Cc: 78995 <at> debbugs.gnu.org
Subject: Changes to `loaddefs.el` for define-minor-mode
Date: Wed, 20 Aug 2025 07:17:45 -0400
AFAICT, the new code seems to change the contents of `loaddefs.el` for
`define-minor-mode`, e.g.:

    % grep '(.*global-auto-revert-mode' **/*defs*.el
    lisp/ldefs-boot.el:(defvar global-auto-revert-mode nil "\
    lisp/ldefs-boot.el:(custom-autoload 'global-auto-revert-mode "autorevert" nil)
    lisp/ldefs-boot.el:(autoload 'global-auto-revert-mode "autorevert" "\
    lisp/ldefs-boot.el:evaluate `(default-value \\='global-auto-revert-mode)'.
    lisp/loaddefs.el:(autoload 'global-auto-revert-mode "autorevert" "\
    % 

As you can see the `global-auto-revert-mode` variable ends up
not preloaded.  I'm generally opposed to preloading variables, but the
change introduces a backward incompatibility with packages which presume
they can take the value of `global-auto-revert-mode` without resorting
to any `boundp` check, such as Magit.

So I suggest the patch below,


        Stefan


diff --git a/lisp/emacs-lisp/loaddefs-gen.el b/lisp/emacs-lisp/loaddefs-gen.el
index 9e91a11204d..e0b3859136c 100644
--- a/lisp/emacs-lisp/loaddefs-gen.el
+++ b/lisp/emacs-lisp/loaddefs-gen.el
@@ -155,7 +155,7 @@ loaddefs-generate--shorten-autoload
 ;; employing :autoload-end to omit unneeded forms).
 (defconst loaddefs--defining-macros
   '( define-skeleton define-derived-mode define-compilation-mode
-     define-generic-mode define-globalized-minor-mode define-minor-mode
+     define-generic-mode define-globalized-minor-mode
      cl-defun defun* cl-defmacro defmacro* define-overloadable-function
      transient-define-prefix transient-define-suffix transient-define-infix
      transient-define-argument transient-define-group





Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78995; Package emacs. (Wed, 20 Aug 2025 14:20:02 GMT) Full text and rfc822 format available.

Message #181 received at 78995 <at> debbugs.gnu.org (full text, mbox):

From: "J.D. Smith" <jdtsmith <at> gmail.com>
To: Stefan Monnier <monnier <at> iro.umontreal.ca>
Cc: 78995 <at> debbugs.gnu.org
Subject: Re: bug#78995: [PATCH] ;;;autoload-expand for special macros
Date: Wed, 20 Aug 2025 10:19:33 -0400
Stefan Monnier <monnier <at> iro.umontreal.ca> writes:

> AFAICT, the new code seems to change the contents of `loaddefs.el` for
> `define-minor-mode`, e.g.:
>
>     % grep '(.*global-auto-revert-mode' **/*defs*.el
>     lisp/ldefs-boot.el:(defvar global-auto-revert-mode nil "\
>     lisp/ldefs-boot.el:(custom-autoload 'global-auto-revert-mode "autorevert" nil)
>     lisp/ldefs-boot.el:(autoload 'global-auto-revert-mode "autorevert" "\
>     lisp/ldefs-boot.el:evaluate `(default-value \\='global-auto-revert-mode)'.
>     lisp/loaddefs.el:(autoload 'global-auto-revert-mode "autorevert" "\
>     % 
>
> As you can see the `global-auto-revert-mode` variable ends up
> not preloaded.  I'm generally opposed to preloading variables, but the
> change introduces a backward incompatibility with packages which presume
> they can take the value of `global-auto-revert-mode` without resorting
> to any `boundp` check, such as Magit.

I don't see this:

    % grep '(.*global-auto-revert-mode' **/*defs*.el
    ldefs-boot.el:(defvar global-auto-revert-mode nil "\
    ldefs-boot.el:(custom-autoload 'global-auto-revert-mode "autorevert" nil)
    ldefs-boot.el:(autoload 'global-auto-revert-mode "autorevert" "\
    ldefs-boot.el:evaluate `(default-value \\='global-auto-revert-mode)'.
    loaddefs_old.el:(defvar global-auto-revert-mode nil "\
    loaddefs_old.el:(custom-autoload 'global-auto-revert-mode "autorevert" nil)
    loaddefs_old.el:(autoload 'global-auto-revert-mode "autorevert" "\
    loaddefs_old.el:evaluate `(default-value \\='global-auto-revert-mode)'.
    loaddefs.el:(defvar global-auto-revert-mode nil "\
    loaddefs.el:(custom-autoload 'global-auto-revert-mode "autorevert" nil)
    loaddefs.el:(autoload 'global-auto-revert-mode "autorevert" "\
    loaddefs.el:evaluate `(default-value \\='global-auto-revert-mode)'.

(N.B.: `loaddefs_old.el' was a backup taken prior to the improvements we
made here.)

To me, this looks like you don't have autoload-macro declarations
exposed while building loaddefs (recall this used to be a hard-coded
list), so the `define-minor-mode' does not get expanded correctly.

What I'd expect/hope is that `define-minor-mode' is already defined via
autoload when autoload generation occurs, and has declared itself
`(autoload-macro expand)`, in `loaddefs.el'.

If you `make bootstrap', do you see:

    % grep '(.*define-minor-mode.*autoload-macro' **/*defs*.el 
    lisp/loaddefs.el:(function-put 'define-minor-mode 'autoload-macro 'expand)

This is essential, because the emacs which is used to generate
loaddefs.el incorporates this file (right? see below).

Summarizing, during generation of loaddefs.el, we need either:

1. easy-mmode to have been actually loaded, so its macros are properly
   defined along with their declarations, or

2. the autoload file used in the version of emacs which is building the
   autoload file to contain autoload-macro expand.

Chicken-and-eggy again, though it does work for me.  I just don't have a
clear enough picture of the build sequence.  Questions I have:

1. What does `ldefs-boot.el' do?  Is it just a "backup" of
   `loaddefs.el', or is it ever actually loaded?

2. Which version of emacs is used to generate loaddefs.el?  I think the
   "final version" is.

3. Is loaddefs.el compiled into the version of emacs that generates
   loaddefs.el?

3. If so, how is that circular dependency broken?  Iteration? Is that
   what `ldefs-boot' is about.

4. Is there a list somewhere of packages that are always explicitly
   loaded for every emacs?  Is easy-mmode on that list?

JD

>
> So I suggest the patch below,
>
>
>         Stefan
>
>
> diff --git a/lisp/emacs-lisp/loaddefs-gen.el b/lisp/emacs-lisp/loaddefs-gen.el
> index 9e91a11204d..e0b3859136c 100644
> --- a/lisp/emacs-lisp/loaddefs-gen.el
> +++ b/lisp/emacs-lisp/loaddefs-gen.el
> @@ -155,7 +155,7 @@ loaddefs-generate--shorten-autoload
>  ;; employing :autoload-end to omit unneeded forms).
>  (defconst loaddefs--defining-macros
>    '( define-skeleton define-derived-mode define-compilation-mode
> -     define-generic-mode define-globalized-minor-mode define-minor-mode
> +     define-generic-mode define-globalized-minor-mode
>       cl-defun defun* cl-defmacro defmacro* define-overloadable-function
>       transient-define-prefix transient-define-suffix transient-define-infix
>       transient-define-argument transient-define-group




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78995; Package emacs. (Wed, 20 Aug 2025 16:25:02 GMT) Full text and rfc822 format available.

Message #184 received at 78995 <at> debbugs.gnu.org (full text, mbox):

From: Stefan Monnier <monnier <at> iro.umontreal.ca>
To: "J.D. Smith" <jdtsmith <at> gmail.com>
Cc: 78995 <at> debbugs.gnu.org
Subject: Re: bug#78995: [PATCH] ;;;autoload-expand for special macros
Date: Wed, 20 Aug 2025 12:24:39 -0400
> I don't see this:

Hmm... I'll have to investigate further, then.
Might be some issue on my side.


        Stefan





Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78995; Package emacs. (Fri, 22 Aug 2025 14:46:01 GMT) Full text and rfc822 format available.

Message #187 received at 78995 <at> debbugs.gnu.org (full text, mbox):

From: "J.D. Smith" <jdtsmith <at> gmail.com>
To: Stefan Monnier <monnier <at> iro.umontreal.ca>
Cc: 78995 <at> debbugs.gnu.org
Subject: Re: bug#78995: [PATCH] ;;;autoload-expand for special macros
Date: Fri, 22 Aug 2025 10:44:57 -0400
Stefan Monnier <monnier <at> iro.umontreal.ca> writes:

>> I don't see this:
>
> Hmm... I'll have to investigate further, then.
> Might be some issue on my side.

Did the problem go away with a `make bootstrap'?  I'd feel more
confident if I understood better how the Emacs which produces
loaddefs.el itself includes autoloads.




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78995; Package emacs. (Sat, 23 Aug 2025 06:45:02 GMT) Full text and rfc822 format available.

Message #190 received at 78995 <at> debbugs.gnu.org (full text, mbox):

From: Stefan Monnier <monnier <at> iro.umontreal.ca>
To: "J.D. Smith" <jdtsmith <at> gmail.com>
Cc: 78995 <at> debbugs.gnu.org
Subject: Re: bug#78995: [PATCH] ;;;autoload-expand for special macros
Date: Sat, 23 Aug 2025 02:44:19 -0400
>> Hmm... I'll have to investigate further, then.
>> Might be some issue on my side.
> Did the problem go away with a `make bootstrap'?

Yup.  And I wasn't able to reproduce the problem afterwards, so I don't
know where it came from.

> I'd feel more confident if I understood better how the Emacs which
> produces loaddefs.el itself includes autoloads.

🙂


        Stefan





This bug report was last modified 27 days ago.

Previous Next


GNU bug tracking system
Copyright (C) 1999 Darren O. Benham, 1997,2003 nCipher Corporation Ltd, 1994-97 Ian Jackson.