Subject: Re: bug#74145: 31.0.50; Default lexical-binding to t

From: Stefan Monnier <[email-masked]>
Date: Tue, 25 Mar 2025 15:27:46 -0400

> Are you ok with our implementing that warning now?

Apparently, noone's interested in doing that, so I suggest the patch below.

        Stefan
diff --git a/lisp/files.el b/lisp/files.el
index 4e3aeeb9246..8bc9bba876c 100644
--- a/lisp/files.el
+++ b/lisp/files.el
@@ -4274,6 +4335,25 @@ hack-local-variables
               (push elem file-local-variables-alist)))
           (hack-local-variables-apply))))))
 
+(defun internal--get-default-lexical-binding-function (from)
+  (or (and (bufferp from) (zerop (buffer-size from)))
+      (and (stringp from) (eql 0 (file-attribute-size (file-attributes from))))
+      (display-warning
+       'files
+       (format-message "Missing `lexical-binding' cookie in %S
+See `(elisp)Selecting Lisp Dialect' and `(elisp)Converting to Lexical Binding'
+for more information."
+                       (if (not (and (bufferp from)
+                                     (equal (buffer-name from) " *load*")
+                                     load-file-name))
+                           from
+                         (abbreviate-file-name load-file-name)))
+       :warning))
+  (default-toplevel-value 'lexical-binding))
+
+(setq internal--get-default-lexical-binding-function
+      #'internal--get-default-lexical-binding-function)
+
 (defun hack-local-variables--find-variables (&optional handle-mode)
   "Return all local variables in the current buffer.
 If HANDLE-MODE is nil, we gather all the specified local
diff --git a/src/lread.c b/src/lread.c
index add8deb3954..fd8f9e80ebd 100644
--- a/src/lread.c
+++ b/src/lread.c
@@ -1271,6 +1265,18 @@ close_file_unwind_android_fd (void *ptr)
 
 #endif
 
+static Lisp_Object
+get_lexical_binding (Lisp_Object stream, Lisp_Object from)
+{
+  lexical_cookie_t lexc = lisp_file_lexical_cookie (stream);
+  return (lexc == Cookie_Lex ? Qt
+	  : lexc == Cookie_Dyn ? Qnil
+	  : (NILP (from)	/* Loading a byte-compiled file.  */
+	     || NILP (Vinternal__get_default_lexical_binding_function)
+	     ? Fdefault_toplevel_value (Qlexical_binding)
+	     : calln (Vinternal__get_default_lexical_binding_function, from)));
+}
+
 DEFUN ("load", Fload, Sload, 1, 5, 0,
        doc: /* Execute a file of Lisp code named FILE.
 First try FILE with `.elc' appended, then try with `.el', then try
@@ -1720,11 +1733,8 @@ DEFUN ("load", Fload, Sload, 1, 5, 0,
     }
   else
     {
-      lexical_cookie_t lexc = lisp_file_lexical_cookie (Qget_file_char);
       Fset (Qlexical_binding,
-	    (lexc == Cookie_Lex ? Qt
-	     : lexc == Cookie_Dyn ? Qnil
-	     : Fdefault_toplevel_value (Qlexical_binding)));
+	    get_lexical_binding (Qget_file_char, compiled ? Qnil : file));
 
       if (! version || version >= 22)
         readevalloop (Qget_file_char, &input, hist_file_name,
@@ -2609,11 +2619,7 @@ DEFUN ("eval-buffer", Feval_buffer, Seval_buffer, 0, 5, "",
   specbind (Qstandard_output, tem);
   record_unwind_protect_excursion ();
   BUF_TEMP_SET_PT (XBUFFER (buf), BUF_BEGV (XBUFFER (buf)));
-  lexical_cookie_t lexc = lisp_file_lexical_cookie (buf);
-  specbind (Qlexical_binding,
-	    lexc == Cookie_Lex ? Qt
-	    : lexc == Cookie_Dyn ? Qnil
-	    : Fdefault_toplevel_value (Qlexical_binding));
+  specbind (Qlexical_binding, get_lexical_binding (buf, buf));
   BUF_TEMP_SET_PT (XBUFFER (buf), BUF_BEGV (XBUFFER (buf)));
   readevalloop (buf, 0, filename,
 		!NILP (printflag), unibyte, Qnil, Qnil, Qnil);
@@ -5169,7 +5175,7 @@ obarray_index (struct Lisp_Obarray *oa, const char *str, ptrdiff_t size_byte)
   return knuth_hash (reduce_emacs_uint_to_hash_hash (hash), oa->size_bits);
 }
 
-/* Return the symbol in OBARRAY whose names matches the string
+/* Return the symbol in OBARRAY whose name matches the string
    of SIZE characters (SIZE_BYTE bytes) at PTR.
    If there is no such symbol, return the integer bucket number of
    where the symbol would be if it were present.
@@ -6145,6 +6151,11 @@ syms_of_lread (void)
 
   DEFSYM (Qchar_from_name, "char-from-name");
 
+  DEFVAR_LISP ("internal--get-default-lexical-binding-function",
+	       Vinternal__get_default_lexical_binding_function,
+	       doc: /* Function to decide default lexical-binding.  */);
+  Vinternal__get_default_lexical_binding_function = Qnil;
+
   DEFVAR_LISP ("read-symbol-shorthands", Vread_symbol_shorthands,
           doc: /* Alist of known symbol-name shorthands.
 This variable's value can only be set via file-local variables.