]> git.eshelyaron.com Git - emacs.git/commitdiff
(Fload, Feval_buffer): Emit a warning when lexbind is unset (bug#74145)
authorStefan Monnier <monnier@iro.umontreal.ca>
Tue, 8 Apr 2025 01:41:35 +0000 (21:41 -0400)
committerEshel Yaron <me@eshelyaron.com>
Tue, 8 Apr 2025 05:50:08 +0000 (07:50 +0200)
This emits a warning at run-time rather than at compile time.

* src/lread.c (get_lexical_binding): New function.
(Fload, Feval_buffer): Use it.
(syms_of_lread): New var `internal--get-default-lexical-binding-function`.
* lisp/files.el: Set it.
(internal--get-default-lexical-binding): New function.

(cherry picked from commit 9f25d46568bf0a4d617145537db4c8aaf5e0219b)

lisp/files.el
src/lread.c

index 68abe814f4bc5fdf31aabbf8d3da7eacdc7602ec..7228f28e726f243435f57a0e93eeb7762f61a63e 100644 (file)
@@ -4278,6 +4278,30 @@ all the specified local variables, but ignores any settings of \"mode:\"."
               (push elem file-local-variables-alist)))
           (hack-local-variables-apply))))))
 
+(defun internal--get-default-lexical-binding (from)
+  (let ((mib (lambda (node) (buttonize node (lambda (_) (info node))))))
+    (or (and (bufferp from) (zerop (buffer-size from)))
+        (and (stringp from)
+             (eql 0 (file-attribute-size (file-attributes from))))
+        (display-warning
+         '(files missing-lexbind-cookie)
+         (format-message "Missing `lexical-binding' cookie in %S.
+You can add one with `M-x elisp-enable-lexical-binding RET'.
+See `%s' and `%s'
+for more information."
+                         (if (not (and (bufferp from)
+                                       (equal (buffer-name from) " *load*")
+                                       load-file-name))
+                             from
+                           (abbreviate-file-name load-file-name))
+                         (funcall mib "(elisp)Selecting Lisp Dialect")
+                         (funcall mib "(elisp)Converting to Lexical Binding"))
+         :warning))
+    (default-toplevel-value 'lexical-binding)))
+
+(setq internal--get-default-lexical-binding-function
+      #'internal--get-default-lexical-binding)
+
 (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
index add8deb3954dac14f2b50e848e14bba8caa272b4..445e5cd1fba422792c92b27dca4de9255643692a 100644 (file)
@@ -1271,6 +1271,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 +1732,8 @@ Return t if the file exists and loads successfully.  */)
     }
   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 +2618,7 @@ This function preserves the position of point.  */)
   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 +5174,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 +6150,11 @@ through `require'.  */);
 
   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.