Subject: bug#25128: closed (Re: bug#25128: Reorder lisp.h to declare types before using them)

From: [email-masked] (GNU bug Tracking System)
Date: Sun, 25 Dec 2016 17:39:02 +0000

Your bug report

#25128: Reorder lisp.h to declare types before using them

which was filed against the emacs package, has been closed.

The explanation is attached below, along with your original report.
If you require more details, please reply to [email-masked].

-- 
25128: http://debbugs.gnu.org/cgi/bugreport.cgi?bug=25128
GNU Bug Tracking System
Contact [email-masked] with problems

Subject: Re: bug#25128: Reorder lisp.h to declare types before using them
From: Paul Eggert <[email-masked]>
To: [email-masked]
Date: Sun, 25 Dec 2016 09:38:14 -0800
List-Id: <debbugs-submit.debbugs.gnu.org>

I installed this patch, after fixing it up to work with the concurrency branch.

Subject: Reorder lisp.h to declare types before using them
From: Paul Eggert <[email-masked]>
To: Emacs bug reports and feature requests <[email-masked]>
Date: Tue, 6 Dec 2016 23:19:19 -0800
List-Id: <debbugs-submit.debbugs.gnu.org>

Tags: patch

Attached is a patch to reorder src/lisp.h so that more types are declared before 
use. The main motivation is to eventually add support for 
-fcheck-pointer-bounds; future changes will need access to type sizes (e.g., 
XCONS might need sizeof (struct Lisp_Cons)), which should be easy after this 
change. Also, the change shortens lisp.h a bit and (if you ask me) makes it 
easier to read, since the basic functions for a type are now declared next to 
the type.

I would like to install this soon, and am posting this as a bug report to give 
Eli and others a heads-up, in case some MS-Windows module now needs to include 
process.h. This may be needed because XPROCESS is now defined in process.h 
instead of lisp.h; similarly for buffer.h, window.h, termhooks.h.
From d9627a9df1ef0e27df0e7eefa40aad85eeeb056c Mon Sep 17 00:00:00 2001
From: Paul Eggert <[email-masked]>
Date: Tue, 6 Dec 2016 22:12:43 -0800
Subject: [PATCH] Reorder lisp.h to declare types before using them

Reorder lisp.h to put basic functions for types to be after the
corresponding type definitions.  This is a more-common programming
style in C, and will make it easier to port Emacs to gcc
-fcheck-pointer-bounds, since the functions now have access to the
corresponding types' sizes.  This patch does not change the code; it
just moves declarations and definitions and removes no-longer-needed
forward declarations.
* src/buffer.c, src/data.c, src/image.c:
Include process.h, for PROCESSP.
* src/buffer.h (BUFFERP, CHECK_BUFFER, XBUFFER):
* src/process.h (PROCESSP, CHECK_PROCESS, XPROCESS):
* src/terminal.h (TERMINALP, XTERMINAL):
* src/window.h (WINDOWP, CHECK_WINDOW, XWINDOW):
Move here from lisp.h.
* src/intervals.h: Include buffer.h, for BUFFERP.
* src/lisp.h: Reorder declarations and definitions as described above.
Move some symbols to other headers (noted above).
Remove forward decls that are no longer needed.
---
 src/buffer.c    |   1 +
 src/buffer.h    |  19 ++
 src/data.c      |   1 +
 src/image.c     |   1 +
 src/intervals.h |   3 +
 src/lisp.h      | 832 +++++++++++++++++++++++++-------------------------------
 src/process.h   |  19 ++
 src/termhooks.h |  13 +
 src/window.h    |  19 ++
 9 files changed, 448 insertions(+), 460 deletions(-)

diff --git a/src/buffer.c b/src/buffer.c
index 6815aa7..0ae0221 100644
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -32,6 +32,7 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #include "lisp.h"
 #include "intervals.h"
+#include "process.h"
 #include "systime.h"
 #include "window.h"
 #include "commands.h"
diff --git a/src/buffer.h b/src/buffer.h
index 6ac161c..a8ca6a3 100644
--- a/src/buffer.h
+++ b/src/buffer.h
@@ -881,6 +881,25 @@ struct buffer
   Lisp_Object undo_list_;
 };
 
+INLINE bool
+BUFFERP (Lisp_Object a)
+{
+  return PSEUDOVECTORP (a, PVEC_BUFFER);
+}
+
+INLINE void
+CHECK_BUFFER (Lisp_Object x)
+{
+  CHECK_TYPE (BUFFERP (x), Qbufferp, x);
+}
+
+INLINE struct buffer *
+XBUFFER (Lisp_Object a)
+{
+  eassert (BUFFERP (a));
+  return XUNTAG (a, Lisp_Vectorlike);
+}
+
 /* Most code should use these functions to set Lisp fields in struct
    buffer.  (Some setters that are private to a single .c file are
    defined as static in those files.)  */
diff --git a/src/data.c b/src/data.c
index 64cd8b2..405234e 100644
--- a/src/data.c
+++ b/src/data.c
@@ -31,6 +31,7 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #include "character.h"
 #include "buffer.h"
 #include "keyboard.h"
+#include "process.h"
 #include "frame.h"
 #include "keymap.h"
 
diff --git a/src/image.c b/src/image.c
index 89572b8..45010e7 100644
--- a/src/image.c
+++ b/src/image.c
@@ -36,6 +36,7 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #include "lisp.h"
 #include "frame.h"
+#include "process.h"
 #include "window.h"
 #include "buffer.h"
 #include "dispextern.h"
diff --git a/src/intervals.h b/src/intervals.h
index 9a38d84..b56c050 100644
--- a/src/intervals.h
+++ b/src/intervals.h
@@ -19,6 +19,9 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #ifndef EMACS_INTERVALS_H
 #define EMACS_INTERVALS_H
 
+#include "buffer.h"
+#include "lisp.h"
+
 INLINE_HEADER_BEGIN
 
 /* Basic data type for use of intervals.  */
diff --git a/src/lisp.h b/src/lisp.h
index b9c6289..c3eaf42 100644
--- a/src/lisp.h
+++ b/src/lisp.h
@@ -258,6 +258,11 @@ DEFINE_GDB_SYMBOL_BEGIN (bool, USE_LSB_TAG)
 #define USE_LSB_TAG (VAL_MAX / 2 < INTPTR_MAX)
 DEFINE_GDB_SYMBOL_END (USE_LSB_TAG)
 
+/* Mask for the value (as opposed to the type bits) of a Lisp object.  */
+DEFINE_GDB_SYMBOL_BEGIN (EMACS_INT, VALMASK)
+# define VALMASK (USE_LSB_TAG ? - (1 << GCTYPEBITS) : VAL_MAX)
+DEFINE_GDB_SYMBOL_END (VALMASK)
+
 #if !USE_LSB_TAG && !defined WIDE_EMACS_INT
 # error "USE_LSB_TAG not supported on this platform; please report this." \
 	"Try 'configure --with-wide-int' to work around the problem."
@@ -556,42 +561,9 @@ enum CHECK_LISP_OBJECT_TYPE { CHECK_LISP_OBJECT_TYPE = false };
 /* Forward declarations.  */
 
 /* Defined in this file.  */
-union Lisp_Fwd;
-INLINE bool BOOL_VECTOR_P (Lisp_Object);
-INLINE bool BUFFER_OBJFWDP (union Lisp_Fwd *);
-INLINE bool BUFFERP (Lisp_Object);
-INLINE bool CHAR_TABLE_P (Lisp_Object);
-INLINE Lisp_Object CHAR_TABLE_REF_ASCII (Lisp_Object, ptrdiff_t);
-INLINE bool (CONSP) (Lisp_Object);
-INLINE bool (FLOATP) (Lisp_Object);
-INLINE bool (INTEGERP) (Lisp_Object);
-INLINE bool (MARKERP) (Lisp_Object);
-INLINE bool (MISCP) (Lisp_Object);
-INLINE bool (NILP) (Lisp_Object);
-INLINE bool OVERLAYP (Lisp_Object);
-INLINE bool PROCESSP (Lisp_Object);
-INLINE bool PSEUDOVECTORP (Lisp_Object, int);
-INLINE bool SAVE_VALUEP (Lisp_Object);
-INLINE bool FINALIZERP (Lisp_Object);
-
-#ifdef HAVE_MODULES
-INLINE bool USER_PTRP (Lisp_Object);
-INLINE struct Lisp_User_Ptr *(XUSER_PTR) (Lisp_Object);
-#endif
 
 INLINE void set_sub_char_table_contents (Lisp_Object, ptrdiff_t,
 					      Lisp_Object);
-INLINE bool STRINGP (Lisp_Object);
-INLINE bool SUB_CHAR_TABLE_P (Lisp_Object);
-INLINE bool SUBRP (Lisp_Object);
-INLINE bool (SYMBOLP) (Lisp_Object);
-INLINE bool (VECTORLIKEP) (Lisp_Object);
-INLINE bool WINDOWP (Lisp_Object);
-INLINE bool TERMINALP (Lisp_Object);
-INLINE struct Lisp_Save_Value *XSAVE_VALUE (Lisp_Object);
-INLINE struct Lisp_Finalizer *XFINALIZER (Lisp_Object);
-INLINE struct Lisp_Symbol *(XSYMBOL) (Lisp_Object);
-INLINE void *(XUNTAG) (Lisp_Object, int);
 
 /* Defined in chartab.c.  */
 extern Lisp_Object char_table_ref (Lisp_Object, int);
@@ -600,8 +572,6 @@ extern void char_table_set (Lisp_Object, int, Lisp_Object);
 /* Defined in data.c.  */
 extern _Noreturn void wrong_type_argument (Lisp_Object, Lisp_Object);
 extern _Noreturn void wrong_choice (Lisp_Object, Lisp_Object);
-extern void notify_variable_watchers (Lisp_Object symbol, Lisp_Object newval,
-                                      Lisp_Object operation, Lisp_Object where);

 #ifdef CANNOT_DUMP
@@ -618,6 +588,56 @@ extern bool initialized;
 extern double extract_float (Lisp_Object);
 
 
+/* Low-level conversion and type checking.  */
+
+/* Convert a Lisp_Object to the corresponding EMACS_INT and vice versa.
+   At the machine level, these operations are no-ops.  */
+
+INLINE EMACS_INT
+(XLI) (Lisp_Object o)
+{
+  return lisp_h_XLI (o);
+}
+
+INLINE Lisp_Object
+(XIL) (EMACS_INT i)
+{
+  return lisp_h_XIL (i);
+}
+
+/* Extract A's type.  */
+
+INLINE enum Lisp_Type
+(XTYPE) (Lisp_Object a)
+{
+#if USE_LSB_TAG
+  return lisp_h_XTYPE (a);
+#else
+  EMACS_UINT i = XLI (a);
+  return USE_LSB_TAG ? i & ~VALMASK : i >> VALBITS;
+#endif
+}
+
+INLINE void
+(CHECK_TYPE) (int ok, Lisp_Object predicate, Lisp_Object x)
+{
+  lisp_h_CHECK_TYPE (ok, predicate, x);
+}
+
+/* Extract A's pointer value, assuming A's type is TYPE.  */
+
+INLINE void *
+(XUNTAG) (Lisp_Object a, int type)
+{
+#if USE_LSB_TAG
+  return lisp_h_XUNTAG (a, type);
+#else
+  intptr_t i = USE_LSB_TAG ? XLI (a) - type : XLI (a) & VALMASK;
+  return (void *) i;
+#endif
+}
+
+
 /* Interned state of a symbol.  */
 
 enum symbol_interned
@@ -746,6 +766,10 @@ struct Lisp_Symbol
   DEFINE_GDB_SYMBOL_BEGIN (Lisp_Object, name) \
   DEFINE_GDB_SYMBOL_END (LISPSYM_INITIALLY (name))
 
+/* The index of the C-defined Lisp symbol SYM.
+   This can be used in a static initializer.  */
+#define SYMBOL_INDEX(sym) i##sym
+
 /* By default, define macros for Qt, etc., as this leads to a bit
    better performance in the core Emacs interpreter.  A plugin can
    define DEFINE_NON_NIL_Q_SYMBOL_MACROS to be false, to be portable to
@@ -756,19 +780,43 @@ struct Lisp_Symbol
 
 #include "globals.h"
 
-/* Convert a Lisp_Object to the corresponding EMACS_INT and vice versa.
-   At the machine level, these operations are no-ops.  */
+INLINE bool
+(SYMBOLP) (Lisp_Object x)
+{
+  return lisp_h_SYMBOLP (x);
+}
 
-INLINE EMACS_INT
-(XLI) (Lisp_Object o)
+INLINE struct Lisp_Symbol *
+(XSYMBOL) (Lisp_Object a)
 {
-  return lisp_h_XLI (o);
+#if USE_LSB_TAG
+  return lisp_h_XSYMBOL (a);
+#else
+  eassert (SYMBOLP (a));
+  intptr_t i = (intptr_t) XUNTAG (a, Lisp_Symbol);
+  void *p = (char *) lispsym + i;
+  return p;
+#endif
 }
 
 INLINE Lisp_Object
-(XIL) (EMACS_INT i)
+make_lisp_symbol (struct Lisp_Symbol *sym)
 {
-  return lisp_h_XIL (i);
+  Lisp_Object a = XIL (TAG_SYMOFFSET ((char *) sym - (char *) lispsym));
+  eassert (XSYMBOL (a) == sym);
+  return a;
+}
+
+INLINE Lisp_Object
+builtin_lisp_symbol (int index)
+{
+  return make_lisp_symbol (lispsym + index);
+}
+
+INLINE void
+(CHECK_SYMBOL) (Lisp_Object x)
+{
+ lisp_h_CHECK_SYMBOL (x);
 }
 
 /* In the size word of a vector, this bit means the vector has been marked.  */
@@ -836,11 +884,6 @@ enum More_Lisp_Bits
    XCONS (tem) is the struct Lisp_Cons * pointing to the memory for
    that cons.  */
 
-/* Mask for the value (as opposed to the type bits) of a Lisp object.  */
-DEFINE_GDB_SYMBOL_BEGIN (EMACS_INT, VALMASK)
-# define VALMASK (USE_LSB_TAG ? - (1 << GCTYPEBITS) : VAL_MAX)
-DEFINE_GDB_SYMBOL_END (VALMASK)
-
 /* Largest and smallest representable fixnum values.  These are the C
    values.  They are macros for use in static initializers.  */
 #define MOST_POSITIVE_FIXNUM (EMACS_INT_MAX >> INTTYPEBITS)
@@ -868,24 +911,6 @@ INLINE EMACS_INT
   return n;
 }
 
-INLINE struct Lisp_Symbol *
-(XSYMBOL) (Lisp_Object a)
-{
-  return lisp_h_XSYMBOL (a);
-}
-
-INLINE enum Lisp_Type
-(XTYPE) (Lisp_Object a)
-{
-  return lisp_h_XTYPE (a);
-}
-
-INLINE void *
-(XUNTAG) (Lisp_Object a, int type)
-{
-  return lisp_h_XUNTAG (a, type);
-}
-
 #else /* ! USE_LSB_TAG */
 
 /* Although compiled only if ! USE_LSB_TAG, the following functions
@@ -937,24 +962,6 @@ XFASTINT (Lisp_Object a)
   return n;
 }
 
-/* Extract A's type.  */
-INLINE enum Lisp_Type
-XTYPE (Lisp_Object a)
-{
-  EMACS_UINT i = XLI (a);
-  return USE_LSB_TAG ? i & ~VALMASK : i >> VALBITS;
-}
-
-/* Extract A's value as a symbol.  */
-INLINE struct Lisp_Symbol *
-XSYMBOL (Lisp_Object a)
-{
-  eassert (SYMBOLP (a));
-  intptr_t i = (intptr_t) XUNTAG (a, Lisp_Symbol);
-  void *p = (char *) lispsym + i;
-  return p;
-}
-
 /* Extract A's pointer value, assuming A's type is TYPE.  */
 INLINE void *
 XUNTAG (Lisp_Object a, int type)
@@ -1014,97 +1021,6 @@ clip_to_bounds (ptrdiff_t lower, EMACS_INT num, ptrdiff_t upper)
 }
 
 
-/* Extract a value or address from a Lisp_Object.  */
-
-INLINE struct Lisp_Cons *
-(XCONS) (Lisp_Object a)
-{
-  return lisp_h_XCONS (a);
-}
-
-INLINE struct Lisp_Vector *
-XVECTOR (Lisp_Object a)
-{
-  eassert (VECTORLIKEP (a));
-  return XUNTAG (a, Lisp_Vectorlike);
-}
-
-INLINE struct Lisp_String *
-XSTRING (Lisp_Object a)
-{
-  eassert (STRINGP (a));
-  return XUNTAG (a, Lisp_String);
-}
-
-/* The index of the C-defined Lisp symbol SYM.
-   This can be used in a static initializer.  */
-#define SYMBOL_INDEX(sym) i##sym
-
-INLINE struct Lisp_Float *
-XFLOAT (Lisp_Object a)
-{
-  eassert (FLOATP (a));
-  return XUNTAG (a, Lisp_Float);
-}
-
-/* Pseudovector types.  */
-
-INLINE struct Lisp_Process *
-XPROCESS (Lisp_Object a)
-{
-  eassert (PROCESSP (a));
-  return XUNTAG (a, Lisp_Vectorlike);
-}
-
-INLINE struct window *
-XWINDOW (Lisp_Object a)
-{
-  eassert (WINDOWP (a));
-  return XUNTAG (a, Lisp_Vectorlike);
-}
-
-INLINE struct terminal *
-XTERMINAL (Lisp_Object a)
-{
-  eassert (TERMINALP (a));
-  return XUNTAG (a, Lisp_Vectorlike);
-}
-
-INLINE struct Lisp_Subr *
-XSUBR (Lisp_Object a)
-{
-  eassert (SUBRP (a));
-  return XUNTAG (a, Lisp_Vectorlike);
-}
-
-INLINE struct buffer *
-XBUFFER (Lisp_Object a)
-{
-  eassert (BUFFERP (a));
-  return XUNTAG (a, Lisp_Vectorlike);
-}
-
-INLINE struct Lisp_Char_Table *
-XCHAR_TABLE (Lisp_Object a)
-{
-  eassert (CHAR_TABLE_P (a));
-  return XUNTAG (a, Lisp_Vectorlike);
-}
-
-INLINE struct Lisp_Sub_Char_Table *
-XSUB_CHAR_TABLE (Lisp_Object a)
-{
-  eassert (SUB_CHAR_TABLE_P (a));
-  return XUNTAG (a, Lisp_Vectorlike);
-}
-
-INLINE struct Lisp_Bool_Vector *
-XBOOL_VECTOR (Lisp_Object a)
-{
-  eassert (BOOL_VECTOR_P (a));
-  return XUNTAG (a, Lisp_Vectorlike);
-}
-
 /* Construct a Lisp_Object from a value or address.  */
 
 INLINE Lisp_Object
@@ -1115,18 +1031,10 @@ make_lisp_ptr (void *ptr, enum Lisp_Type type)
   return a;
 }
 
-INLINE Lisp_Object
-make_lisp_symbol (struct Lisp_Symbol *sym)
-{
-  Lisp_Object a = XIL (TAG_SYMOFFSET ((char *) sym - (char *) lispsym));
-  eassert (XSYMBOL (a) == sym);
-  return a;
-}
-
-INLINE Lisp_Object
-builtin_lisp_symbol (int index)
+INLINE bool
+(INTEGERP) (Lisp_Object x)
 {
-  return make_lisp_symbol (lispsym + index);
+  return lisp_h_INTEGERP (x);
 }
 
 #define XSETINT(a, b) ((a) = make_number (b))
@@ -1191,14 +1099,6 @@ make_pointer_integer (void *p)
   return a;
 }
 
-/* Type checking.  */
-
-INLINE void
-(CHECK_TYPE) (int ok, Lisp_Object predicate, Lisp_Object x)
-{
-  lisp_h_CHECK_TYPE (ok, predicate, x);
-}
-
 /* See the macros in intervals.h.  */
 
 typedef struct interval *INTERVAL;
@@ -1218,22 +1118,46 @@ struct GCALIGNED Lisp_Cons
     } u;
   };
 
-/* Take the car or cdr of something known to be a cons cell.  */
-/* The _addr functions shouldn't be used outside of the minimal set
-   of code that has to know what a cons cell looks like.  Other code not
-   part of the basic lisp implementation should assume that the car and cdr
-   fields are not accessible.  (What if we want to switch to
-   a copying collector someday?  Cached cons cell field addresses may be
-   invalidated at arbitrary points.)  */
-INLINE Lisp_Object *
-xcar_addr (Lisp_Object c)
+INLINE bool
+(NILP) (Lisp_Object x)
 {
-  return &XCONS (c)->car;
+  return lisp_h_NILP (x);
 }
-INLINE Lisp_Object *
-xcdr_addr (Lisp_Object c)
+
+INLINE bool
+(CONSP) (Lisp_Object x)
 {
-  return &XCONS (c)->u.cdr;
+  return lisp_h_CONSP (x);
+}
+
+INLINE void
+CHECK_CONS (Lisp_Object x)
+{
+  CHECK_TYPE (CONSP (x), Qconsp, x);
+}
+
+INLINE struct Lisp_Cons *
+(XCONS) (Lisp_Object a)
+{
+  return lisp_h_XCONS (a);
+}
+
+/* Take the car or cdr of something known to be a cons cell.  */
+/* The _addr functions shouldn't be used outside of the minimal set
+   of code that has to know what a cons cell looks like.  Other code not
+   part of the basic lisp implementation should assume that the car and cdr
+   fields are not accessible.  (What if we want to switch to
+   a copying collector someday?  Cached cons cell field addresses may be
+   invalidated at arbitrary points.)  */
+INLINE Lisp_Object *
+xcar_addr (Lisp_Object c)
+{
+  return &XCONS (c)->car;
+}
+INLINE Lisp_Object *
+xcdr_addr (Lisp_Object c)
+{
+  return &XCONS (c)->u.cdr;
 }
 
 /* Use these from normal code.  */
@@ -1307,6 +1231,25 @@ struct GCALIGNED Lisp_String
     unsigned char *data;
   };
 
+INLINE bool
+STRINGP (Lisp_Object x)
+{
+  return XTYPE (x) == Lisp_String;
+}
+
+INLINE void
+CHECK_STRING (Lisp_Object x)
+{
+  CHECK_TYPE (STRINGP (x), Qstringp, x);
+}
+
+INLINE struct Lisp_String *
+XSTRING (Lisp_Object a)
+{
+  eassert (STRINGP (a));
+  return XUNTAG (a, Lisp_String);
+}
+
 /* True if STR is a multibyte string.  */
 INLINE bool
 STRING_MULTIBYTE (Lisp_Object str)
@@ -1441,6 +1384,62 @@ struct Lisp_Vector
     Lisp_Object contents[FLEXIBLE_ARRAY_MEMBER];
   };
 
+INLINE bool
+(VECTORLIKEP) (Lisp_Object x)
+{
+  return lisp_h_VECTORLIKEP (x);
+}
+
+INLINE struct Lisp_Vector *
+XVECTOR (Lisp_Object a)
+{
+  eassert (VECTORLIKEP (a));
+  return XUNTAG (a, Lisp_Vectorlike);
+}
+
+INLINE ptrdiff_t
+ASIZE (Lisp_Object array)
+{
+  ptrdiff_t size = XVECTOR (array)->header.size;
+  eassume (0 <= size);
+  return size;
+}
+
+INLINE bool
+VECTORP (Lisp_Object x)
+{
+  return VECTORLIKEP (x) && ! (ASIZE (x) & PSEUDOVECTOR_FLAG);
+}
+
+INLINE void
+CHECK_VECTOR (Lisp_Object x)
+{
+  CHECK_TYPE (VECTORP (x), Qvectorp, x);
+}
+
+/* A pseudovector is like a vector, but has other non-Lisp components.  */
+
+INLINE bool
+PSEUDOVECTOR_TYPEP (struct vectorlike_header *a, int code)
+{
+  return ((a->size & (PSEUDOVECTOR_FLAG | PVEC_TYPE_MASK))
+	  == (PSEUDOVECTOR_FLAG | (code << PSEUDOVECTOR_AREA_BITS)));
+}
+
+/* True if A is a pseudovector whose code is CODE.  */
+INLINE bool
+PSEUDOVECTORP (Lisp_Object a, int code)
+{
+  if (! VECTORLIKEP (a))
+    return false;
+  else
+    {
+      /* Converting to struct vectorlike_header * avoids aliasing issues.  */
+      struct vectorlike_header *h = XUNTAG (a, Lisp_Vectorlike);
+      return PSEUDOVECTOR_TYPEP (h, code);
+    }
+}
+
 /* A boolvector is a kind of vectorlike, with contents like a string.  */
 
 struct Lisp_Bool_Vector
@@ -1457,6 +1456,51 @@ struct Lisp_Bool_Vector
     bits_word data[FLEXIBLE_ARRAY_MEMBER];
   };
 
+/* Some handy constants for calculating sizes
+   and offsets, mostly of vectorlike objects.   */
+
+enum
+  {
+    header_size = offsetof (struct Lisp_Vector, contents),
+    bool_header_size = offsetof (struct Lisp_Bool_Vector, data),
+    word_size = sizeof (Lisp_Object)
+  };
+
+/* The number of data words and bytes in a bool vector with SIZE bits.  */
+
+INLINE EMACS_INT
+bool_vector_words (EMACS_INT size)
+{
+  eassume (0 <= size && size <= EMACS_INT_MAX - (BITS_PER_BITS_WORD - 1));
+  return (size + BITS_PER_BITS_WORD - 1) / BITS_PER_BITS_WORD;
+}
+
+INLINE EMACS_INT
+bool_vector_bytes (EMACS_INT size)
+{
+  eassume (0 <= size && size <= EMACS_INT_MAX - (BITS_PER_BITS_WORD - 1));
+  return (size + BOOL_VECTOR_BITS_PER_CHAR - 1) / BOOL_VECTOR_BITS_PER_CHAR;
+}
+
+INLINE bool
+BOOL_VECTOR_P (Lisp_Object a)
+{
+  return PSEUDOVECTORP (a, PVEC_BOOL_VECTOR);
+}
+
+INLINE void
+CHECK_BOOL_VECTOR (Lisp_Object x)
+{
+  CHECK_TYPE (BOOL_VECTOR_P (x), Qbool_vector_p, x);
+}
+
+INLINE struct Lisp_Bool_Vector *
+XBOOL_VECTOR (Lisp_Object a)
+{
+  eassert (BOOL_VECTOR_P (a));
+  return XUNTAG (a, Lisp_Vectorlike);
+}
+
 INLINE EMACS_INT
 bool_vector_size (Lisp_Object a)
 {
@@ -1477,22 +1521,6 @@ bool_vector_uchar_data (Lisp_Object a)
   return (unsigned char *) bool_vector_data (a);
 }
 
-/* The number of data words and bytes in a bool vector with SIZE bits.  */
-
-INLINE EMACS_INT
-bool_vector_words (EMACS_INT size)
-{
-  eassume (0 <= size && size <= EMACS_INT_MAX - (BITS_PER_BITS_WORD - 1));
-  return (size + BITS_PER_BITS_WORD - 1) / BITS_PER_BITS_WORD;
-}
-
-INLINE EMACS_INT
-bool_vector_bytes (EMACS_INT size)
-{
-  eassume (0 <= size && size <= EMACS_INT_MAX - (BITS_PER_BITS_WORD - 1));
-  return (size + BOOL_VECTOR_BITS_PER_CHAR - 1) / BOOL_VECTOR_BITS_PER_CHAR;
-}
-
 /* True if A's Ith bit is set.  */
 
 INLINE bool
@@ -1525,16 +1553,6 @@ bool_vector_set (Lisp_Object a, EMACS_INT i, bool b)
     *addr &= ~ (1 << (i % BOOL_VECTOR_BITS_PER_CHAR));
 }
 
-/* Some handy constants for calculating sizes
-   and offsets, mostly of vectorlike objects.   */
-
-enum
-  {
-    header_size = offsetof (struct Lisp_Vector, contents),
-    bool_header_size = offsetof (struct Lisp_Bool_Vector, data),
-    word_size = sizeof (Lisp_Object)
-  };
-
 /* Conveniences for dealing with Lisp arrays.  */
 
 INLINE Lisp_Object
@@ -1550,14 +1568,6 @@ aref_addr (Lisp_Object array, ptrdiff_t idx)
 }
 
 INLINE ptrdiff_t
-ASIZE (Lisp_Object array)
-{
-  ptrdiff_t size = XVECTOR (array)->header.size;
-  eassume (0 <= size);
-  return size;
-}
-
-INLINE ptrdiff_t
 gc_asize (Lisp_Object array)
 {
   /* Like ASIZE, but also can be used in the garbage collector.  */
@@ -1674,6 +1684,19 @@ struct Lisp_Char_Table
     Lisp_Object extras[FLEXIBLE_ARRAY_MEMBER];
   };
 
+INLINE bool
+CHAR_TABLE_P (Lisp_Object a)
+{
+  return PSEUDOVECTORP (a, PVEC_CHAR_TABLE);
+}
+
+INLINE struct Lisp_Char_Table *
+XCHAR_TABLE (Lisp_Object a)
+{
+  eassert (CHAR_TABLE_P (a));
+  return XUNTAG (a, Lisp_Vectorlike);
+}
+
 struct Lisp_Sub_Char_Table
   {
     /* HEADER.SIZE is the vector's size field, which also holds the
@@ -1695,6 +1718,19 @@ struct Lisp_Sub_Char_Table
     Lisp_Object contents[FLEXIBLE_ARRAY_MEMBER];
   };
 
+INLINE bool
+SUB_CHAR_TABLE_P (Lisp_Object a)
+{
+  return PSEUDOVECTORP (a, PVEC_SUB_CHAR_TABLE);
+}
+
+INLINE struct Lisp_Sub_Char_Table *
+XSUB_CHAR_TABLE (Lisp_Object a)
+{
+  eassert (SUB_CHAR_TABLE_P (a));
+  return XUNTAG (a, Lisp_Vectorlike);
+}
+
 INLINE Lisp_Object
 CHAR_TABLE_REF_ASCII (Lisp_Object ct, ptrdiff_t idx)
 {
@@ -1760,6 +1796,19 @@ struct Lisp_Subr
     EMACS_INT doc;
   };
 
+INLINE bool
+SUBRP (Lisp_Object a)
+{
+  return PSEUDOVECTORP (a, PVEC_SUBR);
+}
+
+INLINE struct Lisp_Subr *
+XSUBR (Lisp_Object a)
+{
+  eassert (SUBRP (a));
+  return XUNTAG (a, Lisp_Vectorlike);
+}
+
 enum char_table_specials
   {
     /* This is the number of slots that every char table must have.  This
@@ -2070,6 +2119,25 @@ struct Lisp_Misc_Any		/* Supertype of all Misc types.  */
   unsigned spacer : 15;
 };
 
+INLINE bool
+(MISCP) (Lisp_Object x)
+{
+  return lisp_h_MISCP (x);
+}
+
+INLINE struct Lisp_Misc_Any *
+XMISCANY (Lisp_Object a)
+{
+  eassert (MISCP (a));
+  return XUNTAG (a, Lisp_Misc);
+}
+
+INLINE enum Lisp_Misc_Type
+XMISCTYPE (Lisp_Object a)
+{
+  return XMISCANY (a)->type;
+}
+
 struct Lisp_Marker
 {
   ENUM_BF (Lisp_Misc_Type) type : 16;		/* = Lisp_Misc_Marker */
@@ -2227,6 +2295,19 @@ struct Lisp_Save_Value
     } data[SAVE_VALUE_SLOTS];
   };
 
+INLINE bool
+SAVE_VALUEP (Lisp_Object x)
+{
+  return MISCP (x) && XMISCTYPE (x) == Lisp_Misc_Save_Value;
+}
+
+INLINE struct Lisp_Save_Value *
+XSAVE_VALUE (Lisp_Object a)
+{
+  eassert (SAVE_VALUEP (a));
+  return XUNTAG (a, Lisp_Misc);
+}
+
 /* Return the type of V's Nth saved value.  */
 INLINE int
 save_type (struct Lisp_Save_Value *v, int n)
@@ -2307,6 +2388,19 @@ struct Lisp_Finalizer
     Lisp_Object function;
   };
 
+INLINE bool
+FINALIZERP (Lisp_Object x)
+{
+  return MISCP (x) && XMISCTYPE (x) == Lisp_Misc_Finalizer;
+}
+
+INLINE struct Lisp_Finalizer *
+XFINALIZER (Lisp_Object a)
+{
+  eassert (FINALIZERP (a));
+  return XUNTAG (a, Lisp_Misc);
+}
+
 /* A miscellaneous object, when it's on the free list.  */
 struct Lisp_Free
   {
@@ -2338,53 +2432,44 @@ XMISC (Lisp_Object a)
   return XUNTAG (a, Lisp_Misc);
 }
 
-INLINE struct Lisp_Misc_Any *
-XMISCANY (Lisp_Object a)
-{
-  eassert (MISCP (a));
-  return & XMISC (a)->u_any;
-}
-
-INLINE enum Lisp_Misc_Type
-XMISCTYPE (Lisp_Object a)
+INLINE bool
+(MARKERP) (Lisp_Object x)
 {
-  return XMISCANY (a)->type;
+  return lisp_h_MARKERP (x);
 }
 
 INLINE struct Lisp_Marker *
 XMARKER (Lisp_Object a)
 {
   eassert (MARKERP (a));
-  return & XMISC (a)->u_marker;
+  return XUNTAG (a, Lisp_Misc);
 }
 
-INLINE struct Lisp_Overlay *
-XOVERLAY (Lisp_Object a)
+INLINE bool
+OVERLAYP (Lisp_Object x)
 {
-  eassert (OVERLAYP (a));
-  return & XMISC (a)->u_overlay;
+  return MISCP (x) && XMISCTYPE (x) == Lisp_Misc_Overlay;
 }
 
-INLINE struct Lisp_Save_Value *
-XSAVE_VALUE (Lisp_Object a)
+INLINE struct Lisp_Overlay *
+XOVERLAY (Lisp_Object a)
 {
-  eassert (SAVE_VALUEP (a));
-  return & XMISC (a)->u_save_value;
+  eassert (OVERLAYP (a));
+  return XUNTAG (a, Lisp_Misc);
 }
 
-INLINE struct Lisp_Finalizer *
-XFINALIZER (Lisp_Object a)
+#ifdef HAVE_MODULES
+INLINE bool
+USER_PTRP (Lisp_Object x)
 {
-  eassert (FINALIZERP (a));
-  return & XMISC (a)->u_finalizer;
+  return MISCP (x) && XMISCTYPE (x) == Lisp_Misc_User_Ptr;
 }
 
-#ifdef HAVE_MODULES
 INLINE struct Lisp_User_Ptr *
 XUSER_PTR (Lisp_Object a)
 {
   eassert (USER_PTRP (a));
-  return & XMISC (a)->u_user_ptr;
+  return XUNTAG (a, Lisp_Misc);
 }
 #endif
 
@@ -2502,6 +2587,12 @@ XFWDTYPE (union Lisp_Fwd *a)
   return a->u_intfwd.type;
 }
 
+INLINE bool
+BUFFER_OBJFWDP (union Lisp_Fwd *a)
+{
+  return XFWDTYPE (a) == Lisp_Fwd_Buffer_Obj;
+}
+
 INLINE struct Lisp_Buffer_Objfwd *
 XBUFFER_OBJFWD (union Lisp_Fwd *a)
 {
@@ -2519,6 +2610,19 @@ struct Lisp_Float
     } u;
   };
 
+INLINE bool
+(FLOATP) (Lisp_Object x)
+{
+  return lisp_h_FLOATP (x);
+}
+
+INLINE struct Lisp_Float *
+XFLOAT (Lisp_Object a)
+{
+  eassert (FLOATP (a));
+  return XUNTAG (a, Lisp_Float);
+}
+
 INLINE double
 XFLOAT_DATA (Lisp_Object f)
 {
@@ -2582,12 +2686,6 @@ enum char_bits
 /* Data type checking.  */
 
 INLINE bool
-(NILP) (Lisp_Object x)
-{
-  return lisp_h_NILP (x);
-}
-
-INLINE bool
 NUMBERP (Lisp_Object x)
 {
   return INTEGERP (x) || FLOATP (x);
@@ -2610,109 +2708,11 @@ RANGED_INTEGERP (intmax_t lo, Lisp_Object x, intmax_t hi)
    && XINT (x) <= TYPE_MAXIMUM (type))
 
 INLINE bool
-(CONSP) (Lisp_Object x)
-{
-  return lisp_h_CONSP (x);
-}
-INLINE bool
-(FLOATP) (Lisp_Object x)
-{
-  return lisp_h_FLOATP (x);
-}
-INLINE bool
-(MISCP) (Lisp_Object x)
-{
-  return lisp_h_MISCP (x);
-}
-INLINE bool
-(SYMBOLP) (Lisp_Object x)
-{
-  return lisp_h_SYMBOLP (x);
-}
-INLINE bool
-(INTEGERP) (Lisp_Object x)
-{
-  return lisp_h_INTEGERP (x);
-}
-INLINE bool
-(VECTORLIKEP) (Lisp_Object x)
-{
-  return lisp_h_VECTORLIKEP (x);
-}
-INLINE bool
-(MARKERP) (Lisp_Object x)
-{
-  return lisp_h_MARKERP (x);
-}
-
-INLINE bool
-STRINGP (Lisp_Object x)
-{
-  return XTYPE (x) == Lisp_String;
-}
-INLINE bool
-VECTORP (Lisp_Object x)
-{
-  return VECTORLIKEP (x) && ! (ASIZE (x) & PSEUDOVECTOR_FLAG);
-}
-INLINE bool
-OVERLAYP (Lisp_Object x)
-{
-  return MISCP (x) && XMISCTYPE (x) == Lisp_Misc_Overlay;
-}
-INLINE bool
-SAVE_VALUEP (Lisp_Object x)
-{
-  return MISCP (x) && XMISCTYPE (x) == Lisp_Misc_Save_Value;
-}
-
-INLINE bool
-FINALIZERP (Lisp_Object x)
-{
-  return MISCP (x) && XMISCTYPE (x) == Lisp_Misc_Finalizer;
-}
-
-#ifdef HAVE_MODULES
-INLINE bool
-USER_PTRP (Lisp_Object x)
-{
-  return MISCP (x) && XMISCTYPE (x) == Lisp_Misc_User_Ptr;
-}
-#endif
-
-INLINE bool
 AUTOLOADP (Lisp_Object x)
 {
   return CONSP (x) && EQ (Qautoload, XCAR (x));
 }
 
-INLINE bool
-BUFFER_OBJFWDP (union Lisp_Fwd *a)
-{
-  return XFWDTYPE (a) == Lisp_Fwd_Buffer_Obj;
-}
-
-INLINE bool
-PSEUDOVECTOR_TYPEP (struct vectorlike_header *a, int code)
-{
-  return ((a->size & (PSEUDOVECTOR_FLAG | PVEC_TYPE_MASK))
-	  == (PSEUDOVECTOR_FLAG | (code << PSEUDOVECTOR_AREA_BITS)));
-}
-
-/* True if A is a pseudovector whose code is CODE.  */
-INLINE bool
-PSEUDOVECTORP (Lisp_Object a, int code)
-{
-  if (! VECTORLIKEP (a))
-    return false;
-  else
-    {
-      /* Converting to struct vectorlike_header * avoids aliasing issues.  */
-      struct vectorlike_header *h = XUNTAG (a, Lisp_Vectorlike);
-      return PSEUDOVECTOR_TYPEP (h, code);
-    }
-}
-
 
 /* Test for specific pseudovector types.  */
 
@@ -2723,60 +2723,12 @@ WINDOW_CONFIGURATIONP (Lisp_Object a)
 }
 
 INLINE bool
-PROCESSP (Lisp_Object a)
-{
-  return PSEUDOVECTORP (a, PVEC_PROCESS);
-}
-
-INLINE bool
-WINDOWP (Lisp_Object a)
-{
-  return PSEUDOVECTORP (a, PVEC_WINDOW);
-}
-
-INLINE bool
-TERMINALP (Lisp_Object a)
-{
-  return PSEUDOVECTORP (a, PVEC_TERMINAL);
-}
-
-INLINE bool
-SUBRP (Lisp_Object a)
-{
-  return PSEUDOVECTORP (a, PVEC_SUBR);
-}
-
-INLINE bool
 COMPILEDP (Lisp_Object a)
 {
   return PSEUDOVECTORP (a, PVEC_COMPILED);
 }
 
 INLINE bool
-BUFFERP (Lisp_Object a)
-{
-  return PSEUDOVECTORP (a, PVEC_BUFFER);
-}
-
-INLINE bool
-CHAR_TABLE_P (Lisp_Object a)
-{
-  return PSEUDOVECTORP (a, PVEC_CHAR_TABLE);
-}
-
-INLINE bool
-SUB_CHAR_TABLE_P (Lisp_Object a)
-{
-  return PSEUDOVECTORP (a, PVEC_SUB_CHAR_TABLE);
-}
-
-INLINE bool
-BOOL_VECTOR_P (Lisp_Object a)
-{
-  return PSEUDOVECTORP (a, PVEC_BOOL_VECTOR);
-}
-
-INLINE bool
 FRAMEP (Lisp_Object a)
 {
   return PSEUDOVECTORP (a, PVEC_FRAME);
@@ -2809,42 +2761,16 @@ INLINE void
 }
 
 INLINE void
-(CHECK_SYMBOL) (Lisp_Object x)
-{
- lisp_h_CHECK_SYMBOL (x);
-}
-
-INLINE void
 (CHECK_NUMBER) (Lisp_Object x)
 {
   lisp_h_CHECK_NUMBER (x);
 }
 
 INLINE void
-CHECK_STRING (Lisp_Object x)
-{
-  CHECK_TYPE (STRINGP (x), Qstringp, x);
-}
-INLINE void
 CHECK_STRING_CAR (Lisp_Object x)
 {
   CHECK_TYPE (STRINGP (XCAR (x)), Qstringp, XCAR (x));
 }
-INLINE void
-CHECK_CONS (Lisp_Object x)
-{
-  CHECK_TYPE (CONSP (x), Qconsp, x);
-}
-INLINE void
-CHECK_VECTOR (Lisp_Object x)
-{
-  CHECK_TYPE (VECTORP (x), Qvectorp, x);
-}
-INLINE void
-CHECK_BOOL_VECTOR (Lisp_Object x)
-{
-  CHECK_TYPE (BOOL_VECTOR_P (x), Qbool_vector_p, x);
-}
 /* This is a bit special because we always need size afterwards.  */
 INLINE ptrdiff_t
 CHECK_VECTOR_OR_STRING (Lisp_Object x)
@@ -2861,23 +2787,6 @@ CHECK_ARRAY (Lisp_Object x, Lisp_Object predicate)
   CHECK_TYPE (ARRAYP (x), predicate, x);
 }
 INLINE void
-CHECK_BUFFER (Lisp_Object x)
-{
-  CHECK_TYPE (BUFFERP (x), Qbufferp, x);
-}
-INLINE void
-CHECK_WINDOW (Lisp_Object x)
-{
-  CHECK_TYPE (WINDOWP (x), Qwindowp, x);
-}
-#ifdef subprocesses
-INLINE void
-CHECK_PROCESS (Lisp_Object x)
-{
-  CHECK_TYPE (PROCESSP (x), Qprocessp, x);
-}
-#endif
-INLINE void
 CHECK_NATNUM (Lisp_Object x)
 {
   CHECK_TYPE (NATNUMP (x), Qwholenump, x);
@@ -3380,6 +3289,8 @@ set_sub_char_table_contents (Lisp_Object table, ptrdiff_t idx, Lisp_Object val)
 }
 
 /* Defined in data.c.  */
+extern void notify_variable_watchers (Lisp_Object, Lisp_Object,
+				      Lisp_Object, Lisp_Object);
 extern Lisp_Object indirect_function (Lisp_Object);
 extern Lisp_Object find_symbol_value (Lisp_Object);
 enum Arith_Comparison {
@@ -4194,6 +4105,7 @@ extern bool inhibit_window_system;
 extern bool running_asynch_code;
 
 /* Defined in process.c.  */
+struct Lisp_Process;
 extern void kill_buffer_processes (Lisp_Object);
 extern int wait_reading_process_output (intmax_t, int, int, bool, Lisp_Object,
 					struct Lisp_Process *, int);
diff --git a/src/process.h b/src/process.h
index 24c6282..8f28ddb 100644
--- a/src/process.h
+++ b/src/process.h
@@ -199,6 +199,25 @@ struct Lisp_Process
 #endif
 };
 
+INLINE bool
+PROCESSP (Lisp_Object a)
+{
+  return PSEUDOVECTORP (a, PVEC_PROCESS);
+}
+
+INLINE void
+CHECK_PROCESS (Lisp_Object x)
+{
+  CHECK_TYPE (PROCESSP (x), Qprocessp, x);
+}
+
+INLINE struct Lisp_Process *
+XPROCESS (Lisp_Object a)
+{
+  eassert (PROCESSP (a));
+  return XUNTAG (a, Lisp_Vectorlike);
+}
+
 /* Every field in the preceding structure except for the first two
    must be a Lisp_Object, for GC's sake.  */
 
diff --git a/src/termhooks.h b/src/termhooks.h
index 03416cb..81e06d9 100644
--- a/src/termhooks.h
+++ b/src/termhooks.h
@@ -654,6 +654,19 @@ struct terminal
   void (*delete_terminal_hook) (struct terminal *);
 };
 
+INLINE bool
+TERMINALP (Lisp_Object a)
+{
+  return PSEUDOVECTORP (a, PVEC_TERMINAL);
+}
+
+INLINE struct terminal *
+XTERMINAL (Lisp_Object a)
+{
+  eassert (TERMINALP (a));
+  return XUNTAG (a, Lisp_Vectorlike);
+}
+
 /* Most code should use these functions to set Lisp fields in struct
    terminal.  */
 INLINE void
diff --git a/src/window.h b/src/window.h
index 4a102f2..717f972 100644
--- a/src/window.h
+++ b/src/window.h
@@ -397,6 +397,25 @@ struct window
     ptrdiff_t window_end_bytepos;
   };
 
+INLINE bool
+WINDOWP (Lisp_Object a)
+{
+  return PSEUDOVECTORP (a, PVEC_WINDOW);
+}
+
+INLINE void
+CHECK_WINDOW (Lisp_Object x)
+{
+  CHECK_TYPE (WINDOWP (x), Qwindowp, x);
+}
+
+INLINE struct window *
+XWINDOW (Lisp_Object a)
+{
+  eassert (WINDOWP (a));
+  return XUNTAG (a, Lisp_Vectorlike);
+}
+
 /* Most code should use these functions to set Lisp fields in struct
    window.  */
 INLINE void
-- 
2.9.3