Subject: bug#78637: 30.1.90; Calling setopt during init loads cus-start over and over

From: Stefan Monnier <[email-masked]>
Date: Sat, 31 May 2025 14:04:39 -0400

>> I believe this can be fixed with the following patch.  On my machine,
>> this patch reduces the runtime of the original init file to 75ms and
>> causes the prepended code to make no difference to the runtime.
>> 
>> diff --git a/lisp/cus-start.el b/lisp/cus-start.el
>> index 91cc6e22152..e82e97e87ca 100644
>> --- a/lisp/cus-start.el
>> +++ b/lisp/cus-start.el
>> @@ -934,7 +934,7 @@ minibuffer-prompt-properties--setter
>>        ;; This is used by describe-variable.
>>        (if version (put symbol 'custom-version version))
>>        ;; Don't re-add to custom-delayed-init-variables post-startup.
>> -      (unless after-init-time
>> +      (when (listp custom-delayed-init-variables)
>>  	;; Note this is the _only_ initialize property we handle.
>>  	(if (eq (cadr (memq :initialize rest)) #'custom-initialize-delay)
>>  	    ;; These vars are defined early and should hence be initialized

I'm sorry I was dense, but yes it looks like you found the culprit.

> I think this patch changes behavior, so it is not TRT.  But before we
> discuss how to fix the problem, let's be sure we understand the
> problem and its reason(s).

I think the patch below is a cleaner version of the patch above and
I think it does do TRT: `custom-delayed-init-variables` is used only at
early startup to force re-evaluation of some of the preloaded (a.k.a
dumped) variables; after that it should simply not be used and adding
entries to it is pointless.

I think this problem comes originally from my lack of understanding when
I added that `custom-delayed-init-variables` thingy here: if I had
understood what the `(unless purify-flag` was doing there I would have
used that test right from the start instead of `after-init-time`.

startup.el sets `custom-delayed-init-variables` to t after using it, so
as to try and catch cases where we mistakenly register vars on this list
"too late".  The `after-init-time` avoided the problem only as long as
`cus-start` was loaded late enough.

        Stefan

diff --git a/lisp/cus-start.el b/lisp/cus-start.el
index 09364b68e11..7e07e055015 100644
--- a/lisp/cus-start.el
+++ b/lisp/cus-start.el
@@ -946,19 +946,18 @@ minibuffer-prompt-properties--setter
 	  (put symbol 'custom-set (cadr prop)))
       ;; This is used by describe-variable.
       (if version (put symbol 'custom-version version))
-      ;; Don't re-add to custom-delayed-init-variables post-startup.
-      (unless after-init-time
-	;; Note this is the _only_ initialize property we handle.
-	(if (eq (cadr (memq :initialize rest)) #'custom-initialize-delay)
-	    ;; These vars are defined early and should hence be initialized
-	    ;; early, even if this file happens to be loaded late.  so add them
-	    ;; to the end of custom-delayed-init-variables.  Otherwise,
-	    ;; auto-save-file-name-transforms will appear in customize-rogue.
-	    (add-to-list 'custom-delayed-init-variables symbol 'append)))
       ;; If this is NOT while dumping Emacs, set up the rest of the
       ;; customization info.  This is the stuff that is not needed
       ;; until someone does M-x customize etc.
-      (unless dump-mode
+      (if dump-mode
+	  ;; Don't re-add to custom-delayed-init-variables post-startup.
+	  ;; Note this is the _only_ initialize property we handle.
+	  (if (eq (cadr (memq :initialize rest)) #'custom-initialize-delay)
+	      ;; These vars are defined early and should hence be initialized
+	      ;; early, even if this file happens to be loaded late.  so add
+              ;; them to the end of custom-delayed-init-variables.  Otherwise,
+	      ;; auto-save-file-name-transforms will appear in customize-rogue.
+	      (add-to-list 'custom-delayed-init-variables symbol 'append))
 	;; Add it to the right group(s).
 	(if (listp group)
 	    (dolist (g group)