Subject: bug#78898: Make read/readevalloop reentrant

From: Lynn Winebarger <[email-masked]>
Date: Fri, 27 Jun 2025 02:45:22 -0400

I tried explicitly forcing emacs-internal as the coding-system for
load_source_file, but without any noticeable difference.
The button preceding the warning messages should be a stop sign emoji.
Using the built emacs to view emacs-lisp/warning.el shows the stop
sign emoji clearly, but it is apparently mangled in the generated
byte-code in warning.elc.
I also built a clean emacs from commit
2bdcf0250acecdb0719203ae711aedf5baad1783.  When I compared the source
elisp files (after building) I see differences in these files:
lisp/international/uni-bidi.el
lisp/international/uni-brackets.el
lisp/international/uni-category.el
lisp/international/uni-combining.el
lisp/international/uni-comment.el
lisp/international/uni-decomposition.el
lisp/international/uni-old-name.el
lisp/international/uni-name.el
lisp/leim/leim-list.el
lisp/leim/ja-dic/ja-dic.el
lisp/net/tramp-loaddefs.el
lisp/textmodes/reftex-loaddefs.el
lisp/loaddefs.el
lisp/finder-inf.el
lisp/cus-load.el

In the byte-compiled files, I see differences for:
lisp/emacs-lisp/eieio-opt.elc
lisp/erc/erc-nicks.elc
lisp/erc/erc.elc
lisp/eshell/em-cmpl.elc
lisp/gnus/gnus-group.elc
lisp/gnus/gnus-srvr.elc
lisp/gnus/gnus-topic.elc
lisp/gnus/gnus-sieve.elc
lisp/gnus/gnus-search.elc
lisp/gnus/message.elc
lisp/gnus/nnfeed.elc
lisp/gnus/nnml.elc
lisp/gnus/nnimap.elc
lisp/gnus/nnagent.elc
lisp/gnus/nnmaildir.elc
lisp/gnus/gnus-start.elc
lisp/gnus/gnus-sum.elc
lisp/gnus/nnmairix.elc
lisp/gnus/nnselect.elc
lisp/net/tramp-cache.elc
lisp/net/tramp-cmds.elc
lisp/net/tramp-gvfs.elc
lisp/net/tramp-sh.elc
lisp/obsolete/nnir.elc
lisp/org/org-agenda.elc
lisp/org/org-lint.elc
lisp/org/ox-ascii.elc
lisp/org/ox-odt.elc
lisp/org/org.elc
lisp/progmodes/eglot.elc
lisp/progmodes/cc-engine.elc
lisp/progmodes/cc-mode.elc
lisp/progmodes/js.elc
lisp/use-package/use-package-core.elc
lisp/loaddefs.elc

I'm not clear on why loaddefs.el should be different.  That, and
eieio-opt.elc being different is unexpected.

Lynn
From d702950972c16c34fb12c2f181da28ae69b93e37 Mon Sep 17 00:00:00 2001
From: Onnie Lynn Winebarger <[email-masked]>
Date: Fri, 27 Jun 2025 02:32:41 -0400
Subject: [PATCH 2/2] Try explicit use of emacs-internal coding in
 load_source_file

---
 src/coding.c | 39 +++++++++++++++++++++++++++++++++++++++
 src/lread.c  | 23 ++++++++++++++++++-----
 2 files changed, 57 insertions(+), 5 deletions(-)

diff --git a/src/coding.c b/src/coding.c
index f4ce1c4b5bd..42d3e51175a 100644
--- a/src/coding.c
+++ b/src/coding.c
@@ -12001,6 +12001,7 @@ syms_of_coding (void)
 There are three such tables: `file-coding-system-alist',
 `process-coding-system-alist', and `network-coding-system-alist'.  */);
   Vcoding_system_for_read = Qnil;
+  DEFSYM (Qcoding_system_for_read, "coding-system-for-read");
 
   DEFVAR_LISP ("coding-system-for-write", Vcoding_system_for_write,
 	       doc: /* Specify the coding system for write operations.
@@ -12304,6 +12305,13 @@ system (e.g. `iso-2022-7bit').
   for (int i = 0; i < coding_category_max; i++)
     Fset (AREF (Vcoding_category_table, i), Qno_conversion);
 
+  /* These are used in local variables "coding: " in some emacs source
+     lisp files.
+     Would like to not require loadup just to load  (or byte-compile)
+     emacs source.
+     utf-8/utf-8-unix
+     utf-8-emacs-unix/utf-8-emacs
+  */
   plist[1] = args[coding_arg_name] = Qraw_text;
   plist[3] = args[coding_arg_mnemonic] = make_fixnum ('t');
   plist[5] = args[coding_arg_coding_type] = Qraw_text;
@@ -12327,6 +12335,37 @@ #define RAW_TEXT_DESCRIPTION                                            \
   args[coding_arg_plist] = CALLMANY (Flist, plist);
   Fdefine_coding_system_internal (coding_arg_max, args);
 
+  memclear (args, sizeof args);
+  plist[1] = args[coding_arg_name] = Qutf_8;
+  plist[3] = args[coding_arg_mnemonic] = make_fixnum ('U');
+  plist[5] = args[coding_arg_coding_type] = Qutf_8;
+  plist[7] = args[coding_arg_ascii_compatible_p] = Qt;
+  plist[9] = args[coding_arg_charset_list] = list1 (Qunicode);
+  plist[10] = intern_c_string (":mime-charset");
+  plist[11] = Qutf_8;
+  plist[13] = build_string ("UTF-8 (no signature (BOM))");
+  plist[15] = args[coding_arg_eol_type] = Qnil;
+  args[coding_arg_plist] = CALLMANY (Flist, plist);
+  args[coding_arg_utf8_bom] = Qnil;
+  Fdefine_coding_system_internal (coding_arg_utf8_max, args);
+
+  memclear (args, sizeof args);
+  plist[1] = args[coding_arg_name] = Qutf_8_emacs;
+  plist[3] = args[coding_arg_mnemonic] = make_fixnum ('U');
+  plist[5] = args[coding_arg_coding_type] = Qutf_8;
+  plist[7] = args[coding_arg_ascii_compatible_p] = Qt;
+  plist[9] = args[coding_arg_charset_list] = list1 (Qemacs);
+  plist[11] = Qnil;
+  plist[13] = build_string ("Support for all Emacs characters (including non-Unicode characters).");
+  plist[15] = args[coding_arg_eol_type] = Qnil;
+  args[coding_arg_plist] = CALLMANY (Flist, plist);
+  args[coding_arg_utf8_bom] = Qnil;
+  Fdefine_coding_system_internal (coding_arg_utf8_max, args);
+
+  DEFSYM (Qemacs_internal, "emacs-internal");
+  DEFSYM (Qutf_8_emacs_unix, "utf-8-emacs-unix");
+  Fdefine_coding_system_alias (Qemacs_internal, Qutf_8_emacs_unix);
+
   pdumper_do_now_and_after_load (reset_coding_after_pdumper_load);
 
   DEFSYM (QUnknown_error, "Unknown error");
diff --git a/src/lread.c b/src/lread.c
index 0fbe187b5a8..cb8559f455c 100644
--- a/src/lread.c
+++ b/src/lread.c
@@ -1818,6 +1818,7 @@ closing_unreadchar (register lread_frame *frame)
 AVOID
 invalid_syntax_lisp (register lread_frame *frame, Lisp_Object s)
 {
+ retry:
   if (HAS_BUFFER_P (frame->intype))
     {
       ptrdiff_t line, column;
@@ -1837,8 +1838,12 @@ invalid_syntax_lisp (register lread_frame *frame, Lisp_Object s)
 	       list3 (s, make_fixnum (line), make_fixnum (column)));
     }
   else if (frame->intype == LREAD_INPUT_INDIRECT
-      && frame->input.frame.source)
-    invalid_syntax_lisp (frame->input.frame.source,s);
+      && frame->input.frame.source && frame != frame->input.frame.source)
+    {
+      /* Shut up infinite recursion warning */
+      frame = frame->input.frame.source;
+      goto retry;
+    }
   else
     xsignal1 (Qinvalid_read_syntax, s);
 }
@@ -2534,7 +2539,6 @@ load_source_file (Lisp_Object fullname, Lisp_Object file,
     = Fgenerate_new_buffer_name (build_string (" *load*"), Qnil);
   Lisp_Object buffer = Fget_buffer_create (buffer_name, Qnil);
   specpdl_ref count = SPECPDL_INDEX ();
-  /* this is only called for source files */
   /* load-with-code-conversion binds load-in-progress in an outer
      scope, where Fload binds it with load-file-name, etc, below */
   specbind (Qload_in_progress, Qt);
@@ -2553,8 +2557,11 @@ load_source_file (Lisp_Object fullname, Lisp_Object file,
     specbind (Qload_file_name, file);
     specbind (Qload_true_file_name, fullname);
     specbind (Qinhibit_file_name_operation, Qnil);
-    /* If auto-coding was implemented, load would have called
-       load-with-code-conversion instead of this, so don't bother */
+    /* this function is only called for source files in a bare temacs */
+    /* Source files in the emacs distribution are required to be
+       in a coding compatible with emacs-internal, so assume that since
+       auto-coding is not available if this function is being called. */
+    specbind (Qcoding_system_for_read, Qemacs_internal);
     record_unwind_current_buffer ();
     Fset_buffer (buffer);
     Fset_buffer_multibyte (Qt);
@@ -2563,6 +2570,12 @@ load_source_file (Lisp_Object fullname, Lisp_Object file,
       specbind (Qdeactivate_mark, Qnil);
       unbind_to (count2,
 		 Finsert_file_contents (fullname, Qnil, Qnil, Qnil, Qnil));
+      Lisp_Object multibyte
+	= BVAR (current_buffer, enable_multibyte_characters);
+      ptrdiff_t id = CODING_SYSTEM_ID (Vlast_coding_system_used);
+      Lisp_Object used = CODING_ATTR_TYPE (CODING_ID_ATTRS (id));
+      if (!(NILP (multibyte)) && (EQ (used, Qraw_text)))
+	Fset_buffer_multibyte (Qnil);
     }
     /* don't worry about shorthands in temacs sans loadup*/
     /* CAVEAT EMPTOR: require emacs lisp source files read by temacs sans
-- 
2.49.0