Subject: bug#48264: [PATCH v3 12/15] Set buffer_defaults fields without a default to Qunbound

From: Spencer Baugh <[email-masked]>
Date: Thu, 6 May 2021 17:33:43 -0400

In this way, we can be more sure that we aren't accidentally using
these fields.  We can also use the fact that fields without a default
are set to Qunbound to implement BUFFER_DEFAULT_VALUE_P.

* src/buffer.c (init_buffer_once): Set unused buffer_defaults fields
to Qunbound.
* src/buffer.h (BUFFER_DEFAULT_VALUE_P):
Check if field is Qunbound to determine if there's a default.
---
 src/buffer.c | 43 +++++++++++++++++++++++++++++++------------
 src/buffer.h |  5 +++--
 2 files changed, 34 insertions(+), 14 deletions(-)

diff --git a/src/buffer.c b/src/buffer.c
index 3ece2f5b15..097d03690a 100644
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -54,7 +54,8 @@ along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.  */
    defined with DEFVAR_PER_BUFFER, that have special slots in each buffer.
    The default value occupies the same slot in this structure
    as an individual buffer's value occupies in that buffer.
-*/
+   Slots in this structure which are set to Qunbound are permanently
+   buffer-local. */
 
 struct buffer buffer_defaults;
 
@@ -5252,6 +5253,15 @@ init_buffer_once (void)
 
   /* Set up the default values of various buffer slots.  */
   /* Must do these before making the first buffer! */
+  int offset;
+  FOR_EACH_PER_BUFFER_OBJECT_AT (offset)
+    {
+      /* These are initialized before us. */
+      if (!(offset == PER_BUFFER_VAR_OFFSET (syntax_table)
+            || offset == PER_BUFFER_VAR_OFFSET (category_table)))
+        set_per_buffer_default (offset, Qunbound);
+    }
+  set_per_buffer_default (PER_BUFFER_VAR_OFFSET (undo_list), Qunbound);
 
   /* real setup is done in bindings.el */
   bset_mode_line_format (&buffer_defaults, build_pure_c_string ("%-"));
@@ -5265,13 +5275,6 @@ init_buffer_once (void)
   bset_selective_display_ellipses (&buffer_defaults, Qt);
   bset_abbrev_table (&buffer_defaults, Qnil);
   bset_display_table (&buffer_defaults, Qnil);
-  bset_undo_list (&buffer_defaults, Qnil);
-  bset_mark_active (&buffer_defaults, Qnil);
-  bset_file_format (&buffer_defaults, Qnil);
-  bset_auto_save_file_format (&buffer_defaults, Qt);
-  set_buffer_overlays_before (&buffer_defaults, NULL);
-  set_buffer_overlays_after (&buffer_defaults, NULL);
-  buffer_defaults.overlay_center = BEG;
 
   XSETFASTINT (BVAR (&buffer_defaults, tab_width), 8);
   bset_truncate_lines (&buffer_defaults, Qnil);
@@ -5285,13 +5288,10 @@ init_buffer_once (void)
   bset_extra_line_spacing (&buffer_defaults, Qnil);
   bset_cursor_in_non_selected_windows (&buffer_defaults, Qt);
 
-  bset_enable_multibyte_characters (&buffer_defaults, Qt);
   bset_buffer_file_coding_system (&buffer_defaults, Qnil);
   XSETFASTINT (BVAR (&buffer_defaults, fill_column), 70);
   XSETFASTINT (BVAR (&buffer_defaults, left_margin), 0);
   bset_cache_long_scans (&buffer_defaults, Qt);
-  bset_file_truename (&buffer_defaults, Qnil);
-  XSETFASTINT (BVAR (&buffer_defaults, display_count), 0);
   XSETFASTINT (BVAR (&buffer_defaults, left_margin_cols), 0);
   XSETFASTINT (BVAR (&buffer_defaults, right_margin_cols), 0);
   bset_left_fringe_width (&buffer_defaults, Qnil);
@@ -5307,7 +5307,6 @@ init_buffer_once (void)
   bset_fringe_cursor_alist (&buffer_defaults, Qnil);
   bset_scroll_up_aggressively (&buffer_defaults, Qnil);
   bset_scroll_down_aggressively (&buffer_defaults, Qnil);
-  bset_display_time (&buffer_defaults, Qnil);
 
   /* Assign the local-flags to the slots that have default values.
      The local flag is a bit that is used in the buffer
@@ -5333,6 +5332,26 @@ init_buffer_once (void)
   DEFSYM (Qkill_buffer_hook, "kill-buffer-hook");
   Fput (Qkill_buffer_hook, Qpermanent_local, Qt);
 
+  /* Sanity check that we didn't set the default for slots which
+     are permanent-buffer-locals. */
+  eassert (EQ (BVAR (&buffer_defaults, filename), Qunbound));
+  eassert (EQ (BVAR (&buffer_defaults, directory), Qunbound));
+  eassert (EQ (BVAR (&buffer_defaults, backed_up), Qunbound));
+  eassert (EQ (BVAR (&buffer_defaults, save_length), Qunbound));
+  eassert (EQ (BVAR (&buffer_defaults, auto_save_file_name), Qunbound));
+  eassert (EQ (BVAR (&buffer_defaults, read_only), Qunbound));
+  eassert (EQ (BVAR (&buffer_defaults, mode_name), Qunbound));
+  eassert (EQ (BVAR (&buffer_defaults, undo_list), Qunbound));
+  eassert (EQ (BVAR (&buffer_defaults, mark_active), Qunbound));
+  eassert (EQ (BVAR (&buffer_defaults, point_before_scroll), Qunbound));
+  eassert (EQ (BVAR (&buffer_defaults, file_truename), Qunbound));
+  eassert (EQ (BVAR (&buffer_defaults, invisibility_spec), Qunbound));
+  eassert (EQ (BVAR (&buffer_defaults, file_format), Qunbound));
+  eassert (EQ (BVAR (&buffer_defaults, auto_save_file_format), Qunbound));
+  eassert (EQ (BVAR (&buffer_defaults, display_count), Qunbound));
+  eassert (EQ (BVAR (&buffer_defaults, display_time), Qunbound));
+  eassert (EQ (BVAR (&buffer_defaults, enable_multibyte_characters), Qunbound));
+
   /* Super-magic invisible buffer.  */
   Vprin1_to_string_buffer =
     Fget_buffer_create (build_pure_c_string (" prin1"), Qt);
diff --git a/src/buffer.h b/src/buffer.h
index e55cbcdd94..fc67b220e4 100644
--- a/src/buffer.h
+++ b/src/buffer.h
@@ -1102,7 +1102,8 @@ BUFFER_CHECK_INDIRECTION (struct buffer *b)
    that have special slots in each buffer.
    The default value occupies the same slot in this structure
    as an individual buffer's value occupies in that buffer.
-*/
+   Slots in this structure which are set to Qunbound are permanently
+   buffer-local. */
 
 extern struct buffer buffer_defaults;
 
@@ -1474,7 +1475,7 @@ set_per_buffer_value (struct buffer *b, int offset, Lisp_Object value)
 INLINE bool
 BUFFER_DEFAULT_VALUE_P (int offset)
 {
-  return PER_BUFFER_IDX (offset) > 0;
+  return !EQ (per_buffer_default (offset), Qunbound);
 }
 
 /* Value is true if the variable with offset OFFSET has a local value
-- 
2.31.1