unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
* Re: emacs-26 9e59de9: Use GCALIGNED properly for GCC
       [not found] ` <20171109031208.D2CAF2033E@vcs0.savannah.gnu.org>
@ 2017-11-09 23:31   ` Glenn Morris
  2017-11-10  7:10     ` martin rudalics
  0 siblings, 1 reply; 20+ messages in thread
From: Glenn Morris @ 2017-11-09 23:31 UTC (permalink / raw)
  To: emacs-devel; +Cc: Paul Eggert

Paul Eggert wrote:

> branch: emacs-26
> commit 9e59de9449b53c3ecd85b624c11360ba9cafee75
[...]
>     Use GCALIGNED properly for GCC

This seems to cause build failure on 32-bit GNU/Linux.
build.i686-linux on hydra fails since this commit was merged to master:

https://hydra.nixos.org/eval/1408828

(Sadly the hydra build logs seem to be missing at the moment, so there's
nothing informative there.)

I reproduced the issue on 64-bit RHEL7 building the emacs-26 branch with

./configure --without-all --without-x CC="gcc -m32"

The command "./temacs --batch --load loadup bootstrap" simply exits
immediately with no output and status 0.

With 9e59de9 reverted, the same build completes ok.



^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: emacs-26 9e59de9: Use GCALIGNED properly for GCC
  2017-11-09 23:31   ` emacs-26 9e59de9: Use GCALIGNED properly for GCC Glenn Morris
@ 2017-11-10  7:10     ` martin rudalics
  2017-11-10  8:06       ` Eli Zaretskii
  0 siblings, 1 reply; 20+ messages in thread
From: martin rudalics @ 2017-11-10  7:10 UTC (permalink / raw)
  To: Glenn Morris, emacs-devel; +Cc: Paul Eggert

... and trying my usual 32-bit build of the release branch on Windows
currently fails as

(gdb) run --batch  --load loadup bootstrap
Starting program: c:\emacs-git\release\dbg\src\temacs.exe --batch  --load loadup bootstrap
[New Thread 3424.0xcf4]

Breakpoint 1, terminate_due_to_signal (sig=22, backtrace_limit=2147483647) at ../../src/emacs.c:364
364	  signal (sig, SIG_DFL);
(gdb) bt
#0  terminate_due_to_signal (sig=22, backtrace_limit=2147483647) at ../../src/emacs.c:364
#1  0x01184515 in die (msg=0x150ce54 <PSEUDOVECTOR_FLAG+48> "XTYPE (a) == type && XUNTAG (a, type) == ptr", file=0x150cdf0 <Qzlib+4> "../../src/lisp.h", line=1068) at ../../src/alloc.c:7431
#2  0x010fdc0e in make_lisp_ptr (ptr=0x12b3e94 <Sinternal_make_lisp_face>, type=Lisp_Vectorlike) at ../../src/lisp.h:1068
#3  0x011de6b2 in defsubr (sname=0x12b3e94 <Sinternal_make_lisp_face>) at ../../src/lread.c:4354
#4  0x010fd66a in syms_of_xfaces () at ../../src/xfaces.c:6460
#5  0x0110423a in main (argc=5, argv=0xa33fd0) at ../../src/emacs.c:1220
(gdb)

Reverting to b9d7c902603a49d2624bdd35efdfba1785a4bce5 makes the build
succeed again.

martin



^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: emacs-26 9e59de9: Use GCALIGNED properly for GCC
  2017-11-10  7:10     ` martin rudalics
@ 2017-11-10  8:06       ` Eli Zaretskii
  2017-11-10  8:26         ` Paul Eggert
  0 siblings, 1 reply; 20+ messages in thread
From: Eli Zaretskii @ 2017-11-10  8:06 UTC (permalink / raw)
  To: martin rudalics; +Cc: rgm, eggert, emacs-devel

> Date: Fri, 10 Nov 2017 08:10:54 +0100
> From: martin rudalics <rudalics@gmx.at>
> Cc: Paul Eggert <eggert@cs.ucla.edu>
> 
> ... and trying my usual 32-bit build of the release branch on Windows
> currently fails as

Paul, maybe we should simply go back a few notches and not mark
main_thread as GCALIGNED, except on that single platform which needed
it (i.e. via #ifdef)?  Then we could return all the other symbols to
their previous syntax.

Or maybe we should move GCALIGNED to yet another position, like at the
beginning or the end of the whole construct.  Like this:

   GCALIGNED struct foo FOO;
or
   struct foo FOO GCALIGNED;

Not sure what else can we do, but this seems to be an exceptionally
fragile feature, at least with GCC 7 that many people are using.



^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: emacs-26 9e59de9: Use GCALIGNED properly for GCC
  2017-11-10  8:06       ` Eli Zaretskii
@ 2017-11-10  8:26         ` Paul Eggert
  2017-11-10  9:57           ` Eli Zaretskii
  2017-11-11  7:08           ` Paul Eggert
  0 siblings, 2 replies; 20+ messages in thread
From: Paul Eggert @ 2017-11-10  8:26 UTC (permalink / raw)
  To: Eli Zaretskii, martin rudalics; +Cc: rgm, emacs-devel

Eli Zaretskii wrote:
> Paul, maybe we should simply go back a few notches and not mark
> main_thread as GCALIGNED, except on that single platform which needed
> it (i.e. via #ifdef)?  Then we could return all the other symbols to
> their previous syntax.
> 
> Or maybe we should move GCALIGNED to yet another position, like at the
> beginning or the end of the whole construct.  Like this:
> 
>     GCALIGNED struct foo FOO;
> or
>     struct foo FOO GCALIGNED;
> 
> Not sure what else can we do, but this seems to be an exceptionally
> fragile feature, at least with GCC 7 that many people are using.

I've investigated this further, and neither solution is likely to work. It is 
merely the luck of the draw that we have seen the bug only on that platform so 
far, and a similar bug is likely to occur on other platforms. Neither GCALIGNED 
syntax works in general (see GCC bug 82914) and we've seen examples of failures 
with either syntax.

I have thought of a solution that fixes the problem by dropping use of GCALIGNED 
and instead using classic C unions along with 'char alignas (8)'. The idea is to 
gcalign a 'struct foo' this way:

    union gcaligned_foo { struct foo s; char alignas (8) gcaligned; };

Something like this should work on all platforms that Emacs ports to. I plan to 
work on a first cut tomorrow.



^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: emacs-26 9e59de9: Use GCALIGNED properly for GCC
  2017-11-10  8:26         ` Paul Eggert
@ 2017-11-10  9:57           ` Eli Zaretskii
  2017-11-10 16:23             ` Stefan Monnier
  2017-11-11  7:08           ` Paul Eggert
  1 sibling, 1 reply; 20+ messages in thread
From: Eli Zaretskii @ 2017-11-10  9:57 UTC (permalink / raw)
  To: Paul Eggert; +Cc: rudalics, emacs-devel, rgm

> Cc: rgm@gnu.org, emacs-devel@gnu.org
> From: Paul Eggert <eggert@cs.ucla.edu>
> Date: Fri, 10 Nov 2017 00:26:19 -0800
> 
> I have thought of a solution that fixes the problem by dropping use of GCALIGNED 
> and instead using classic C unions along with 'char alignas (8)'. The idea is to 
> gcalign a 'struct foo' this way:
> 
>     union gcaligned_foo { struct foo s; char alignas (8) gcaligned; };

Wouldn't it be more reliable to use something like

  union gcaligned_foo { struct foo s; int64_t gcaligned; };

IOW, should we rely on alignas?  There could be dragons there too, no?

> Something like this should work on all platforms that Emacs ports to. I plan to 
> work on a first cut tomorrow.

Thanks.



^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: emacs-26 9e59de9: Use GCALIGNED properly for GCC
  2017-11-10  9:57           ` Eli Zaretskii
@ 2017-11-10 16:23             ` Stefan Monnier
  2017-11-10 17:58               ` Paul Eggert
  0 siblings, 1 reply; 20+ messages in thread
From: Stefan Monnier @ 2017-11-10 16:23 UTC (permalink / raw)
  To: emacs-devel

>   union gcaligned_foo { struct foo s; int64_t gcaligned; };

Are int64_t necessarily aligned on multiples of 8 on 32bit platforms?

> IOW, should we rely on alignas?  There could be dragons there too, no?

FWIW, for the dummy alignment thingy I wouldn't use `char` (I wouldn't be
surprised to see errors in compilers when asking to align on multiples
of N for objects smaller than N), so maybe

    #define gc_aligned(typename) \
       union { typename s; int64_t alignas (GCALIGNMENT) dummy; };

I'm not super happy about the "64" in there (which hardcodes basically
the value of GCALIGNMENT).  Depending on how alignas can be used to
impose alignment of an array, we could try:

    typedef char gcsized_t[GCALIGNMENT];
    #define gc_aligned(typename) \
       union { typename s; gcsized_t alignas (GCALIGNMENT) dummy; }

but maybe getting rid of this 64 is not that important.


        Stefan




^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: emacs-26 9e59de9: Use GCALIGNED properly for GCC
  2017-11-10 16:23             ` Stefan Monnier
@ 2017-11-10 17:58               ` Paul Eggert
  2017-11-10 18:02                 ` Stefan Monnier
  0 siblings, 1 reply; 20+ messages in thread
From: Paul Eggert @ 2017-11-10 17:58 UTC (permalink / raw)
  To: Stefan Monnier, emacs-devel

Stefan Monnier wrote:
>>    union gcaligned_foo { struct foo s; int64_t gcaligned; };
> 
> Are int64_t necessarily aligned on multiples of 8 on 32bit platforms?

No, unfortunately.

>> IOW, should we rely on alignas?  There could be dragons there too, no?
> 
> FWIW, for the dummy alignment thingy I wouldn't use `char` (I wouldn't be
> surprised to see errors in compilers when asking to align on multiples
> of N for objects smaller than N), so maybe
> 
>      #define gc_aligned(typename) \
>         union { typename s; int64_t alignas (GCALIGNMENT) dummy; };

That does not work either, alas, as C11 says 'alignas (8)' is an error when the 
natural alignment of the object is less than 8. This is one of the problems that 
we have encountered in earlier attempts to fix this bug. 'char alignas (8)' 
avoids this problem.

If we run into a platform where alignas (8) does not work either natively or via 
Gnulib emulation, the patch I'm working on has a 'verify' check that should 
result in a build failure. Although I have some ideas for fixing the situation 
if it arises, they would add some complexity (and would depend on the details of 
any problematic hosts), and I'd rather avoid this if possible.



^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: emacs-26 9e59de9: Use GCALIGNED properly for GCC
  2017-11-10 17:58               ` Paul Eggert
@ 2017-11-10 18:02                 ` Stefan Monnier
  2017-11-10 18:11                   ` Philipp Stephani
  0 siblings, 1 reply; 20+ messages in thread
From: Stefan Monnier @ 2017-11-10 18:02 UTC (permalink / raw)
  To: emacs-devel

>>> union gcaligned_foo { struct foo s; int64_t gcaligned; };
>> Are int64_t necessarily aligned on multiples of 8 on 32bit platforms?
> No, unfortunately.

That was my impression as well.

> That does not work either, alas, as C11 says 'alignas (8)' is an error when
> the natural alignment of the object is less than 8. This is one of the
> problems that we have encountered in earlier attempts to fix this bug. 'char
> alignas (8)' avoids this problem.

I don't follow: the natural alignment for `char` is definitely less than
8, so if "'alignas (8)' is an error when the natural alignment of the
object is less than 8", how can "char alignas (8)" avoid the problem?


        Stefan




^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: emacs-26 9e59de9: Use GCALIGNED properly for GCC
  2017-11-10 18:02                 ` Stefan Monnier
@ 2017-11-10 18:11                   ` Philipp Stephani
  2017-11-10 19:19                     ` Paul Eggert
  0 siblings, 1 reply; 20+ messages in thread
From: Philipp Stephani @ 2017-11-10 18:11 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: emacs-devel

[-- Attachment #1: Type: text/plain, Size: 901 bytes --]

Stefan Monnier <monnier@iro.umontreal.ca> schrieb am Fr., 10. Nov. 2017 um
19:03 Uhr:

> >>> union gcaligned_foo { struct foo s; int64_t gcaligned; };
> >> Are int64_t necessarily aligned on multiples of 8 on 32bit platforms?
> > No, unfortunately.
>
> That was my impression as well.
>
> > That does not work either, alas, as C11 says 'alignas (8)' is an error
> when
> > the natural alignment of the object is less than 8. This is one of the
> > problems that we have encountered in earlier attempts to fix this bug.
> 'char
> > alignas (8)' avoids this problem.
>
> I don't follow: the natural alignment for `char` is definitely less than
> 8, so if "'alignas (8)' is an error when the natural alignment of the
> object is less than 8", how can "char alignas (8)" avoid the problem?
>
>
It's the other way round: alignas(8) is an error when the natural alignment
of the object is *greater* than 8.

[-- Attachment #2: Type: text/html, Size: 1306 bytes --]

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: emacs-26 9e59de9: Use GCALIGNED properly for GCC
  2017-11-10 18:11                   ` Philipp Stephani
@ 2017-11-10 19:19                     ` Paul Eggert
  2017-11-10 20:31                       ` Stefan Monnier
  0 siblings, 1 reply; 20+ messages in thread
From: Paul Eggert @ 2017-11-10 19:19 UTC (permalink / raw)
  To: Philipp Stephani, Stefan Monnier; +Cc: emacs-devel

Philipp Stephani wrote:
> It's the other way round: alignas(8) is an error when the natural alignment
> of the object is*greater*  than 8.

Yes, sorry, I misstated it backwards.




^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: emacs-26 9e59de9: Use GCALIGNED properly for GCC
  2017-11-10 19:19                     ` Paul Eggert
@ 2017-11-10 20:31                       ` Stefan Monnier
  2017-11-10 20:45                         ` Paul Eggert
  0 siblings, 1 reply; 20+ messages in thread
From: Stefan Monnier @ 2017-11-10 20:31 UTC (permalink / raw)
  To: Paul Eggert; +Cc: Philipp Stephani, emacs-devel

>> It's the other way round: alignas(8) is an error when the natural alignment
>> of the object is*greater*  than 8.
> Yes, sorry, I misstated it backwards.

Then I don't understand what you meant by "that does not work either".


        Stefan



^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: emacs-26 9e59de9: Use GCALIGNED properly for GCC
  2017-11-10 20:31                       ` Stefan Monnier
@ 2017-11-10 20:45                         ` Paul Eggert
  0 siblings, 0 replies; 20+ messages in thread
From: Paul Eggert @ 2017-11-10 20:45 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: Philipp Stephani, emacs-devel

Stefan Monnier wrote:
> Then I don't understand what you meant by "that does not work either".

I was confused (:-). I suppose I was worried about the admittedly unlikely 
possibility of a platform where alignof (int64_t) exceeds 8. This worry stemmed 
from an earlier iteration of this fix, where we ran into such a type on 
MS-Windows. Although perhaps I'm worrying too much, the point remains that 
because int64_t's alignment is not always a multiple of 8, using int64_t for 
alignment would not suffice for platforms where alignas does not work.

Also, there's at least one type (struct vectorlike_header) where alignment is 
convenient, and where the type's size is smaller than int64_t on some platforms, 
so using int64_t for alignment there would cause objects of this type (and of 
its containing types) to grow unnecessarily.



^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: emacs-26 9e59de9: Use GCALIGNED properly for GCC
  2017-11-10  8:26         ` Paul Eggert
  2017-11-10  9:57           ` Eli Zaretskii
@ 2017-11-11  7:08           ` Paul Eggert
  2017-11-11  7:57             ` Paul Eggert
  2017-11-11  8:33             ` martin rudalics
  1 sibling, 2 replies; 20+ messages in thread
From: Paul Eggert @ 2017-11-11  7:08 UTC (permalink / raw)
  To: Eli Zaretskii, martin rudalics; +Cc: rgm, emacs-devel

[-- Attachment #1: Type: text/plain, Size: 579 bytes --]

Paul Eggert wrote:

> I have thought of a solution that fixes the problem by dropping use of GCALIGNED 
> and instead using classic C unions along with 'char alignas (8)'.

Patches attached. They work for me on various platforms including gcc -m32 on 
Fedora 26 x86-64 (which is close to the platform Glenn mentioned). The 2nd patch 
does the real work: most of it consists of changing private accessors to account 
for the newly-introduced unions. It shrinks the source code a bit, which is a 
good sign. I plan to test a bit more before installing; comments welcome.

[-- Attachment #2: 0001-Change-vectorlike-from-struct-to-union.txt --]
[-- Type: text/plain, Size: 12235 bytes --]

From c92462e52433c422d41c5e5aa177f9513eb517e3 Mon Sep 17 00:00:00 2001
From: Paul Eggert <eggert@cs.ucla.edu>
Date: Fri, 10 Nov 2017 17:37:50 -0800
Subject: [PATCH 1/2] Change vectorlike from struct to union

* src/lisp.h (vectorlike_headed): Change from struct to union.
All uses changed.  Since it has only one member, this does not
change semantics.  This is designed to simplify future changes
needed to fix bugs like Bug#29040.  All uses changed.
---
 doc/lispref/internals.texi |  4 ++--
 src/buffer.h               |  2 +-
 src/font.h                 |  6 +++---
 src/frame.h                |  2 +-
 src/lisp.h                 | 28 ++++++++++++++--------------
 src/process.h              |  2 +-
 src/termhooks.h            |  2 +-
 src/thread.h               |  6 +++---
 src/w32term.h              |  2 +-
 src/window.c               |  8 ++++----
 src/window.h               |  2 +-
 src/xterm.h                |  2 +-
 src/xwidget.h              |  4 ++--
 13 files changed, 35 insertions(+), 35 deletions(-)

diff --git a/doc/lispref/internals.texi b/doc/lispref/internals.texi
index 663d0fd92b..b0348e74d4 100644
--- a/doc/lispref/internals.texi
+++ b/doc/lispref/internals.texi
@@ -248,7 +248,7 @@ Garbage Collection
 @cindex storage of vector-like Lisp objects
   Beyond the basic vector, a lot of objects like window, buffer, and
 frame are managed as if they were vectors.  The corresponding C data
-structures include the @code{struct vectorlike_header} field whose
+structures include the @code{union vectorlike_header} field whose
 @code{size} member contains the subtype enumerated by @code{enum pvec_type}
 and an information about how many @code{Lisp_Object} fields this structure
 contains and what the size of the rest data is.  This information is
@@ -1085,7 +1085,7 @@ Buffer Internals
 
 @table @code
 @item header
-A header of type @code{struct vectorlike_header} is common to all
+A header of type @code{union vectorlike_header} is common to all
 vectorlike objects.
 
 @item own_text
diff --git a/src/buffer.h b/src/buffer.h
index ac7c5a5467..46c7c6e5ad 100644
--- a/src/buffer.h
+++ b/src/buffer.h
@@ -504,7 +504,7 @@ struct buffer_text
 
 struct buffer
 {
-  struct vectorlike_header header;
+  union vectorlike_header header;
 
   /* The name of this buffer.  */
   Lisp_Object name_;
diff --git a/src/font.h b/src/font.h
index 8f2e27f0ed..43d6f67e3e 100644
--- a/src/font.h
+++ b/src/font.h
@@ -244,7 +244,7 @@ enum font_property_index
 
 struct font_spec
 {
-  struct vectorlike_header header;
+  union vectorlike_header header;
   Lisp_Object props[FONT_SPEC_MAX];
 };
 
@@ -252,7 +252,7 @@ struct font_spec
 
 struct font_entity
 {
-  struct vectorlike_header header;
+  union vectorlike_header header;
   Lisp_Object props[FONT_ENTITY_MAX];
 };
 
@@ -265,7 +265,7 @@ struct font_entity
 
 struct font
 {
-  struct vectorlike_header header;
+  union vectorlike_header header;
 
   /* All Lisp_Object components must come first.
      That ensures they are all aligned normally.  */
diff --git a/src/frame.h b/src/frame.h
index e610fc768d..a3b7763643 100644
--- a/src/frame.h
+++ b/src/frame.h
@@ -79,7 +79,7 @@ enum ns_appearance_type
 
 struct frame
 {
-  struct vectorlike_header header;
+  union vectorlike_header header;
 
   /* All Lisp_Object components must come first.
      That ensures they are all aligned normally.  */
diff --git a/src/lisp.h b/src/lisp.h
index 015346858b..1d6fd5a4fe 100644
--- a/src/lisp.h
+++ b/src/lisp.h
@@ -796,11 +796,11 @@ struct Lisp_Symbol
 /* Header of vector-like objects.  This documents the layout constraints on
    vectors and pseudovectors (objects of PVEC_xxx subtype).  It also prevents
    compilers from being fooled by Emacs's type punning: XSETPSEUDOVECTOR
-   and PSEUDOVECTORP cast their pointers to struct vectorlike_header *,
+   and PSEUDOVECTORP cast their pointers to union vectorlike_header *,
    because when two such pointers potentially alias, a compiler won't
    incorrectly reorder loads and stores to their size fields.  See
    Bug#8546.  */
-struct vectorlike_header
+union vectorlike_header
   {
     /* The only field contains various pieces of information:
        - The MSB (ARRAY_MARK_FLAG) holds the gcmarkbit.
@@ -1094,10 +1094,10 @@ INLINE bool
 		       | ((restsize) << PSEUDOVECTOR_SIZE_BITS) \
 		       | (lispsize)))
 
-/* The cast to struct vectorlike_header * avoids aliasing issues.  */
+/* The cast to union vectorlike_header * avoids aliasing issues.  */
 #define XSETPSEUDOVECTOR(a, b, code) \
   XSETTYPED_PSEUDOVECTOR (a, b,					\
-			  (((struct vectorlike_header *)	\
+			  (((union vectorlike_header *)	\
 			    XUNTAG (a, Lisp_Vectorlike))	\
 			   ->size),				\
 			  code)
@@ -1399,7 +1399,7 @@ STRING_SET_CHARS (Lisp_Object string, ptrdiff_t newsize)
 
 struct Lisp_Vector
   {
-    struct vectorlike_header header;
+    union vectorlike_header header;
     Lisp_Object contents[FLEXIBLE_ARRAY_MEMBER];
   };
 
@@ -1456,7 +1456,7 @@ PSEUDOVECTOR_TYPE (struct Lisp_Vector *v)
 
 /* Can't be used with PVEC_NORMAL_VECTOR.  */
 INLINE bool
-PSEUDOVECTOR_TYPEP (struct vectorlike_header *a, enum pvec_type code)
+PSEUDOVECTOR_TYPEP (union vectorlike_header *a, enum pvec_type code)
 {
   /* We don't use PSEUDOVECTOR_TYPE here so as to avoid a shift
    * operation when `code' is known.  */
@@ -1472,8 +1472,8 @@ PSEUDOVECTORP (Lisp_Object a, int code)
     return false;
   else
     {
-      /* Converting to struct vectorlike_header * avoids aliasing issues.  */
-      struct vectorlike_header *h = XUNTAG (a, Lisp_Vectorlike);
+      /* Converting to union vectorlike_header * avoids aliasing issues.  */
+      union vectorlike_header *h = XUNTAG (a, Lisp_Vectorlike);
       return PSEUDOVECTOR_TYPEP (h, code);
     }
 }
@@ -1484,7 +1484,7 @@ struct Lisp_Bool_Vector
   {
     /* HEADER.SIZE is the vector's size field.  It doesn't have the real size,
        just the subtype information.  */
-    struct vectorlike_header header;
+    union vectorlike_header header;
     /* This is the size in bits.  */
     EMACS_INT size;
     /* The actual bits, packed into bytes.
@@ -1697,7 +1697,7 @@ struct Lisp_Char_Table
        pseudovector type information.  It holds the size, too.
        The size counts the defalt, parent, purpose, ascii,
        contents, and extras slots.  */
-    struct vectorlike_header header;
+    union vectorlike_header header;
 
     /* This holds a default value,
        which is used whenever the value for a specific character is nil.  */
@@ -1739,7 +1739,7 @@ struct Lisp_Sub_Char_Table
   {
     /* HEADER.SIZE is the vector's size field, which also holds the
        pseudovector type information.  It holds the size, too.  */
-    struct vectorlike_header header;
+    union vectorlike_header header;
 
     /* Depth of this sub char-table.  It should be 1, 2, or 3.  A sub
        char-table of depth 1 contains 16 elements, and each element
@@ -1814,7 +1814,7 @@ CHAR_TABLE_SET (Lisp_Object ct, int idx, Lisp_Object val)
 
 struct Lisp_Subr
   {
-    struct vectorlike_header header;
+    union vectorlike_header header;
     union {
       Lisp_Object (*a0) (void);
       Lisp_Object (*a1) (Lisp_Object);
@@ -2026,7 +2026,7 @@ struct hash_table_test
 struct Lisp_Hash_Table
 {
   /* This is for Lisp; the hash table code does not refer to it.  */
-  struct vectorlike_header header;
+  union vectorlike_header header;
 
   /* Nil if table is non-weak.  Otherwise a symbol describing the
      weakness of the table.  */
@@ -3929,7 +3929,7 @@ typedef emacs_value (*emacs_subr) (emacs_env *, ptrdiff_t,
 
 struct Lisp_Module_Function
 {
-  struct vectorlike_header header;
+  union vectorlike_header header;
 
   /* Fields traced by GC; these must come first.  */
   Lisp_Object documentation;
diff --git a/src/process.h b/src/process.h
index 5a044f669f..5670f44736 100644
--- a/src/process.h
+++ b/src/process.h
@@ -41,7 +41,7 @@ enum { PROCESS_OPEN_FDS = 6 };
 
 struct Lisp_Process
   {
-    struct vectorlike_header header;
+    union vectorlike_header header;
 
     /* Name of subprocess terminal.  */
     Lisp_Object tty_name;
diff --git a/src/termhooks.h b/src/termhooks.h
index dd6044aabd..fe4e993c96 100644
--- a/src/termhooks.h
+++ b/src/termhooks.h
@@ -373,7 +373,7 @@ extern struct tty_display_info *gpm_tty;
 struct terminal
 {
   /* This is for Lisp; the terminal code does not refer to it.  */
-  struct vectorlike_header header;
+  union vectorlike_header header;
 
   /* Parameter alist of this terminal.  */
   Lisp_Object param_alist;
diff --git a/src/thread.h b/src/thread.h
index 19baafbf8a..1845974bc2 100644
--- a/src/thread.h
+++ b/src/thread.h
@@ -35,7 +35,7 @@ along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.  */
 
 struct thread_state
 {
-  struct vectorlike_header header;
+  union vectorlike_header header;
 
   /* The buffer in which the last search was performed, or
      Qt if the last search was done in a string;
@@ -230,7 +230,7 @@ typedef struct
 /* A mutex as a lisp object.  */
 struct Lisp_Mutex
 {
-  struct vectorlike_header header;
+  union vectorlike_header header;
 
   /* The name of the mutex, or nil.  */
   Lisp_Object name;
@@ -261,7 +261,7 @@ XMUTEX (Lisp_Object a)
 /* A condition variable as a lisp object.  */
 struct Lisp_CondVar
 {
-  struct vectorlike_header header;
+  union vectorlike_header header;
 
   /* The associated mutex.  */
   Lisp_Object mutex;
diff --git a/src/w32term.h b/src/w32term.h
index 8d08ca0a2b..de234cb57d 100644
--- a/src/w32term.h
+++ b/src/w32term.h
@@ -431,7 +431,7 @@ extern struct w32_output w32term_display;
 struct scroll_bar {
 
   /* This field is shared by all vectors.  */
-  struct vectorlike_header header;
+  union vectorlike_header header;
 
   /* The window we're a scroll bar for.  */
   Lisp_Object window;
diff --git a/src/window.c b/src/window.c
index cc1d2a7b36..7f472523b4 100644
--- a/src/window.c
+++ b/src/window.c
@@ -3733,8 +3733,8 @@ make_parent_window (Lisp_Object window, bool horflag)
 
   o = XWINDOW (window);
   p = allocate_window ();
-  memcpy ((char *) p + sizeof (struct vectorlike_header),
-	  (char *) o + sizeof (struct vectorlike_header),
+  memcpy ((char *) p + sizeof (union vectorlike_header),
+	  (char *) o + sizeof (union vectorlike_header),
 	  word_size * VECSIZE (struct window));
   /* P's buffer slot may change from nil to a buffer...  */
   adjust_window_count (p, 1);
@@ -6232,7 +6232,7 @@ from the top of the window.  */)
 
 struct save_window_data
   {
-    struct vectorlike_header header;
+    union vectorlike_header header;
     Lisp_Object selected_frame;
     Lisp_Object current_window;
     Lisp_Object f_current_buffer;
@@ -6260,7 +6260,7 @@ struct save_window_data
 /* This is saved as a Lisp_Vector.  */
 struct saved_window
 {
-  struct vectorlike_header header;
+  union vectorlike_header header;
 
   Lisp_Object window, buffer, start, pointm, old_pointm;
   Lisp_Object pixel_left, pixel_top, pixel_height, pixel_width;
diff --git a/src/window.h b/src/window.h
index df7c23f824..25c9686a9f 100644
--- a/src/window.h
+++ b/src/window.h
@@ -88,7 +88,7 @@ struct cursor_pos
 struct window
   {
     /* This is for Lisp; the terminal code does not refer to it.  */
-    struct vectorlike_header header;
+    union vectorlike_header header;
 
     /* The frame this window is on.  */
     Lisp_Object frame;
diff --git a/src/xterm.h b/src/xterm.h
index 6274630706..7ab20ba06c 100644
--- a/src/xterm.h
+++ b/src/xterm.h
@@ -887,7 +887,7 @@ extern void x_mark_frame_dirty (struct frame *f);
 struct scroll_bar
 {
   /* These fields are shared by all vectors.  */
-  struct vectorlike_header header;
+  union vectorlike_header header;
 
   /* The window we're a scroll bar for.  */
   Lisp_Object window;
diff --git a/src/xwidget.h b/src/xwidget.h
index 22a8eb3a55..02a0453dab 100644
--- a/src/xwidget.h
+++ b/src/xwidget.h
@@ -33,7 +33,7 @@ struct window;
 
 struct xwidget
 {
-  struct vectorlike_header header;
+  union vectorlike_header header;
 
   /* Auxiliary data.  */
   Lisp_Object plist;
@@ -62,7 +62,7 @@ struct xwidget
 
 struct xwidget_view
 {
-  struct vectorlike_header header;
+  union vectorlike_header header;
   Lisp_Object model;
   Lisp_Object w;
 
-- 
2.13.6


[-- Attachment #3: 0002-Use-alignas-to-fix-GCALIGN-related-bugs.txt --]
[-- Type: text/plain, Size: 77662 bytes --]

From 19634bef6a161a513ace9669341efac8e782b732 Mon Sep 17 00:00:00 2001
From: Paul Eggert <eggert@cs.ucla.edu>
Date: Fri, 10 Nov 2017 19:10:44 -0800
Subject: [PATCH 2/2] Use alignas to fix GCALIGN-related bugs
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Use alignas and unions to specify alignments of objects needing
addresses that are at least a multiple of GCALIGNMENT.  Using
these standard C facilities should be safer than relying on ad hoc
and poorly-understood features like GCC’s __attribute__
((aligned (N))), the root cause for recent porting bugs like
Bug#29040.  The alignas macro was standardized by C11 and Gnulib
supports alignas for pre-C11 platforms.  I have tested this on Sun
Studio 12 sparc (2007) and GCC 4.4.7 x86-64 (2012) as well as on
more recent platforms like GCC 7.2.1 (2017) on Fedora 26 (both
x86-64 and x86).
* lib-src/make-docfile.c (close_emacs_globals): lispsym is now
just an array of struct Lisp_Symbol, since struct Lisp_Symbol is
now properly aligned.  All uses changed.
* src/alloc.c (NEXT_FREE_LISP_STRING): Just use the new u.next
member; this is simpler and safer than casting a pointer that
might not be aligned properly.
(aligned_Lisp_Symbol): Remove.  No longer needed, now that struct
Lisp_Symbol is aligned properly.  All uses replaced with struct
Lisp_Symbol.
* src/lisp.h (GCALIGNED): Remove, as it does not work as expected:
it can cause the natural alignment to be ignored.  All uses
replaced by unions with a ‘char alignas (GCALIGNMENT)’ member as
described below.
(struct Lisp_Symbol, struct Lisp_Cons, struct Lisp_String):
Change definition from ‘struct TAG { MEMBERS };’ to
‘struct TAG { union { struct { MEMBERS } s; char alignas
(GCALIGNMENT) gcaligned; } u; };’.  This guarantees ‘struct TAG’
to have an alignment that at least max (GCALIGNMENT, N) where N is
its old alignment.  All uses like ‘PTR->MEMBER’ changed to
‘PTR->u.s.MEMBER’; these uses were supposed to be mostly private
anyway.  Verify that the resulting ‘struct TAG’ is properly
aligned for Emacs.
(union vectorlike_header): New member ‘gcaligned’ to guarantee
that this type, and its containing types like ‘struct Lisp_Subr’,
‘struct buffer’ and ‘struct thread_state’, are all properly
aligned for Emacs.
(struct Lisp_String): New union member ‘next’, for the benefit
of NEXT_FREE_LISP_STRING.
(union Aligned_Cons, union Aligned_String): Remove.  All uses
replaced by struct Lisp_Cons and struct Lisp_String, since they
are now properly aligned.
(USE_STACK_CONS, USE_STACK_STRING): Simplify now that we can
assume struct Lisp_Cons and struct Lisp_String are properly
aligned.
---
 lib-src/make-docfile.c |   4 +-
 src/alloc.c            | 211 ++++++++++++++++++-------------------
 src/buffer.c           |  19 ++--
 src/bytecode.c         |   4 +-
 src/casefiddle.c       |   4 +-
 src/cmds.c             |   6 +-
 src/data.c             |  76 +++++++-------
 src/doc.c              |   2 +-
 src/eval.c             |  59 +++++------
 src/fns.c              |   4 +-
 src/keyboard.c         |  10 +-
 src/lisp.h             | 277 ++++++++++++++++++++++++-------------------------
 src/lread.c            |  52 +++++-----
 src/minibuf.c          |  12 +--
 src/thread.c           |   2 +-
 src/xterm.c            |   2 +-
 16 files changed, 367 insertions(+), 377 deletions(-)

diff --git a/lib-src/make-docfile.c b/lib-src/make-docfile.c
index ff84df94a6..9e4755b63a 100644
--- a/lib-src/make-docfile.c
+++ b/lib-src/make-docfile.c
@@ -667,9 +667,7 @@ close_emacs_globals (ptrdiff_t num_symbols)
 	   "#ifndef DEFINE_SYMBOLS\n"
 	   "extern\n"
 	   "#endif\n"
-	   "struct {\n"
-	   "  struct GCALIGNED Lisp_Symbol s;\n"
-	   "} lispsym[%td];\n"),
+	   "struct Lisp_Symbol lispsym[%td];\n"),
 	  num_symbols);
 }
 
diff --git a/src/alloc.c b/src/alloc.c
index 5a44d7a9fc..3b87195b70 100644
--- a/src/alloc.c
+++ b/src/alloc.c
@@ -211,9 +211,9 @@ alloc_unexec_post (void)
 /* Mark, unmark, query mark bit of a Lisp string.  S must be a pointer
    to a struct Lisp_String.  */
 
-#define MARK_STRING(S)		((S)->size |= ARRAY_MARK_FLAG)
-#define UNMARK_STRING(S)	((S)->size &= ~ARRAY_MARK_FLAG)
-#define STRING_MARKED_P(S)	(((S)->size & ARRAY_MARK_FLAG) != 0)
+#define MARK_STRING(S)		((S)->u.s.size |= ARRAY_MARK_FLAG)
+#define UNMARK_STRING(S)	((S)->u.s.size &= ~ARRAY_MARK_FLAG)
+#define STRING_MARKED_P(S)	(((S)->u.s.size & ARRAY_MARK_FLAG) != 0)
 
 #define VECTOR_MARK(V)		((V)->header.size |= ARRAY_MARK_FLAG)
 #define VECTOR_UNMARK(V)	((V)->header.size &= ~ARRAY_MARK_FLAG)
@@ -1730,14 +1730,14 @@ static EMACS_INT total_string_bytes;
    string_free_list, return a pointer to its successor in the
    free-list.  */
 
-#define NEXT_FREE_LISP_STRING(S) (*(struct Lisp_String **) (S))
+#define NEXT_FREE_LISP_STRING(S) ((S)->u.next)
 
 /* Return a pointer to the sdata structure belonging to Lisp string S.
    S must be live, i.e. S->data must not be null.  S->data is actually
    a pointer to the `u.data' member of its sdata structure; the
    structure starts at a constant offset in front of that.  */
 
-#define SDATA_OF_STRING(S) ((sdata *) ((S)->data - SDATA_DATA_OFFSET))
+#define SDATA_OF_STRING(S) ((sdata *) ((S)->u.s.data - SDATA_DATA_OFFSET))
 
 
 #ifdef GC_CHECK_STRING_OVERRUN
@@ -1818,9 +1818,10 @@ ptrdiff_t
 string_bytes (struct Lisp_String *s)
 {
   ptrdiff_t nbytes =
-    (s->size_byte < 0 ? s->size & ~ARRAY_MARK_FLAG : s->size_byte);
+    (s->u.s.size_byte < 0 ? s->u.s.size & ~ARRAY_MARK_FLAG : s->u.s.size_byte);
 
-  if (!PURE_P (s) && s->data && nbytes != SDATA_NBYTES (SDATA_OF_STRING (s)))
+  if (!PURE_P (s) && s->u.s.data
+      && nbytes != SDATA_NBYTES (SDATA_OF_STRING (s)))
     emacs_abort ();
   return nbytes;
 }
@@ -1926,7 +1927,7 @@ allocate_string (void)
 	{
 	  s = b->strings + i;
 	  /* Every string on a free list should have NULL data pointer.  */
-	  s->data = NULL;
+	  s->u.s.data = NULL;
 	  NEXT_FREE_LISP_STRING (s) = string_free_list;
 	  string_free_list = s;
 	}
@@ -1965,10 +1966,10 @@ allocate_string (void)
 
 
 /* Set up Lisp_String S for holding NCHARS characters, NBYTES bytes,
-   plus a NUL byte at the end.  Allocate an sdata structure for S, and
-   set S->data to its `u.data' member.  Store a NUL byte at the end of
-   S->data.  Set S->size to NCHARS and S->size_byte to NBYTES.  Free
-   S->data if it was initially non-null.  */
+   plus a NUL byte at the end.  Allocate an sdata structure DATA for
+   S, and set S->u.s.data to SDATA->u.data.  Store a NUL byte at the
+   end of S->u.s.data.  Set S->u.s.size to NCHARS and S->u.s.size_byte
+   to NBYTES.  Free S->u.s.data if it was initially non-null.  */
 
 void
 allocate_string_data (struct Lisp_String *s,
@@ -1984,7 +1985,7 @@ allocate_string_data (struct Lisp_String *s,
   /* Determine the number of bytes needed to store NBYTES bytes
      of string data.  */
   needed = SDATA_SIZE (nbytes);
-  if (s->data)
+  if (s->u.s.data)
     {
       old_data = SDATA_OF_STRING (s);
       old_nbytes = STRING_BYTES (s);
@@ -2043,13 +2044,13 @@ allocate_string_data (struct Lisp_String *s,
 
   MALLOC_UNBLOCK_INPUT;
 
-  s->data = SDATA_DATA (data);
+  s->u.s.data = SDATA_DATA (data);
 #ifdef GC_CHECK_STRING_BYTES
   SDATA_NBYTES (data) = nbytes;
 #endif
-  s->size = nchars;
-  s->size_byte = nbytes;
-  s->data[nbytes] = '\0';
+  s->u.s.size = nchars;
+  s->u.s.size_byte = nbytes;
+  s->u.s.data[nbytes] = '\0';
 #ifdef GC_CHECK_STRING_OVERRUN
   memcpy ((char *) data + needed, string_overrun_cookie,
 	  GC_STRING_OVERRUN_COOKIE_SIZE);
@@ -2093,7 +2094,7 @@ sweep_strings (void)
 	{
 	  struct Lisp_String *s = b->strings + i;
 
-	  if (s->data)
+	  if (s->u.s.data)
 	    {
 	      /* String was not on free-list before.  */
 	      if (STRING_MARKED_P (s))
@@ -2102,7 +2103,7 @@ sweep_strings (void)
 		  UNMARK_STRING (s);
 
 		  /* Do not use string_(set|get)_intervals here.  */
-		  s->intervals = balance_intervals (s->intervals);
+		  s->u.s.intervals = balance_intervals (s->u.s.intervals);
 
 		  ++total_strings;
 		  total_string_bytes += STRING_BYTES (s);
@@ -2125,7 +2126,7 @@ sweep_strings (void)
 
 		  /* Reset the strings's `data' member so that we
 		     know it's free.  */
-		  s->data = NULL;
+		  s->u.s.data = NULL;
 
 		  /* Put the string on the free-list.  */
 		  NEXT_FREE_LISP_STRING (s) = string_free_list;
@@ -2264,7 +2265,7 @@ compact_small_strings (void)
 		    {
 		      eassert (tb != b || to < from);
 		      memmove (to, from, nbytes + GC_STRING_EXTRA);
-		      to->string->data = SDATA_DATA (to);
+		      to->string->u.s.data = SDATA_DATA (to);
 		    }
 
 		  /* Advance past the sdata we copied to.  */
@@ -2544,7 +2545,7 @@ make_uninit_multibyte_string (EMACS_INT nchars, EMACS_INT nbytes)
     return empty_multibyte_string;
 
   s = allocate_string ();
-  s->intervals = NULL;
+  s->u.s.intervals = NULL;
   allocate_string_data (s, nchars, nbytes);
   XSETSTRING (string, s);
   string_chars_consed += nbytes;
@@ -2729,8 +2730,8 @@ static struct Lisp_Cons *cons_free_list;
 void
 free_cons (struct Lisp_Cons *ptr)
 {
-  ptr->u.chain = cons_free_list;
-  ptr->car = Vdead;
+  ptr->u.s.u.chain = cons_free_list;
+  ptr->u.s.car = Vdead;
   cons_free_list = ptr;
   consing_since_gc -= sizeof *ptr;
   total_free_conses++;
@@ -2749,7 +2750,7 @@ DEFUN ("cons", Fcons, Scons, 2, 2, 0,
       /* We use the cdr for chaining the free list
 	 so that we won't use the same field that has the mark bit.  */
       XSETCONS (val, cons_free_list);
-      cons_free_list = cons_free_list->u.chain;
+      cons_free_list = cons_free_list->u.s.u.chain;
     }
   else
     {
@@ -2786,7 +2787,7 @@ check_cons_list (void)
   struct Lisp_Cons *tail = cons_free_list;
 
   while (tail)
-    tail = tail->u.chain;
+    tail = tail->u.s.u.chain;
 }
 #endif
 
@@ -3543,27 +3544,17 @@ usage: (make-byte-code ARGLIST BYTE-CODE CONSTANTS DEPTH &optional DOCSTRING INT
 			   Symbol Allocation
  ***********************************************************************/
 
-/* Like struct Lisp_Symbol, but padded so that the size is a multiple
-   of the required alignment.  */
-
-union aligned_Lisp_Symbol
-{
-  struct Lisp_Symbol s;
-  unsigned char c[(sizeof (struct Lisp_Symbol) + GCALIGNMENT - 1)
-		  & -GCALIGNMENT];
-};
-
 /* Each symbol_block is just under 1020 bytes long, since malloc
    really allocates in units of powers of two and uses 4 bytes for its
    own overhead.  */
 
 #define SYMBOL_BLOCK_SIZE \
-  ((1020 - sizeof (struct symbol_block *)) / sizeof (union aligned_Lisp_Symbol))
+  ((1020 - sizeof (struct symbol_block *)) / sizeof (struct Lisp_Symbol))
 
 struct symbol_block
 {
   /* Place `symbols' first, to preserve alignment.  */
-  union aligned_Lisp_Symbol symbols[SYMBOL_BLOCK_SIZE];
+  struct Lisp_Symbol symbols[SYMBOL_BLOCK_SIZE];
   struct symbol_block *next;
 };
 
@@ -3587,7 +3578,7 @@ static struct Lisp_Symbol *symbol_free_list;
 static void
 set_symbol_name (Lisp_Object sym, Lisp_Object name)
 {
-  XSYMBOL (sym)->name = name;
+  XSYMBOL (sym)->u.s.name = name;
 }
 
 void
@@ -3596,15 +3587,15 @@ init_symbol (Lisp_Object val, Lisp_Object name)
   struct Lisp_Symbol *p = XSYMBOL (val);
   set_symbol_name (val, name);
   set_symbol_plist (val, Qnil);
-  p->redirect = SYMBOL_PLAINVAL;
+  p->u.s.redirect = SYMBOL_PLAINVAL;
   SET_SYMBOL_VAL (p, Qunbound);
   set_symbol_function (val, Qnil);
   set_symbol_next (val, NULL);
-  p->gcmarkbit = false;
-  p->interned = SYMBOL_UNINTERNED;
-  p->trapped_write = SYMBOL_UNTRAPPED_WRITE;
-  p->declared_special = false;
-  p->pinned = false;
+  p->u.s.gcmarkbit = false;
+  p->u.s.interned = SYMBOL_UNINTERNED;
+  p->u.s.trapped_write = SYMBOL_UNTRAPPED_WRITE;
+  p->u.s.declared_special = false;
+  p->u.s.pinned = false;
 }
 
 DEFUN ("make-symbol", Fmake_symbol, Smake_symbol, 1, 1, 0,
@@ -3621,7 +3612,7 @@ Its value is void, and its function definition and property list are nil.  */)
   if (symbol_free_list)
     {
       XSETSYMBOL (val, symbol_free_list);
-      symbol_free_list = symbol_free_list->next;
+      symbol_free_list = symbol_free_list->u.s.next;
     }
   else
     {
@@ -3634,7 +3625,7 @@ Its value is void, and its function definition and property list are nil.  */)
 	  symbol_block_index = 0;
 	  total_free_symbols += SYMBOL_BLOCK_SIZE;
 	}
-      XSETSYMBOL (val, &symbol_block->symbols[symbol_block_index].s);
+      XSETSYMBOL (val, &symbol_block->symbols[symbol_block_index]);
       symbol_block_index++;
     }
 
@@ -4587,7 +4578,7 @@ live_string_holding (struct mem_node *m, void *p)
       if (0 <= offset && offset < STRING_BLOCK_SIZE * sizeof b->strings[0])
 	{
 	  struct Lisp_String *s = p = cp -= offset % sizeof b->strings[0];
-	  if (s->data)
+	  if (s->u.s.data)
 	    return make_lisp_ptr (s, Lisp_String);
 	}
     }
@@ -4621,7 +4612,7 @@ live_cons_holding (struct mem_node *m, void *p)
 	      || offset / sizeof b->conses[0] < cons_block_index))
 	{
 	  struct Lisp_Cons *s = p = cp -= offset % sizeof b->conses[0];
-	  if (!EQ (s->car, Vdead))
+	  if (!EQ (s->u.s.car, Vdead))
 	    return make_lisp_ptr (s, Lisp_Cons);
 	}
     }
@@ -4656,7 +4647,7 @@ live_symbol_holding (struct mem_node *m, void *p)
 	      || offset / sizeof b->symbols[0] < symbol_block_index))
 	{
 	  struct Lisp_Symbol *s = p = cp -= offset % sizeof b->symbols[0];
-	  if (!EQ (s->function, Vdead))
+	  if (!EQ (s->u.s.function, Vdead))
 	    return make_lisp_symbol (s);
 	}
     }
@@ -4984,7 +4975,7 @@ mark_memory (void *start, void *end)
        Lisp_Object obj = build_string ("test");
        struct Lisp_String *s = XSTRING (obj);
        Fgarbage_collect ();
-       fprintf (stderr, "test '%s'\n", s->data);
+       fprintf (stderr, "test '%s'\n", s->u.s.data);
        return Qnil;
      }
 
@@ -5484,16 +5475,16 @@ make_pure_string (const char *data,
 {
   Lisp_Object string;
   struct Lisp_String *s = pure_alloc (sizeof *s, Lisp_String);
-  s->data = (unsigned char *) find_string_data_in_pure (data, nbytes);
-  if (s->data == NULL)
+  s->u.s.data = (unsigned char *) find_string_data_in_pure (data, nbytes);
+  if (s->u.s.data == NULL)
     {
-      s->data = pure_alloc (nbytes + 1, -1);
-      memcpy (s->data, data, nbytes);
-      s->data[nbytes] = '\0';
+      s->u.s.data = pure_alloc (nbytes + 1, -1);
+      memcpy (s->u.s.data, data, nbytes);
+      s->u.s.data[nbytes] = '\0';
     }
-  s->size = nchars;
-  s->size_byte = multibyte ? nbytes : -1;
-  s->intervals = NULL;
+  s->u.s.size = nchars;
+  s->u.s.size_byte = multibyte ? nbytes : -1;
+  s->u.s.intervals = NULL;
   XSETSTRING (string, s);
   return string;
 }
@@ -5506,10 +5497,10 @@ make_pure_c_string (const char *data, ptrdiff_t nchars)
 {
   Lisp_Object string;
   struct Lisp_String *s = pure_alloc (sizeof *s, Lisp_String);
-  s->size = nchars;
-  s->size_byte = -1;
-  s->data = (unsigned char *) data;
-  s->intervals = NULL;
+  s->u.s.size = nchars;
+  s->u.s.size_byte = -1;
+  s->u.s.data = (unsigned char *) data;
+  s->u.s.intervals = NULL;
   XSETSTRING (string, s);
   return string;
 }
@@ -5620,7 +5611,7 @@ purecopy (Lisp_Object obj)
       || SUBRP (obj))
     return obj;    /* Already pure.  */
 
-  if (STRINGP (obj) && XSTRING (obj)->intervals)
+  if (STRINGP (obj) && XSTRING (obj)->u.s.intervals)
     message_with_string ("Dropping text-properties while making string `%s' pure",
 			 obj, true);
 
@@ -5675,10 +5666,10 @@ purecopy (Lisp_Object obj)
     }
   else if (SYMBOLP (obj))
     {
-      if (!XSYMBOL (obj)->pinned && !c_symbol_p (XSYMBOL (obj)))
+      if (!XSYMBOL (obj)->u.s.pinned && !c_symbol_p (XSYMBOL (obj)))
 	{ /* We can't purify them, but they appear in many pure objects.
 	     Mark them as `pinned' so we know to mark them at every GC cycle.  */
-	  XSYMBOL (obj)->pinned = true;
+	  XSYMBOL (obj)->u.s.pinned = true;
 	  symbol_block_pinned = symbol_block;
 	}
       /* Don't hash-cons it.  */
@@ -5891,10 +5882,10 @@ mark_pinned_symbols (void)
 
   for (sblk = symbol_block_pinned; sblk; sblk = sblk->next)
     {
-      union aligned_Lisp_Symbol *sym = sblk->symbols, *end = sym + lim;
+      struct Lisp_Symbol *sym = sblk->symbols, *end = sym + lim;
       for (; sym < end; ++sym)
-	if (sym->s.pinned)
-	  mark_object (make_lisp_symbol (&sym->s));
+	if (sym->u.s.pinned)
+	  mark_object (make_lisp_symbol (sym));
 
       lim = SYMBOL_BLOCK_SIZE;
     }
@@ -6256,7 +6247,7 @@ mark_char_table (struct Lisp_Vector *ptr, enum pvec_type pvectype)
     {
       Lisp_Object val = ptr->contents[i];
 
-      if (INTEGERP (val) || (SYMBOLP (val) && XSYMBOL (val)->gcmarkbit))
+      if (INTEGERP (val) || (SYMBOLP (val) && XSYMBOL (val)->u.s.gcmarkbit))
 	continue;
       if (SUB_CHAR_TABLE_P (val))
 	{
@@ -6499,7 +6490,7 @@ mark_object (Lisp_Object arg)
 	  break;
 	CHECK_ALLOCATED_AND_LIVE (live_string_p);
 	MARK_STRING (ptr);
-	MARK_INTERVAL_TREE (ptr->intervals);
+	MARK_INTERVAL_TREE (ptr->u.s.intervals);
 #ifdef GC_CHECK_STRING_BYTES
 	/* Check that the string size recorded in the string is the
 	   same as the one recorded in the sdata structure.  */
@@ -6640,17 +6631,17 @@ mark_object (Lisp_Object arg)
 
     case Lisp_Symbol:
       {
-	register struct Lisp_Symbol *ptr = XSYMBOL (obj);
+	struct Lisp_Symbol *ptr = XSYMBOL (obj);
       nextsym:
-	if (ptr->gcmarkbit)
+	if (ptr->u.s.gcmarkbit)
 	  break;
 	CHECK_ALLOCATED_AND_LIVE_SYMBOL ();
-	ptr->gcmarkbit = 1;
+	ptr->u.s.gcmarkbit = 1;
 	/* Attempt to catch bogus objects.  */
-        eassert (valid_lisp_object_p (ptr->function));
-	mark_object (ptr->function);
-	mark_object (ptr->plist);
-	switch (ptr->redirect)
+	eassert (valid_lisp_object_p (ptr->u.s.function));
+	mark_object (ptr->u.s.function);
+	mark_object (ptr->u.s.plist);
+	switch (ptr->u.s.redirect)
 	  {
 	  case SYMBOL_PLAINVAL: mark_object (SYMBOL_VAL (ptr)); break;
 	  case SYMBOL_VARALIAS:
@@ -6671,11 +6662,11 @@ mark_object (Lisp_Object arg)
 	    break;
 	  default: emacs_abort ();
 	  }
-	if (!PURE_P (XSTRING (ptr->name)))
-	  MARK_STRING (XSTRING (ptr->name));
-	MARK_INTERVAL_TREE (string_intervals (ptr->name));
+	if (!PURE_P (XSTRING (ptr->u.s.name)))
+	  MARK_STRING (XSTRING (ptr->u.s.name));
+	MARK_INTERVAL_TREE (string_intervals (ptr->u.s.name));
 	/* Inner loop to mark next symbol in this bucket, if any.  */
-	po = ptr = ptr->next;
+	po = ptr = ptr->u.s.next;
 	if (ptr)
 	  goto nextsym;
       }
@@ -6729,14 +6720,14 @@ mark_object (Lisp_Object arg)
 	CHECK_ALLOCATED_AND_LIVE (live_cons_p);
 	CONS_MARK (ptr);
 	/* If the cdr is nil, avoid recursion for the car.  */
-	if (EQ (ptr->u.cdr, Qnil))
+	if (EQ (ptr->u.s.u.cdr, Qnil))
 	  {
-	    obj = ptr->car;
+	    obj = ptr->u.s.car;
 	    cdr_count = 0;
 	    goto loop;
 	  }
-	mark_object (ptr->car);
-	obj = ptr->u.cdr;
+	mark_object (ptr->u.s.car);
+	obj = ptr->u.s.u.cdr;
 	cdr_count++;
 	if (cdr_count == mark_object_loop_halt)
 	  emacs_abort ();
@@ -6797,7 +6788,7 @@ survives_gc_p (Lisp_Object obj)
       break;
 
     case Lisp_Symbol:
-      survives_p = XSYMBOL (obj)->gcmarkbit;
+      survives_p = XSYMBOL (obj)->u.s.gcmarkbit;
       break;
 
     case Lisp_Misc:
@@ -6873,9 +6864,9 @@ sweep_conses (void)
                   if (!CONS_MARKED_P (&cblk->conses[pos]))
                     {
                       this_free++;
-                      cblk->conses[pos].u.chain = cons_free_list;
+                      cblk->conses[pos].u.s.u.chain = cons_free_list;
                       cons_free_list = &cblk->conses[pos];
-                      cons_free_list->car = Vdead;
+                      cons_free_list->u.s.car = Vdead;
                     }
                   else
                     {
@@ -6894,7 +6885,7 @@ sweep_conses (void)
         {
           *cprev = cblk->next;
           /* Unhook from the free list.  */
-          cons_free_list = cblk->conses[0].u.chain;
+          cons_free_list = cblk->conses[0].u.s.u.chain;
           lisp_align_free (cblk);
         }
       else
@@ -7018,39 +7009,39 @@ sweep_symbols (void)
   symbol_free_list = NULL;
 
   for (int i = 0; i < ARRAYELTS (lispsym); i++)
-    lispsym[i].s.gcmarkbit = 0;
+    lispsym[i].u.s.gcmarkbit = 0;
 
   for (sblk = symbol_block; sblk; sblk = *sprev)
     {
       int this_free = 0;
-      union aligned_Lisp_Symbol *sym = sblk->symbols;
-      union aligned_Lisp_Symbol *end = sym + lim;
+      struct Lisp_Symbol *sym = sblk->symbols;
+      struct Lisp_Symbol *end = sym + lim;
 
       for (; sym < end; ++sym)
         {
-          if (!sym->s.gcmarkbit)
+          if (!sym->u.s.gcmarkbit)
             {
-              if (sym->s.redirect == SYMBOL_LOCALIZED)
+              if (sym->u.s.redirect == SYMBOL_LOCALIZED)
 		{
-                  xfree (SYMBOL_BLV (&sym->s));
+                  xfree (SYMBOL_BLV (sym));
                   /* At every GC we sweep all symbol_blocks and rebuild the
                      symbol_free_list, so those symbols which stayed unused
                      between the two will be re-swept.
                      So we have to make sure we don't re-free this blv next
                      time we sweep this symbol_block (bug#29066).  */
-                  sym->s.redirect = SYMBOL_PLAINVAL;
+                  sym->u.s.redirect = SYMBOL_PLAINVAL;
                 }
-              sym->s.next = symbol_free_list;
-              symbol_free_list = &sym->s;
-              symbol_free_list->function = Vdead;
+              sym->u.s.next = symbol_free_list;
+              symbol_free_list = sym;
+              symbol_free_list->u.s.function = Vdead;
               ++this_free;
             }
           else
             {
               ++num_used;
-              sym->s.gcmarkbit = 0;
+              sym->u.s.gcmarkbit = 0;
               /* Attempt to catch bogus objects.  */
-              eassert (valid_lisp_object_p (sym->s.function));
+              eassert (valid_lisp_object_p (sym->u.s.function));
             }
         }
 
@@ -7062,7 +7053,7 @@ sweep_symbols (void)
         {
           *sprev = sblk->next;
           /* Unhook from the free list.  */
-          symbol_free_list = sblk->symbols[0].s.next;
+          symbol_free_list = sblk->symbols[0].u.s.next;
           lisp_free (sblk);
         }
       else
@@ -7289,10 +7280,10 @@ symbol_uses_obj (Lisp_Object symbol, Lisp_Object obj)
   struct Lisp_Symbol *sym = XSYMBOL (symbol);
   Lisp_Object val = find_symbol_value (symbol);
   return (EQ (val, obj)
-	  || EQ (sym->function, obj)
-	  || (!NILP (sym->function)
-	      && COMPILEDP (sym->function)
-	      && EQ (AREF (sym->function, COMPILED_BYTECODE), obj))
+	  || EQ (sym->u.s.function, obj)
+	  || (!NILP (sym->u.s.function)
+	      && COMPILEDP (sym->u.s.function)
+	      && EQ (AREF (sym->u.s.function, COMPILED_BYTECODE), obj))
 	  || (!NILP (val)
 	      && COMPILEDP (val)
 	      && EQ (AREF (val, COMPILED_BYTECODE), obj)));
@@ -7323,15 +7314,15 @@ which_symbols (Lisp_Object obj, EMACS_INT find_max)
 
        for (sblk = symbol_block; sblk; sblk = sblk->next)
 	 {
-	   union aligned_Lisp_Symbol *aligned_sym = sblk->symbols;
+	   struct Lisp_Symbol *asym = sblk->symbols;
 	   int bn;
 
-	   for (bn = 0; bn < SYMBOL_BLOCK_SIZE; bn++, aligned_sym++)
+	   for (bn = 0; bn < SYMBOL_BLOCK_SIZE; bn++, asym++)
 	     {
 	       if (sblk == symbol_block && bn >= symbol_block_index)
 		 break;
 
-	       Lisp_Object sym = make_lisp_symbol (&aligned_sym->s);
+	       Lisp_Object sym = make_lisp_symbol (asym);
 	       if (symbol_uses_obj (sym, obj))
 		 {
 		   found = Fcons (sym, found);
diff --git a/src/buffer.c b/src/buffer.c
index edeed55e8b..4ae5e811b0 100644
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -61,7 +61,7 @@ struct buffer *all_buffers;
    Setting the default value also goes through the alist of buffers
    and stores into each buffer that does not say it has a local value.  */
 
-struct GCALIGNED buffer buffer_defaults;
+struct buffer buffer_defaults;
 
 /* This structure marks which slots in a buffer have corresponding
    default values in buffer_defaults.
@@ -84,7 +84,7 @@ struct buffer buffer_local_flags;
 /* This structure holds the names of symbols whose values may be
    buffer-local.  It is indexed and accessed in the same way as the above.  */
 
-struct GCALIGNED buffer buffer_local_symbols;
+struct buffer buffer_local_symbols;
 
 /* Return the symbol of the per-buffer variable at offset OFFSET in
    the buffer structure.  */
@@ -1021,7 +1021,8 @@ reset_buffer_local_variables (struct buffer *b, bool permanent_too)
                           newlist = Fcons (elt, newlist);
                       }
                   newlist = Fnreverse (newlist);
-                  if (XSYMBOL (local_var)->trapped_write == SYMBOL_TRAPPED_WRITE)
+                  if (XSYMBOL (local_var)->u.s.trapped_write
+		      == SYMBOL_TRAPPED_WRITE)
                     notify_variable_watchers (local_var, newlist,
                                               Qmakunbound, Fcurrent_buffer ());
                   XSETCDR (XCAR (tmp), newlist);
@@ -1034,7 +1035,7 @@ reset_buffer_local_variables (struct buffer *b, bool permanent_too)
           else
             XSETCDR (last, XCDR (tmp));
 
-          if (XSYMBOL (local_var)->trapped_write == SYMBOL_TRAPPED_WRITE)
+          if (XSYMBOL (local_var)->u.s.trapped_write == SYMBOL_TRAPPED_WRITE)
             notify_variable_watchers (local_var, Qnil,
                                       Qmakunbound, Fcurrent_buffer ());
         }
@@ -1166,7 +1167,7 @@ buffer_local_value (Lisp_Object variable, Lisp_Object buffer)
   sym = XSYMBOL (variable);
 
  start:
-  switch (sym->redirect)
+  switch (sym->u.s.redirect)
     {
     case SYMBOL_VARALIAS: sym = indirect_variable (sym); goto start;
     case SYMBOL_PLAINVAL: result = SYMBOL_VAL (sym); break;
@@ -2096,7 +2097,7 @@ void set_buffer_internal_2 (register struct buffer *b)
 	{
 	  Lisp_Object var = XCAR (XCAR (tail));
 	  struct Lisp_Symbol *sym = XSYMBOL (var);
-	  if (sym->redirect == SYMBOL_LOCALIZED /* Just to be sure.  */
+	  if (sym->u.s.redirect == SYMBOL_LOCALIZED /* Just to be sure.  */
 	      && SYMBOL_BLV (sym)->fwd)
 	    /* Just reference the variable
 	       to cause it to become set for this buffer.  */
@@ -2752,7 +2753,7 @@ swap_out_buffer_local_variables (struct buffer *b)
   for (alist = oalist; CONSP (alist); alist = XCDR (alist))
     {
       Lisp_Object sym = XCAR (XCAR (alist));
-      eassert (XSYMBOL (sym)->redirect == SYMBOL_LOCALIZED);
+      eassert (XSYMBOL (sym)->u.s.redirect == SYMBOL_LOCALIZED);
       /* Need not do anything if some other buffer's binding is
 	 now cached.  */
       if (EQ (SYMBOL_BLV (XSYMBOL (sym))->where, buffer))
@@ -5423,8 +5424,8 @@ defvar_per_buffer (struct Lisp_Buffer_Objfwd *bo_fwd, const char *namestring,
   bo_fwd->type = Lisp_Fwd_Buffer_Obj;
   bo_fwd->offset = offset;
   bo_fwd->predicate = predicate;
-  sym->declared_special = 1;
-  sym->redirect = SYMBOL_FORWARDED;
+  sym->u.s.declared_special = true;
+  sym->u.s.redirect = SYMBOL_FORWARDED;
   SET_SYMBOL_FWD (sym, (union Lisp_Fwd *) bo_fwd);
   XSETSYMBOL (PER_BUFFER_SYMBOL (offset), sym);
 
diff --git a/src/bytecode.c b/src/bytecode.c
index 50c7abe289..ebaf3c3a7f 100644
--- a/src/bytecode.c
+++ b/src/bytecode.c
@@ -489,7 +489,7 @@ exec_byte_code (Lisp_Object bytestr, Lisp_Object vector, Lisp_Object maxdepth,
 	  {
 	    Lisp_Object v1 = vectorp[op], v2;
 	    if (!SYMBOLP (v1)
-		|| XSYMBOL (v1)->redirect != SYMBOL_PLAINVAL
+		|| XSYMBOL (v1)->u.s.redirect != SYMBOL_PLAINVAL
 		|| (v2 = SYMBOL_VAL (XSYMBOL (v1)), EQ (v2, Qunbound)))
 	      v2 = Fsymbol_value (v1);
 	    PUSH (v2);
@@ -558,7 +558,7 @@ exec_byte_code (Lisp_Object bytestr, Lisp_Object vector, Lisp_Object maxdepth,
 	    /* Inline the most common case.  */
 	    if (SYMBOLP (sym)
 		&& !EQ (val, Qunbound)
-		&& !XSYMBOL (sym)->redirect
+		&& !XSYMBOL (sym)->u.s.redirect
 		&& !SYMBOL_TRAPPED_WRITE_P (sym))
 	      SET_SYMBOL_VAL (XSYMBOL (sym), val);
 	    else
diff --git a/src/casefiddle.c b/src/casefiddle.c
index 8f564edeb9..7b34f78a5c 100644
--- a/src/casefiddle.c
+++ b/src/casefiddle.c
@@ -133,9 +133,9 @@ case_character_impl (struct casing_str_buf *buf,
           struct Lisp_String *str = XSTRING (prop);
           if (STRING_BYTES (str) <= sizeof buf->data)
 	    {
-	      buf->len_chars = str->size;
+	      buf->len_chars = str->u.s.size;
 	      buf->len_bytes = STRING_BYTES (str);
-	      memcpy (buf->data, str->data, buf->len_bytes);
+	      memcpy (buf->data, str->u.s.data, buf->len_bytes);
 	      return 1;
 	    }
         }
diff --git a/src/cmds.c b/src/cmds.c
index e4c0c86691..1788f22fe5 100644
--- a/src/cmds.c
+++ b/src/cmds.c
@@ -421,11 +421,11 @@ internal_self_insert (int c, EMACS_INT n)
 	 and the hook has a non-nil `no-self-insert' property,
 	 return right away--don't really self-insert.  */
       if (SYMBOLP (sym) && ! NILP (sym)
-	  && ! NILP (XSYMBOL (sym)->function)
-	  && SYMBOLP (XSYMBOL (sym)->function))
+	  && ! NILP (XSYMBOL (sym)->u.s.function)
+	  && SYMBOLP (XSYMBOL (sym)->u.s.function))
 	{
 	  Lisp_Object prop;
-	  prop = Fget (XSYMBOL (sym)->function, intern ("no-self-insert"));
+	  prop = Fget (XSYMBOL (sym)->u.s.function, intern ("no-self-insert"));
 	  if (! NILP (prop))
 	    return 1;
 	}
diff --git a/src/data.c b/src/data.c
index ef7210fbfa..b4f6fd5c65 100644
--- a/src/data.c
+++ b/src/data.c
@@ -670,7 +670,7 @@ global value outside of any lexical scope.  */)
   sym = XSYMBOL (symbol);
 
  start:
-  switch (sym->redirect)
+  switch (sym->u.s.redirect)
     {
     case SYMBOL_PLAINVAL: valcontents = SYMBOL_VAL (sym); break;
     case SYMBOL_VARALIAS: sym = indirect_variable (sym); goto start;
@@ -704,10 +704,10 @@ global value outside of any lexical scope.  */)
    expect `t' in particular, rather than any true value.  */
 DEFUN ("fboundp", Ffboundp, Sfboundp, 1, 1, 0,
        doc: /* Return t if SYMBOL's function definition is not void.  */)
-  (register Lisp_Object symbol)
+  (Lisp_Object symbol)
 {
   CHECK_SYMBOL (symbol);
-  return NILP (XSYMBOL (symbol)->function) ? Qnil : Qt;
+  return NILP (XSYMBOL (symbol)->u.s.function) ? Qnil : Qt;
 }
 
 DEFUN ("makunbound", Fmakunbound, Smakunbound, 1, 1, 0,
@@ -736,18 +736,18 @@ Return SYMBOL.  */)
 
 DEFUN ("symbol-function", Fsymbol_function, Ssymbol_function, 1, 1, 0,
        doc: /* Return SYMBOL's function definition, or nil if that is void.  */)
-  (register Lisp_Object symbol)
+  (Lisp_Object symbol)
 {
   CHECK_SYMBOL (symbol);
-  return XSYMBOL (symbol)->function;
+  return XSYMBOL (symbol)->u.s.function;
 }
 
 DEFUN ("symbol-plist", Fsymbol_plist, Ssymbol_plist, 1, 1, 0,
        doc: /* Return SYMBOL's property list.  */)
-  (register Lisp_Object symbol)
+  (Lisp_Object symbol)
 {
   CHECK_SYMBOL (symbol);
-  return XSYMBOL (symbol)->plist;
+  return XSYMBOL (symbol)->u.s.plist;
 }
 
 DEFUN ("symbol-name", Fsymbol_name, Ssymbol_name, 1, 1, 0,
@@ -771,7 +771,7 @@ DEFUN ("fset", Ffset, Sfset, 2, 2, 0,
   if (NILP (symbol))
     xsignal1 (Qsetting_constant, symbol);
 
-  function = XSYMBOL (symbol)->function;
+  function = XSYMBOL (symbol)->u.s.function;
 
   if (!NILP (Vautoload_queue) && !NILP (function))
     Vautoload_queue = Fcons (Fcons (symbol, function), Vautoload_queue);
@@ -814,7 +814,7 @@ The return value is undefined.  */)
       { /* Only add autoload entries after dumping, because the ones before are
 	   not useful and else we get loads of them from the loaddefs.el.  */
 
-	if (AUTOLOADP (XSYMBOL (symbol)->function))
+	if (AUTOLOADP (XSYMBOL (symbol)->u.s.function))
 	  /* Remember that the function was already an autoload.  */
 	  LOADHIST_ATTACH (Fcons (Qt, symbol));
 	LOADHIST_ATTACH (Fcons (autoload ? Qautoload : Qdefun, symbol));
@@ -940,10 +940,10 @@ indirect_variable (struct Lisp_Symbol *symbol)
 
   hare = tortoise = symbol;
 
-  while (hare->redirect == SYMBOL_VARALIAS)
+  while (hare->u.s.redirect == SYMBOL_VARALIAS)
     {
       hare = SYMBOL_ALIAS (hare);
-      if (hare->redirect != SYMBOL_VARALIAS)
+      if (hare->u.s.redirect != SYMBOL_VARALIAS)
 	break;
 
       hare = SYMBOL_ALIAS (hare);
@@ -1247,7 +1247,7 @@ find_symbol_value (Lisp_Object symbol)
   sym = XSYMBOL (symbol);
 
  start:
-  switch (sym->redirect)
+  switch (sym->u.s.redirect)
     {
     case SYMBOL_VARALIAS: sym = indirect_variable (sym); goto start;
     case SYMBOL_PLAINVAL: return SYMBOL_VAL (sym);
@@ -1310,7 +1310,7 @@ set_internal (Lisp_Object symbol, Lisp_Object newval, Lisp_Object where,
 
   CHECK_SYMBOL (symbol);
   sym = XSYMBOL (symbol);
-  switch (sym->trapped_write)
+  switch (sym->u.s.trapped_write)
     {
     case SYMBOL_NOWRITE:
       if (NILP (Fkeywordp (symbol))
@@ -1336,7 +1336,7 @@ set_internal (Lisp_Object symbol, Lisp_Object newval, Lisp_Object where,
     }
 
  start:
-  switch (sym->redirect)
+  switch (sym->u.s.redirect)
     {
     case SYMBOL_VARALIAS: sym = indirect_variable (sym); goto start;
     case SYMBOL_PLAINVAL: SET_SYMBOL_VAL (sym , newval); return;
@@ -1436,7 +1436,7 @@ set_internal (Lisp_Object symbol, Lisp_Object newval, Lisp_Object where,
 	if (voide)
 	  { /* If storing void (making the symbol void), forward only through
 	       buffer-local indicator, not through Lisp_Objfwd, etc.  */
-	    sym->redirect = SYMBOL_PLAINVAL;
+	    sym->u.s.redirect = SYMBOL_PLAINVAL;
 	    SET_SYMBOL_VAL (sym, newval);
 	  }
 	else
@@ -1452,9 +1452,9 @@ static void
 set_symbol_trapped_write (Lisp_Object symbol, enum symbol_trapped_write trap)
 {
   struct Lisp_Symbol *sym = XSYMBOL (symbol);
-  if (sym->trapped_write == SYMBOL_NOWRITE)
+  if (sym->u.s.trapped_write == SYMBOL_NOWRITE)
     xsignal1 (Qtrapping_constant, symbol);
-  sym->trapped_write = trap;
+  sym->u.s.trapped_write = trap;
 }
 
 static void
@@ -1469,7 +1469,7 @@ harmonize_variable_watchers (Lisp_Object alias, Lisp_Object base_variable)
   if (!EQ (base_variable, alias)
       && EQ (base_variable, Findirect_variable (alias)))
     set_symbol_trapped_write
-      (alias, XSYMBOL (base_variable)->trapped_write);
+      (alias, XSYMBOL (base_variable)->u.s.trapped_write);
 }
 
 DEFUN ("add-variable-watcher", Fadd_variable_watcher, Sadd_variable_watcher,
@@ -1583,7 +1583,7 @@ default_value (Lisp_Object symbol)
   sym = XSYMBOL (symbol);
 
  start:
-  switch (sym->redirect)
+  switch (sym->u.s.redirect)
     {
     case SYMBOL_VARALIAS: sym = indirect_variable (sym); goto start;
     case SYMBOL_PLAINVAL: return SYMBOL_VAL (sym);
@@ -1653,7 +1653,7 @@ set_default_internal (Lisp_Object symbol, Lisp_Object value,
 
   CHECK_SYMBOL (symbol);
   sym = XSYMBOL (symbol);
-  switch (sym->trapped_write)
+  switch (sym->u.s.trapped_write)
     {
     case SYMBOL_NOWRITE:
       if (NILP (Fkeywordp (symbol))
@@ -1665,7 +1665,7 @@ set_default_internal (Lisp_Object symbol, Lisp_Object value,
 
     case SYMBOL_TRAPPED_WRITE:
       /* Don't notify here if we're going to call Fset anyway.  */
-      if (sym->redirect != SYMBOL_PLAINVAL
+      if (sym->u.s.redirect != SYMBOL_PLAINVAL
           /* Setting due to thread switching doesn't count.  */
           && bindflag != SET_INTERNAL_THREAD_SWITCH)
         notify_variable_watchers (symbol, value, Qset_default, Qnil);
@@ -1677,7 +1677,7 @@ set_default_internal (Lisp_Object symbol, Lisp_Object value,
     }
 
  start:
-  switch (sym->redirect)
+  switch (sym->u.s.redirect)
     {
     case SYMBOL_VARALIAS: sym = indirect_variable (sym); goto start;
     case SYMBOL_PLAINVAL: set_internal (symbol, value, Qnil, bindflag); return;
@@ -1829,7 +1829,7 @@ The function `default-value' gets the default value and `set-default' sets it.
   sym = XSYMBOL (variable);
 
  start:
-  switch (sym->redirect)
+  switch (sym->u.s.redirect)
     {
     case SYMBOL_VARALIAS: sym = indirect_variable (sym); goto start;
     case SYMBOL_PLAINVAL:
@@ -1857,7 +1857,7 @@ The function `default-value' gets the default value and `set-default' sets it.
   if (!blv)
     {
       blv = make_blv (sym, forwarded, valcontents);
-      sym->redirect = SYMBOL_LOCALIZED;
+      sym->u.s.redirect = SYMBOL_LOCALIZED;
       SET_SYMBOL_BLV (sym, blv);
     }
 
@@ -1897,7 +1897,7 @@ Instead, use `add-hook' and specify t for the LOCAL argument.  */)
   sym = XSYMBOL (variable);
 
  start:
-  switch (sym->redirect)
+  switch (sym->u.s.redirect)
     {
     case SYMBOL_VARALIAS: sym = indirect_variable (sym); goto start;
     case SYMBOL_PLAINVAL:
@@ -1914,7 +1914,7 @@ Instead, use `add-hook' and specify t for the LOCAL argument.  */)
     default: emacs_abort ();
     }
 
-  if (sym->trapped_write == SYMBOL_NOWRITE)
+  if (sym->u.s.trapped_write == SYMBOL_NOWRITE)
     error ("Symbol %s may not be buffer-local",
 	   SDATA (SYMBOL_NAME (variable)));
 
@@ -1930,7 +1930,7 @@ Instead, use `add-hook' and specify t for the LOCAL argument.  */)
   if (!blv)
     {
       blv = make_blv (sym, forwarded, valcontents);
-      sym->redirect = SYMBOL_LOCALIZED;
+      sym->u.s.redirect = SYMBOL_LOCALIZED;
       SET_SYMBOL_BLV (sym, blv);
     }
 
@@ -1987,7 +1987,7 @@ From now on the default value will apply in this buffer.  Return VARIABLE.  */)
   sym = XSYMBOL (variable);
 
  start:
-  switch (sym->redirect)
+  switch (sym->u.s.redirect)
     {
     case SYMBOL_VARALIAS: sym = indirect_variable (sym); goto start;
     case SYMBOL_PLAINVAL: return variable;
@@ -2014,7 +2014,7 @@ From now on the default value will apply in this buffer.  Return VARIABLE.  */)
     default: emacs_abort ();
     }
 
-  if (sym->trapped_write == SYMBOL_TRAPPED_WRITE)
+  if (sym->u.s.trapped_write == SYMBOL_TRAPPED_WRITE)
     notify_variable_watchers (variable, Qnil, Qmakunbound, Fcurrent_buffer ());
 
   /* Get rid of this buffer's alist element, if any.  */
@@ -2056,7 +2056,7 @@ BUFFER defaults to the current buffer.  */)
   sym = XSYMBOL (variable);
 
  start:
-  switch (sym->redirect)
+  switch (sym->u.s.redirect)
     {
     case SYMBOL_VARALIAS: sym = indirect_variable (sym); goto start;
     case SYMBOL_PLAINVAL: return Qnil;
@@ -2110,7 +2110,7 @@ value in BUFFER, or if VARIABLE is automatically buffer-local (see
   sym = XSYMBOL (variable);
 
  start:
-  switch (sym->redirect)
+  switch (sym->u.s.redirect)
     {
     case SYMBOL_VARALIAS: sym = indirect_variable (sym); goto start;
     case SYMBOL_PLAINVAL: return Qnil;
@@ -2145,7 +2145,7 @@ If the current binding is global (the default), the value is nil.  */)
   find_symbol_value (variable);
 
  start:
-  switch (sym->redirect)
+  switch (sym->u.s.redirect)
     {
     case SYMBOL_VARALIAS: sym = indirect_variable (sym); goto start;
     case SYMBOL_PLAINVAL: return Qnil;
@@ -2163,7 +2163,7 @@ If the current binding is global (the default), the value is nil.  */)
 	 buffer's or frame's value we are saving.  */
       if (!NILP (Flocal_variable_p (variable, Qnil)))
 	return Fcurrent_buffer ();
-      else if (sym->redirect == SYMBOL_LOCALIZED
+      else if (sym->u.s.redirect == SYMBOL_LOCALIZED
 	       && blv_found (SYMBOL_BLV (sym)))
 	return SYMBOL_BLV (sym)->where;
       else
@@ -2234,12 +2234,12 @@ indirect_function (register Lisp_Object object)
     {
       if (!SYMBOLP (hare) || NILP (hare))
 	break;
-      hare = XSYMBOL (hare)->function;
+      hare = XSYMBOL (hare)->u.s.function;
       if (!SYMBOLP (hare) || NILP (hare))
 	break;
-      hare = XSYMBOL (hare)->function;
+      hare = XSYMBOL (hare)->u.s.function;
 
-      tortoise = XSYMBOL (tortoise)->function;
+      tortoise = XSYMBOL (tortoise)->u.s.function;
 
       if (EQ (hare, tortoise))
 	xsignal1 (Qcyclic_function_indirection, object);
@@ -2261,7 +2261,7 @@ function chain of symbols.  */)
   /* Optimize for no indirection.  */
   result = object;
   if (SYMBOLP (result) && !NILP (result)
-      && (result = XSYMBOL (result)->function, SYMBOLP (result)))
+      && (result = XSYMBOL (result)->u.s.function, SYMBOLP (result)))
     result = indirect_function (result);
   if (!NILP (result))
     return result;
@@ -3877,7 +3877,7 @@ syms_of_data (void)
   defsubr (&Sbool_vector_count_consecutive);
   defsubr (&Sbool_vector_count_population);
 
-  set_symbol_function (Qwholenump, XSYMBOL (Qnatnump)->function);
+  set_symbol_function (Qwholenump, XSYMBOL (Qnatnump)->u.s.function);
 
   DEFVAR_LISP ("most-positive-fixnum", Vmost_positive_fixnum,
 	       doc: /* The largest value that is representable in a Lisp integer.  */);
diff --git a/src/doc.c b/src/doc.c
index e81740bfc1..0cd62172c3 100644
--- a/src/doc.c
+++ b/src/doc.c
@@ -472,7 +472,7 @@ store_function_docstring (Lisp_Object obj, EMACS_INT offset)
 {
   /* Don't use indirect_function here, or defaliases will apply their
      docstrings to the base functions (Bug#2603).  */
-  Lisp_Object fun = SYMBOLP (obj) ? XSYMBOL (obj)->function : obj;
+  Lisp_Object fun = SYMBOLP (obj) ? XSYMBOL (obj)->u.s.function : obj;
 
   /* The type determines where the docstring is stored.  */
 
diff --git a/src/eval.c b/src/eval.c
index 52e4c96d4b..40b47968be 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -603,7 +603,7 @@ The return value is BASE-VARIABLE.  */)
 
   sym = XSYMBOL (new_alias);
 
-  switch (sym->redirect)
+  switch (sym->u.s.redirect)
     {
     case SYMBOL_FORWARDED:
       error ("Cannot make an internal variable an alias");
@@ -632,14 +632,14 @@ The return value is BASE-VARIABLE.  */)
 	error ("Don't know how to make a let-bound variable an alias");
   }
 
-  if (sym->trapped_write == SYMBOL_TRAPPED_WRITE)
+  if (sym->u.s.trapped_write == SYMBOL_TRAPPED_WRITE)
     notify_variable_watchers (new_alias, base_variable, Qdefvaralias, Qnil);
 
-  sym->declared_special = 1;
-  XSYMBOL (base_variable)->declared_special = 1;
-  sym->redirect = SYMBOL_VARALIAS;
+  sym->u.s.declared_special = true;
+  XSYMBOL (base_variable)->u.s.declared_special = true;
+  sym->u.s.redirect = SYMBOL_VARALIAS;
   SET_SYMBOL_ALIAS (sym, XSYMBOL (base_variable));
-  sym->trapped_write = XSYMBOL (base_variable)->trapped_write;
+  sym->u.s.trapped_write = XSYMBOL (base_variable)->u.s.trapped_write;
   LOADHIST_ATTACH (new_alias);
   /* Even if docstring is nil: remove old docstring.  */
   Fput (new_alias, Qvariable_documentation, docstring);
@@ -745,7 +745,7 @@ usage: (defvar SYMBOL &optional INITVALUE DOCSTRING)  */)
       tem = Fdefault_boundp (sym);
 
       /* Do it before evaluating the initial value, for self-references.  */
-      XSYMBOL (sym)->declared_special = 1;
+      XSYMBOL (sym)->u.s.declared_special = true;
 
       if (NILP (tem))
 	Fset_default (sym, eval_sub (XCAR (tail)));
@@ -769,7 +769,7 @@ usage: (defvar SYMBOL &optional INITVALUE DOCSTRING)  */)
       LOADHIST_ATTACH (sym);
     }
   else if (!NILP (Vinternal_interpreter_environment)
-	   && !XSYMBOL (sym)->declared_special)
+	   && !XSYMBOL (sym)->u.s.declared_special)
     /* A simple (defvar foo) with lexical scoping does "nothing" except
        declare that var to be dynamically scoped *locally* (i.e. within
        the current file or let-block).  */
@@ -818,7 +818,7 @@ usage: (defconst SYMBOL INITVALUE [DOCSTRING])  */)
   if (!NILP (Vpurify_flag))
     tem = Fpurecopy (tem);
   Fset_default (sym, tem);
-  XSYMBOL (sym)->declared_special = 1;
+  XSYMBOL (sym)->u.s.declared_special = true;
   if (!NILP (docstring))
     {
       if (!NILP (Vpurify_flag))
@@ -837,7 +837,7 @@ DEFUN ("internal-make-var-non-special", Fmake_var_non_special,
      (Lisp_Object symbol)
 {
   CHECK_SYMBOL (symbol);
-  XSYMBOL (symbol)->declared_special = 0;
+  XSYMBOL (symbol)->u.s.declared_special = false;
   return Qnil;
 }
 
@@ -877,7 +877,7 @@ usage: (let* VARLIST BODY...)  */)
 	}
 
       if (!NILP (lexenv) && SYMBOLP (var)
-	  && !XSYMBOL (var)->declared_special
+	  && !XSYMBOL (var)->u.s.declared_special
 	  && NILP (Fmemq (var, Vinternal_interpreter_environment)))
 	/* Lexically bind VAR by adding it to the interpreter's binding
 	   alist.  */
@@ -953,7 +953,7 @@ usage: (let VARLIST BODY...)  */)
       tem = temps[argnum];
 
       if (!NILP (lexenv) && SYMBOLP (var)
-	  && !XSYMBOL (var)->declared_special
+	  && !XSYMBOL (var)->u.s.declared_special
 	  && NILP (Fmemq (var, Vinternal_interpreter_environment)))
 	/* Lexically bind VAR by adding it to the lexenv alist.  */
 	lexenv = Fcons (Fcons (var, tem), lexenv);
@@ -1022,7 +1022,7 @@ definitions to shadow the loaded ones for use in file byte-compilation.  */)
 	  tem = Fassq (sym, environment);
 	  if (NILP (tem))
 	    {
-	      def = XSYMBOL (sym)->function;
+	      def = XSYMBOL (sym)->u.s.function;
 	      if (!NILP (def))
 		continue;
 	    }
@@ -1932,8 +1932,8 @@ this does nothing and returns nil.  */)
   CHECK_STRING (file);
 
   /* If function is defined and not as an autoload, don't override.  */
-  if (!NILP (XSYMBOL (function)->function)
-      && !AUTOLOADP (XSYMBOL (function)->function))
+  if (!NILP (XSYMBOL (function)->u.s.function)
+      && !AUTOLOADP (XSYMBOL (function)->u.s.function))
     return Qnil;
 
   if (!NILP (Vpurify_flag) && EQ (docstring, make_number (0)))
@@ -2164,7 +2164,7 @@ eval_sub (Lisp_Object form)
   fun = original_fun;
   if (!SYMBOLP (fun))
     fun = Ffunction (Fcons (fun, Qnil));
-  else if (!NILP (fun) && (fun = XSYMBOL (fun)->function, SYMBOLP (fun)))
+  else if (!NILP (fun) && (fun = XSYMBOL (fun)->u.s.function, SYMBOLP (fun)))
     fun = indirect_function (fun);
 
   if (SUBRP (fun))
@@ -2347,7 +2347,7 @@ usage: (apply FUNCTION &rest ARGUMENTS)  */)
 
   /* Optimize for no indirection.  */
   if (SYMBOLP (fun) && !NILP (fun)
-      && (fun = XSYMBOL (fun)->function, SYMBOLP (fun)))
+      && (fun = XSYMBOL (fun)->u.s.function, SYMBOLP (fun)))
     {
       fun = indirect_function (fun);
       if (NILP (fun))
@@ -2759,7 +2759,7 @@ usage: (funcall FUNCTION &rest ARGUMENTS)  */)
   /* Optimize for no indirection.  */
   fun = original_fun;
   if (SYMBOLP (fun) && !NILP (fun)
-      && (fun = XSYMBOL (fun)->function, SYMBOLP (fun)))
+      && (fun = XSYMBOL (fun)->u.s.function, SYMBOLP (fun)))
     fun = indirect_function (fun);
 
   if (SUBRP (fun))
@@ -3075,7 +3075,7 @@ function with `&rest' args, or `unevalled' for a special form.  */)
   function = original;
   if (SYMBOLP (function) && !NILP (function))
     {
-      function = XSYMBOL (function)->function;
+      function = XSYMBOL (function)->u.s.function;
       if (SYMBOLP (function))
 	function = indirect_function (function);
     }
@@ -3214,7 +3214,7 @@ let_shadows_buffer_binding_p (struct Lisp_Symbol *symbol)
     if ((--p)->kind > SPECPDL_LET)
       {
 	struct Lisp_Symbol *let_bound_symbol = XSYMBOL (specpdl_symbol (p));
-	eassert (let_bound_symbol->redirect != SYMBOL_VARALIAS);
+	eassert (let_bound_symbol->u.s.redirect != SYMBOL_VARALIAS);
 	if (symbol == let_bound_symbol
 	    && EQ (specpdl_where (p), buf))
 	  return 1;
@@ -3227,10 +3227,10 @@ static void
 do_specbind (struct Lisp_Symbol *sym, union specbinding *bind,
              Lisp_Object value, enum Set_Internal_Bind bindflag)
 {
-  switch (sym->redirect)
+  switch (sym->u.s.redirect)
     {
     case SYMBOL_PLAINVAL:
-      if (!sym->trapped_write)
+      if (!sym->u.s.trapped_write)
 	SET_SYMBOL_VAL (sym, value);
       else
         set_internal (specpdl_symbol (bind), value, Qnil, bindflag);
@@ -3274,7 +3274,7 @@ specbind (Lisp_Object symbol, Lisp_Object value)
   sym = XSYMBOL (symbol);
 
  start:
-  switch (sym->redirect)
+  switch (sym->u.s.redirect)
     {
     case SYMBOL_VARALIAS:
       sym = indirect_variable (sym); XSETSYMBOL (symbol, sym); goto start;
@@ -3298,10 +3298,10 @@ specbind (Lisp_Object symbol, Lisp_Object value)
 	specpdl_ptr->let.where = Fcurrent_buffer ();
 	specpdl_ptr->let.saved_value = Qnil;
 
-	eassert (sym->redirect != SYMBOL_LOCALIZED
+	eassert (sym->u.s.redirect != SYMBOL_LOCALIZED
 		 || (EQ (SYMBOL_BLV (sym)->where, Fcurrent_buffer ())));
 
-	if (sym->redirect == SYMBOL_LOCALIZED)
+	if (sym->u.s.redirect == SYMBOL_LOCALIZED)
 	  {
 	    if (!blv_found (SYMBOL_BLV (sym)))
 	      specpdl_ptr->let.kind = SPECPDL_LET_DEFAULT;
@@ -3412,9 +3412,9 @@ do_one_unbind (union specbinding *this_binding, bool unwinding,
       { /* If variable has a trivial value (no forwarding), and isn't
 	   trapped, we can just set it.  */
 	Lisp_Object sym = specpdl_symbol (this_binding);
-	if (SYMBOLP (sym) && XSYMBOL (sym)->redirect == SYMBOL_PLAINVAL)
+	if (SYMBOLP (sym) && XSYMBOL (sym)->u.s.redirect == SYMBOL_PLAINVAL)
 	  {
-	    if (XSYMBOL (sym)->trapped_write == SYMBOL_UNTRAPPED_WRITE)
+	    if (XSYMBOL (sym)->u.s.trapped_write == SYMBOL_UNTRAPPED_WRITE)
 	      SET_SYMBOL_VAL (XSYMBOL (sym), specpdl_old_value (this_binding));
 	    else
 	      set_internal (sym, specpdl_old_value (this_binding),
@@ -3546,7 +3546,7 @@ context where binding is lexical by default.  */)
   (Lisp_Object symbol)
 {
    CHECK_SYMBOL (symbol);
-   return XSYMBOL (symbol)->declared_special ? Qt : Qnil;
+   return XSYMBOL (symbol)->u.s.declared_special ? Qt : Qnil;
 }
 
 \f
@@ -3702,7 +3702,8 @@ backtrace_eval_unrewind (int distance)
 	       just set it.  No need to check for constant symbols here,
 	       since that was already done by specbind.  */
 	    Lisp_Object sym = specpdl_symbol (tmp);
-	    if (SYMBOLP (sym) && XSYMBOL (sym)->redirect == SYMBOL_PLAINVAL)
+	    if (SYMBOLP (sym)
+		&& XSYMBOL (sym)->u.s.redirect == SYMBOL_PLAINVAL)
 	      {
 		Lisp_Object old_value = specpdl_old_value (tmp);
 		set_specpdl_old_value (tmp, SYMBOL_VAL (XSYMBOL (sym)));
diff --git a/src/fns.c b/src/fns.c
index 2311a6e041..42859344bd 100644
--- a/src/fns.c
+++ b/src/fns.c
@@ -1993,7 +1993,7 @@ This is the last value stored with `(put SYMBOL PROPNAME VALUE)'.  */)
                                     propname);
   if (!NILP (propval))
     return propval;
-  return Fplist_get (XSYMBOL (symbol)->plist, propname);
+  return Fplist_get (XSYMBOL (symbol)->u.s.plist, propname);
 }
 
 DEFUN ("plist-put", Fplist_put, Splist_put, 3, 3, 0,
@@ -2039,7 +2039,7 @@ It can be retrieved with `(get SYMBOL PROPNAME)'.  */)
 {
   CHECK_SYMBOL (symbol);
   set_symbol_plist
-    (symbol, Fplist_put (XSYMBOL (symbol)->plist, propname, value));
+    (symbol, Fplist_put (XSYMBOL (symbol)->u.s.plist, propname, value));
   return value;
 }
 \f
diff --git a/src/keyboard.c b/src/keyboard.c
index 7ddd6b9674..57757cf211 100644
--- a/src/keyboard.c
+++ b/src/keyboard.c
@@ -7901,7 +7901,7 @@ parse_menu_item (Lisp_Object item, int inmenubar)
 		       (such as lmenu.el set it up), check if the
 		       original command matches the cached command.  */
 		    && !(SYMBOLP (def)
-			 && EQ (tem, XSYMBOL (def)->function))))
+			 && EQ (tem, XSYMBOL (def)->u.s.function))))
 	      keys = Qnil;
 	  }
 
@@ -8761,9 +8761,9 @@ access_keymap_keyremap (Lisp_Object map, Lisp_Object key, Lisp_Object prompt,
   /* Handle a symbol whose function definition is a keymap
      or an array.  */
   if (SYMBOLP (next) && !NILP (Ffboundp (next))
-      && (ARRAYP (XSYMBOL (next)->function)
-	  || KEYMAPP (XSYMBOL (next)->function)))
-    next = Fautoload_do_load (XSYMBOL (next)->function, next, Qnil);
+      && (ARRAYP (XSYMBOL (next)->u.s.function)
+	  || KEYMAPP (XSYMBOL (next)->u.s.function)))
+    next = Fautoload_do_load (XSYMBOL (next)->u.s.function, next, Qnil);
 
   /* If the keymap gives a function, not an
      array, then call the function with one arg and use
@@ -11510,7 +11510,7 @@ for that character after that prefix key.  */);
 	       doc: /* Form to evaluate when Emacs starts up.
 Useful to set before you dump a modified Emacs.  */);
   Vtop_level = Qnil;
-  XSYMBOL (Qtop_level)->declared_special = false;
+  XSYMBOL (Qtop_level)->u.s.declared_special = false;
 
   DEFVAR_KBOARD ("keyboard-translate-table", Vkeyboard_translate_table,
                  doc: /* Translate table for local keyboard input, or nil.
diff --git a/src/lisp.h b/src/lisp.h
index 1d6fd5a4fe..e9aec4c597 100644
--- a/src/lisp.h
+++ b/src/lisp.h
@@ -229,7 +229,7 @@ extern bool suppress_checking EXTERNALLY_VISIBLE;
    USE_LSB_TAG not only requires the least 3 bits of pointers returned by
    malloc to be 0 but also needs to be able to impose a mult-of-8 alignment
    on the few static Lisp_Objects used, all of which are aligned via
-   the GCALIGN macro defined below.  */
+   'char alignas (GCALIGNMENT) gcaligned;' inside a union.  */
 
 enum Lisp_Bits
   {
@@ -277,20 +277,6 @@ DEFINE_GDB_SYMBOL_END (VALMASK)
 error !;
 #endif
 
-/* Use GCALIGNED immediately after the 'struct' keyword to require the
-   struct to have an address that is a multiple of GCALIGNMENT.  This
-   is a no-op if the struct's natural alignment is already a multiple
-   of GCALIGNMENT.  GCALIGNED's implementation uses the 'aligned'
-   attribute instead of 'alignas (GCALIGNMENT)', as the latter would
-   fail if an object's natural alignment exceeds GCALIGNMENT.  The
-   implementation hopes that natural alignment suffices on platforms
-   lacking 'aligned'.  */
-#ifdef HAVE_STRUCT_ATTRIBUTE_ALIGNED
-# define GCALIGNED __attribute__ ((aligned (GCALIGNMENT)))
-#else
-# define GCALIGNED /* empty */
-#endif
-
 /* Some operations are so commonly executed that they are implemented
    as macros, not functions, because otherwise runtime performance would
    suffer too much when compiling with GCC without optimization.
@@ -338,15 +324,17 @@ error !;
 #define lisp_h_MISCP(x) (XTYPE (x) == Lisp_Misc)
 #define lisp_h_NILP(x) EQ (x, Qnil)
 #define lisp_h_SET_SYMBOL_VAL(sym, v) \
-   (eassert ((sym)->redirect == SYMBOL_PLAINVAL), (sym)->val.value = (v))
-#define lisp_h_SYMBOL_CONSTANT_P(sym) (XSYMBOL (sym)->trapped_write == SYMBOL_NOWRITE)
-#define lisp_h_SYMBOL_TRAPPED_WRITE_P(sym) (XSYMBOL (sym)->trapped_write)
+   (eassert ((sym)->u.s.redirect == SYMBOL_PLAINVAL), \
+    (sym)->u.s.val.value = (v))
+#define lisp_h_SYMBOL_CONSTANT_P(sym) \
+   (XSYMBOL (sym)->u.s.trapped_write == SYMBOL_NOWRITE)
+#define lisp_h_SYMBOL_TRAPPED_WRITE_P(sym) (XSYMBOL (sym)->u.s.trapped_write)
 #define lisp_h_SYMBOL_VAL(sym) \
-   (eassert ((sym)->redirect == SYMBOL_PLAINVAL), (sym)->val.value)
+   (eassert ((sym)->u.s.redirect == SYMBOL_PLAINVAL), (sym)->u.s.val.value)
 #define lisp_h_SYMBOLP(x) (XTYPE (x) == Lisp_Symbol)
 #define lisp_h_VECTORLIKEP(x) (XTYPE (x) == Lisp_Vectorlike)
-#define lisp_h_XCAR(c) XCONS (c)->car
-#define lisp_h_XCDR(c) XCONS (c)->u.cdr
+#define lisp_h_XCAR(c) XCONS (c)->u.s.car
+#define lisp_h_XCDR(c) XCONS (c)->u.s.u.cdr
 #define lisp_h_XCONS(a) \
    (eassert (CONSP (a)), (struct Lisp_Cons *) XUNTAG (a, Lisp_Cons))
 #define lisp_h_XHASH(a) XUINT (a)
@@ -677,52 +665,60 @@ enum symbol_trapped_write
 
 struct Lisp_Symbol
 {
-  bool_bf gcmarkbit : 1;
-
-  /* Indicates where the value can be found:
-     0 : it's a plain var, the value is in the `value' field.
-     1 : it's a varalias, the value is really in the `alias' symbol.
-     2 : it's a localized var, the value is in the `blv' object.
-     3 : it's a forwarding variable, the value is in `forward'.  */
-  ENUM_BF (symbol_redirect) redirect : 3;
-
-  /* 0 : normal case, just set the value
-     1 : constant, cannot set, e.g. nil, t, :keywords.
-     2 : trap the write, call watcher functions.  */
-  ENUM_BF (symbol_trapped_write) trapped_write : 2;
-
-  /* Interned state of the symbol.  This is an enumerator from
-     enum symbol_interned.  */
-  unsigned interned : 2;
-
-  /* True means that this variable has been explicitly declared
-     special (with `defvar' etc), and shouldn't be lexically bound.  */
-  bool_bf declared_special : 1;
-
-  /* True if pointed to from purespace and hence can't be GC'd.  */
-  bool_bf pinned : 1;
-
-  /* The symbol's name, as a Lisp string.  */
-  Lisp_Object name;
-
-  /* Value of the symbol or Qunbound if unbound.  Which alternative of the
-     union is used depends on the `redirect' field above.  */
-  union {
-    Lisp_Object value;
-    struct Lisp_Symbol *alias;
-    struct Lisp_Buffer_Local_Value *blv;
-    union Lisp_Fwd *fwd;
-  } val;
-
-  /* Function value of the symbol or Qnil if not fboundp.  */
-  Lisp_Object function;
+  union
+  {
+    struct
+    {
+      bool_bf gcmarkbit : 1;
+
+      /* Indicates where the value can be found:
+	 0 : it's a plain var, the value is in the `value' field.
+	 1 : it's a varalias, the value is really in the `alias' symbol.
+	 2 : it's a localized var, the value is in the `blv' object.
+	 3 : it's a forwarding variable, the value is in `forward'.  */
+      ENUM_BF (symbol_redirect) redirect : 3;
+
+      /* 0 : normal case, just set the value
+	 1 : constant, cannot set, e.g. nil, t, :keywords.
+	 2 : trap the write, call watcher functions.  */
+      ENUM_BF (symbol_trapped_write) trapped_write : 2;
+
+      /* Interned state of the symbol.  This is an enumerator from
+	 enum symbol_interned.  */
+      unsigned interned : 2;
+
+      /* True means that this variable has been explicitly declared
+	 special (with `defvar' etc), and shouldn't be lexically bound.  */
+      bool_bf declared_special : 1;
+
+      /* True if pointed to from purespace and hence can't be GC'd.  */
+      bool_bf pinned : 1;
+
+      /* The symbol's name, as a Lisp string.  */
+      Lisp_Object name;
+
+      /* Value of the symbol or Qunbound if unbound.  Which alternative of the
+	 union is used depends on the `redirect' field above.  */
+      union {
+	Lisp_Object value;
+	struct Lisp_Symbol *alias;
+	struct Lisp_Buffer_Local_Value *blv;
+	union Lisp_Fwd *fwd;
+      } val;
+
+      /* Function value of the symbol or Qnil if not fboundp.  */
+      Lisp_Object function;
 
-  /* The symbol's property list.  */
-  Lisp_Object plist;
+      /* The symbol's property list.  */
+      Lisp_Object plist;
 
-  /* Next symbol in obarray bucket, if the symbol is interned.  */
-  struct Lisp_Symbol *next;
+      /* Next symbol in obarray bucket, if the symbol is interned.  */
+      struct Lisp_Symbol *next;
+    } s;
+    char alignas (GCALIGNMENT) gcaligned;
+  } u;
 };
+verify (alignof (struct Lisp_Symbol) % GCALIGNMENT == 0);
 
 /* Declare a Lisp-callable function.  The MAXARGS parameter has the same
    meaning as in the DEFUN macro, and is used to construct a prototype.  */
@@ -802,7 +798,7 @@ struct Lisp_Symbol
    Bug#8546.  */
 union vectorlike_header
   {
-    /* The only field contains various pieces of information:
+    /* The main member contains various pieces of information:
        - The MSB (ARRAY_MARK_FLAG) holds the gcmarkbit.
        - The next bit (PSEUDOVECTOR_FLAG) indicates whether this is a plain
          vector (0) or a pseudovector (1).
@@ -822,7 +818,9 @@ union vectorlike_header
 	 Current layout limits the pseudovectors to 63 PVEC_xxx subtypes,
 	 4095 Lisp_Objects in GC-ed area and 4095 word-sized other slots.  */
     ptrdiff_t size;
+    char alignas (GCALIGNMENT) gcaligned;
   };
+verify (alignof (union vectorlike_header) % GCALIGNMENT == 0);
 
 INLINE bool
 (SYMBOLP) (Lisp_Object x)
@@ -854,7 +852,7 @@ make_lisp_symbol (struct Lisp_Symbol *sym)
 INLINE Lisp_Object
 builtin_lisp_symbol (int index)
 {
-  return make_lisp_symbol (&lispsym[index].s);
+  return make_lisp_symbol (&lispsym[index]);
 }
 
 INLINE void
@@ -1144,20 +1142,28 @@ make_pointer_integer (void *p)
 
 typedef struct interval *INTERVAL;
 
-struct GCALIGNED Lisp_Cons
+struct Lisp_Cons
+{
+  union
   {
-    /* Car of this cons cell.  */
-    Lisp_Object car;
-
-    union
+    struct
     {
-      /* Cdr of this cons cell.  */
-      Lisp_Object cdr;
-
-      /* Used to chain conses on a free list.  */
-      struct Lisp_Cons *chain;
-    } u;
-  };
+      /* Car of this cons cell.  */
+      Lisp_Object car;
+
+      union
+      {
+	/* Cdr of this cons cell.  */
+	Lisp_Object cdr;
+
+	/* Used to chain conses on a free list.  */
+	struct Lisp_Cons *chain;
+      } u;
+    } s;
+    char alignas (GCALIGNMENT) gcaligned;
+  } u;
+};
+verify (alignof (struct Lisp_Cons) % GCALIGNMENT == 0);
 
 INLINE bool
 (NILP) (Lisp_Object x)
@@ -1193,12 +1199,12 @@ INLINE struct Lisp_Cons *
 INLINE Lisp_Object *
 xcar_addr (Lisp_Object c)
 {
-  return &XCONS (c)->car;
+  return &XCONS (c)->u.s.car;
 }
 INLINE Lisp_Object *
 xcdr_addr (Lisp_Object c)
 {
-  return &XCONS (c)->u.cdr;
+  return &XCONS (c)->u.s.u.cdr;
 }
 
 /* Use these from normal code.  */
@@ -1262,15 +1268,24 @@ CDR_SAFE (Lisp_Object c)
   return CONSP (c) ? XCDR (c) : Qnil;
 }
 
-/* In a string or vector, the sign bit of the `size' is the gc mark bit.  */
+/* In a string or vector, the sign bit of u.s.size is the gc mark bit.  */
 
-struct GCALIGNED Lisp_String
+struct Lisp_String
+{
+  union
   {
-    ptrdiff_t size;
-    ptrdiff_t size_byte;
-    INTERVAL intervals;		/* Text properties in this string.  */
-    unsigned char *data;
-  };
+    struct
+    {
+      ptrdiff_t size;
+      ptrdiff_t size_byte;
+      INTERVAL intervals;	/* Text properties in this string.  */
+      unsigned char *data;
+    } s;
+    struct Lisp_String *next;
+    char alignas (GCALIGNMENT) gcaligned;
+  } u;
+};
+verify (alignof (struct Lisp_String) % GCALIGNMENT == 0);
 
 INLINE bool
 STRINGP (Lisp_Object x)
@@ -1295,7 +1310,7 @@ XSTRING (Lisp_Object a)
 INLINE bool
 STRING_MULTIBYTE (Lisp_Object str)
 {
-  return 0 <= XSTRING (str)->size_byte;
+  return 0 <= XSTRING (str)->u.s.size_byte;
 }
 
 /* An upper bound on the number of bytes in a Lisp string, not
@@ -1317,20 +1332,20 @@ STRING_MULTIBYTE (Lisp_Object str)
 /* Mark STR as a unibyte string.  */
 #define STRING_SET_UNIBYTE(STR)				\
   do {							\
-    if (XSTRING (STR)->size == 0)			\
+    if (XSTRING (STR)->u.s.size == 0)			\
       (STR) = empty_unibyte_string;			\
     else						\
-      XSTRING (STR)->size_byte = -1;			\
+      XSTRING (STR)->u.s.size_byte = -1;		\
   } while (false)
 
 /* Mark STR as a multibyte string.  Assure that STR contains only
    ASCII characters in advance.  */
 #define STRING_SET_MULTIBYTE(STR)			\
   do {							\
-    if (XSTRING (STR)->size == 0)			\
+    if (XSTRING (STR)->u.s.size == 0)			\
       (STR) = empty_multibyte_string;			\
     else						\
-      XSTRING (STR)->size_byte = XSTRING (STR)->size;	\
+      XSTRING (STR)->u.s.size_byte = XSTRING (STR)->u.s.size; \
   } while (false)
 
 /* Convenience functions for dealing with Lisp strings.  */
@@ -1338,7 +1353,7 @@ STRING_MULTIBYTE (Lisp_Object str)
 INLINE unsigned char *
 SDATA (Lisp_Object string)
 {
-  return XSTRING (string)->data;
+  return XSTRING (string)->u.s.data;
 }
 INLINE char *
 SSDATA (Lisp_Object string)
@@ -1359,7 +1374,7 @@ SSET (Lisp_Object string, ptrdiff_t index, unsigned char new)
 INLINE ptrdiff_t
 SCHARS (Lisp_Object string)
 {
-  ptrdiff_t nchars = XSTRING (string)->size;
+  ptrdiff_t nchars = XSTRING (string)->u.s.size;
   eassume (0 <= nchars);
   return nchars;
 }
@@ -1373,7 +1388,7 @@ STRING_BYTES (struct Lisp_String *s)
 #ifdef GC_CHECK_STRING_BYTES
   ptrdiff_t nbytes = string_bytes (s);
 #else
-  ptrdiff_t nbytes = s->size_byte < 0 ? s->size : s->size_byte;
+  ptrdiff_t nbytes = s->u.s.size_byte < 0 ? s->u.s.size : s->u.s.size_byte;
 #endif
   eassume (0 <= nbytes);
   return nbytes;
@@ -1392,7 +1407,7 @@ STRING_SET_CHARS (Lisp_Object string, ptrdiff_t newsize)
   eassert (STRING_MULTIBYTE (string)
 	   ? 0 <= newsize && newsize <= SBYTES (string)
 	   : newsize == SCHARS (string));
-  XSTRING (string)->size = newsize;
+  XSTRING (string)->u.s.size = newsize;
 }
 
 /* A regular vector is just a header plus an array of Lisp_Objects.  */
@@ -1910,20 +1925,20 @@ INLINE Lisp_Object
 INLINE struct Lisp_Symbol *
 SYMBOL_ALIAS (struct Lisp_Symbol *sym)
 {
-  eassume (sym->redirect == SYMBOL_VARALIAS && sym->val.alias);
-  return sym->val.alias;
+  eassume (sym->u.s.redirect == SYMBOL_VARALIAS && sym->u.s.val.alias);
+  return sym->u.s.val.alias;
 }
 INLINE struct Lisp_Buffer_Local_Value *
 SYMBOL_BLV (struct Lisp_Symbol *sym)
 {
-  eassume (sym->redirect == SYMBOL_LOCALIZED && sym->val.blv);
-  return sym->val.blv;
+  eassume (sym->u.s.redirect == SYMBOL_LOCALIZED && sym->u.s.val.blv);
+  return sym->u.s.val.blv;
 }
 INLINE union Lisp_Fwd *
 SYMBOL_FWD (struct Lisp_Symbol *sym)
 {
-  eassume (sym->redirect == SYMBOL_FORWARDED && sym->val.fwd);
-  return sym->val.fwd;
+  eassume (sym->u.s.redirect == SYMBOL_FORWARDED && sym->u.s.val.fwd);
+  return sym->u.s.val.fwd;
 }
 
 INLINE void
@@ -1935,26 +1950,26 @@ INLINE void
 INLINE void
 SET_SYMBOL_ALIAS (struct Lisp_Symbol *sym, struct Lisp_Symbol *v)
 {
-  eassume (sym->redirect == SYMBOL_VARALIAS && v);
-  sym->val.alias = v;
+  eassume (sym->u.s.redirect == SYMBOL_VARALIAS && v);
+  sym->u.s.val.alias = v;
 }
 INLINE void
 SET_SYMBOL_BLV (struct Lisp_Symbol *sym, struct Lisp_Buffer_Local_Value *v)
 {
-  eassume (sym->redirect == SYMBOL_LOCALIZED && v);
-  sym->val.blv = v;
+  eassume (sym->u.s.redirect == SYMBOL_LOCALIZED && v);
+  sym->u.s.val.blv = v;
 }
 INLINE void
 SET_SYMBOL_FWD (struct Lisp_Symbol *sym, union Lisp_Fwd *v)
 {
-  eassume (sym->redirect == SYMBOL_FORWARDED && v);
-  sym->val.fwd = v;
+  eassume (sym->u.s.redirect == SYMBOL_FORWARDED && v);
+  sym->u.s.val.fwd = v;
 }
 
 INLINE Lisp_Object
 SYMBOL_NAME (Lisp_Object sym)
 {
-  return XSYMBOL (sym)->name;
+  return XSYMBOL (sym)->u.s.name;
 }
 
 /* Value is true if SYM is an interned symbol.  */
@@ -1962,7 +1977,7 @@ SYMBOL_NAME (Lisp_Object sym)
 INLINE bool
 SYMBOL_INTERNED_P (Lisp_Object sym)
 {
-  return XSYMBOL (sym)->interned != SYMBOL_UNINTERNED;
+  return XSYMBOL (sym)->u.s.interned != SYMBOL_UNINTERNED;
 }
 
 /* Value is true if SYM is interned in initial_obarray.  */
@@ -1970,7 +1985,7 @@ SYMBOL_INTERNED_P (Lisp_Object sym)
 INLINE bool
 SYMBOL_INTERNED_IN_INITIAL_OBARRAY_P (Lisp_Object sym)
 {
-  return XSYMBOL (sym)->interned == SYMBOL_INTERNED_IN_INITIAL_OBARRAY;
+  return XSYMBOL (sym)->u.s.interned == SYMBOL_INTERNED_IN_INITIAL_OBARRAY;
 }
 
 /* Value is non-zero if symbol cannot be changed through a simple set,
@@ -2948,7 +2963,7 @@ CHECK_NUMBER_CDR (Lisp_Object x)
 #ifdef _MSC_VER
 #define DEFUN(lname, fnname, sname, minargs, maxargs, intspec, doc)	\
    Lisp_Object fnname DEFUN_ARGS_ ## maxargs ;				\
-   static struct GCALIGNED Lisp_Subr sname =				\
+   static struct Lisp_Subr sname =				\
    { { (PVEC_SUBR << PSEUDOVECTOR_AREA_BITS)				\
        | (sizeof (struct Lisp_Subr) / sizeof (EMACS_INT)) },		\
       { (Lisp_Object (__cdecl *)(void))fnname },                        \
@@ -2956,7 +2971,7 @@ CHECK_NUMBER_CDR (Lisp_Object x)
    Lisp_Object fnname
 #else  /* not _MSC_VER */
 #define DEFUN(lname, fnname, sname, minargs, maxargs, intspec, doc)	\
-   static struct GCALIGNED Lisp_Subr sname =				\
+   static struct Lisp_Subr sname =				\
      { { PVEC_SUBR << PSEUDOVECTOR_AREA_BITS },				\
        { .a ## maxargs = fnname },					\
        minargs, maxargs, lname, intspec, 0};				\
@@ -3224,25 +3239,25 @@ set_hash_value_slot (struct Lisp_Hash_Table *h, ptrdiff_t idx, Lisp_Object val)
 INLINE void
 set_symbol_function (Lisp_Object sym, Lisp_Object function)
 {
-  XSYMBOL (sym)->function = function;
+  XSYMBOL (sym)->u.s.function = function;
 }
 
 INLINE void
 set_symbol_plist (Lisp_Object sym, Lisp_Object plist)
 {
-  XSYMBOL (sym)->plist = plist;
+  XSYMBOL (sym)->u.s.plist = plist;
 }
 
 INLINE void
 set_symbol_next (Lisp_Object sym, struct Lisp_Symbol *next)
 {
-  XSYMBOL (sym)->next = next;
+  XSYMBOL (sym)->u.s.next = next;
 }
 
 INLINE void
 make_symbol_constant (Lisp_Object sym)
 {
-  XSYMBOL (sym)->trapped_write = SYMBOL_NOWRITE;
+  XSYMBOL (sym)->u.s.trapped_write = SYMBOL_NOWRITE;
 }
 
 /* Buffer-local variable access functions.  */
@@ -3267,7 +3282,7 @@ set_overlay_plist (Lisp_Object overlay, Lisp_Object plist)
 INLINE INTERVAL
 string_intervals (Lisp_Object s)
 {
-  return XSTRING (s)->intervals;
+  return XSTRING (s)->u.s.intervals;
 }
 
 /* Set text properties of S to I.  */
@@ -3275,7 +3290,7 @@ string_intervals (Lisp_Object s)
 INLINE void
 set_string_intervals (Lisp_Object s, INTERVAL i)
 {
-  XSTRING (s)->intervals = i;
+  XSTRING (s)->u.s.intervals = i;
 }
 
 /* Set a Lisp slot in TABLE to VAL.  Most code should use this instead
@@ -4600,20 +4615,6 @@ enum { defined_GC_CHECK_STRING_BYTES = true };
 enum { defined_GC_CHECK_STRING_BYTES = false };
 #endif
 
-/* Struct inside unions that are typically no larger and aligned enough.  */
-
-union Aligned_Cons
-{
-  struct Lisp_Cons s;
-  double d; intmax_t i; void *p;
-};
-
-union Aligned_String
-{
-  struct Lisp_String s;
-  double d; intmax_t i; void *p;
-};
-
 /* True for stack-based cons and string implementations, respectively.
    Use stack-based strings only if stack-based cons also works.
    Otherwise, STACK_CONS would create heap-based cons cells that
@@ -4621,18 +4622,16 @@ union Aligned_String
 
 enum
   {
-    USE_STACK_CONS = (USE_STACK_LISP_OBJECTS
-		      && alignof (union Aligned_Cons) % GCALIGNMENT == 0),
+    USE_STACK_CONS = USE_STACK_LISP_OBJECTS,
     USE_STACK_STRING = (USE_STACK_CONS
-			&& !defined_GC_CHECK_STRING_BYTES
-			&& alignof (union Aligned_String) % GCALIGNMENT == 0)
+			&& !defined_GC_CHECK_STRING_BYTES)
   };
 
 /* Auxiliary macros used for auto allocation of Lisp objects.  Please
    use these only in macros like AUTO_CONS that declare a local
    variable whose lifetime will be clear to the programmer.  */
 #define STACK_CONS(a, b) \
-  make_lisp_ptr (&((union Aligned_Cons) { { a, { b } } }).s, Lisp_Cons)
+  make_lisp_ptr (&((struct Lisp_Cons) {{{a, {b}}}}), Lisp_Cons)
 #define AUTO_CONS_EXPR(a, b) \
   (USE_STACK_CONS ? STACK_CONS (a, b) : Fcons (a, b))
 
@@ -4678,7 +4677,7 @@ enum
   Lisp_Object name =							\
     (USE_STACK_STRING							\
      ? (make_lisp_ptr							\
-	((&((union Aligned_String) {{len, -1, 0, (unsigned char *) (str)}}).s), \
+	((&(struct Lisp_String) {{{len, -1, 0, (unsigned char *) (str)}}}), \
 	 Lisp_String))							\
      : make_unibyte_string (str, len))
 
diff --git a/src/lread.c b/src/lread.c
index 33da866722..b056f4aaf3 100644
--- a/src/lread.c
+++ b/src/lread.c
@@ -4043,14 +4043,14 @@ intern_sym (Lisp_Object sym, Lisp_Object obarray, Lisp_Object index)
 {
   Lisp_Object *ptr;
 
-  XSYMBOL (sym)->interned = (EQ (obarray, initial_obarray)
-			     ? SYMBOL_INTERNED_IN_INITIAL_OBARRAY
-			     : SYMBOL_INTERNED);
+  XSYMBOL (sym)->u.s.interned = (EQ (obarray, initial_obarray)
+				 ? SYMBOL_INTERNED_IN_INITIAL_OBARRAY
+				 : SYMBOL_INTERNED);
 
   if (SREF (SYMBOL_NAME (sym), 0) == ':' && EQ (obarray, initial_obarray))
     {
       make_symbol_constant (sym);
-      XSYMBOL (sym)->redirect = SYMBOL_PLAINVAL;
+      XSYMBOL (sym)->u.s.redirect = SYMBOL_PLAINVAL;
       SET_SYMBOL_VAL (XSYMBOL (sym), sym);
     }
 
@@ -4203,16 +4203,16 @@ usage: (unintern NAME OBARRAY)  */)
   /* if (EQ (tem, Qnil) || EQ (tem, Qt))
        error ("Attempt to unintern t or nil"); */
 
-  XSYMBOL (tem)->interned = SYMBOL_UNINTERNED;
+  XSYMBOL (tem)->u.s.interned = SYMBOL_UNINTERNED;
 
   hash = oblookup_last_bucket_number;
 
   if (EQ (AREF (obarray, hash), tem))
     {
-      if (XSYMBOL (tem)->next)
+      if (XSYMBOL (tem)->u.s.next)
 	{
 	  Lisp_Object sym;
-	  XSETSYMBOL (sym, XSYMBOL (tem)->next);
+	  XSETSYMBOL (sym, XSYMBOL (tem)->u.s.next);
 	  ASET (obarray, hash, sym);
 	}
       else
@@ -4223,13 +4223,13 @@ usage: (unintern NAME OBARRAY)  */)
       Lisp_Object tail, following;
 
       for (tail = AREF (obarray, hash);
-	   XSYMBOL (tail)->next;
+	   XSYMBOL (tail)->u.s.next;
 	   tail = following)
 	{
-	  XSETSYMBOL (following, XSYMBOL (tail)->next);
+	  XSETSYMBOL (following, XSYMBOL (tail)->u.s.next);
 	  if (EQ (following, tem))
 	    {
-	      set_symbol_next (tail, XSYMBOL (following)->next);
+	      set_symbol_next (tail, XSYMBOL (following)->u.s.next);
 	      break;
 	    }
 	}
@@ -4264,13 +4264,13 @@ oblookup (Lisp_Object obarray, register const char *ptr, ptrdiff_t size, ptrdiff
   else if (!SYMBOLP (bucket))
     error ("Bad data in guts of obarray"); /* Like CADR error message.  */
   else
-    for (tail = bucket; ; XSETSYMBOL (tail, XSYMBOL (tail)->next))
+    for (tail = bucket; ; XSETSYMBOL (tail, XSYMBOL (tail)->u.s.next))
       {
 	if (SBYTES (SYMBOL_NAME (tail)) == size_byte
 	    && SCHARS (SYMBOL_NAME (tail)) == size
 	    && !memcmp (SDATA (SYMBOL_NAME (tail)), ptr, size_byte))
 	  return tail;
-	else if (XSYMBOL (tail)->next == 0)
+	else if (XSYMBOL (tail)->u.s.next == 0)
 	  break;
       }
   XSETINT (tem, hash);
@@ -4290,9 +4290,9 @@ map_obarray (Lisp_Object obarray, void (*fn) (Lisp_Object, Lisp_Object), Lisp_Ob
 	while (1)
 	  {
 	    (*fn) (tail, arg);
-	    if (XSYMBOL (tail)->next == 0)
+	    if (XSYMBOL (tail)->u.s.next == 0)
 	      break;
-	    XSETSYMBOL (tail, XSYMBOL (tail)->next);
+	    XSETSYMBOL (tail, XSYMBOL (tail)->u.s.next);
 	  }
     }
 }
@@ -4332,12 +4332,12 @@ init_obarray (void)
   DEFSYM (Qnil, "nil");
   SET_SYMBOL_VAL (XSYMBOL (Qnil), Qnil);
   make_symbol_constant (Qnil);
-  XSYMBOL (Qnil)->declared_special = true;
+  XSYMBOL (Qnil)->u.s.declared_special = true;
 
   DEFSYM (Qt, "t");
   SET_SYMBOL_VAL (XSYMBOL (Qt), Qt);
   make_symbol_constant (Qt);
-  XSYMBOL (Qt)->declared_special = true;
+  XSYMBOL (Qt)->u.s.declared_special = true;
 
   /* Qt is correct even if CANNOT_DUMP.  loadup.el will set to nil at end.  */
   Vpurify_flag = Qt;
@@ -4361,7 +4361,7 @@ defalias (struct Lisp_Subr *sname, char *string)
 {
   Lisp_Object sym;
   sym = intern (string);
-  XSETSUBR (XSYMBOL (sym)->function, sname);
+  XSETSUBR (XSYMBOL (sym)->u.s.function, sname);
 }
 #endif /* NOTDEF */
 
@@ -4376,8 +4376,8 @@ defvar_int (struct Lisp_Intfwd *i_fwd,
   sym = intern_c_string (namestring);
   i_fwd->type = Lisp_Fwd_Int;
   i_fwd->intvar = address;
-  XSYMBOL (sym)->declared_special = 1;
-  XSYMBOL (sym)->redirect = SYMBOL_FORWARDED;
+  XSYMBOL (sym)->u.s.declared_special = true;
+  XSYMBOL (sym)->u.s.redirect = SYMBOL_FORWARDED;
   SET_SYMBOL_FWD (XSYMBOL (sym), (union Lisp_Fwd *)i_fwd);
 }
 
@@ -4391,8 +4391,8 @@ defvar_bool (struct Lisp_Boolfwd *b_fwd,
   sym = intern_c_string (namestring);
   b_fwd->type = Lisp_Fwd_Bool;
   b_fwd->boolvar = address;
-  XSYMBOL (sym)->declared_special = 1;
-  XSYMBOL (sym)->redirect = SYMBOL_FORWARDED;
+  XSYMBOL (sym)->u.s.declared_special = true;
+  XSYMBOL (sym)->u.s.redirect = SYMBOL_FORWARDED;
   SET_SYMBOL_FWD (XSYMBOL (sym), (union Lisp_Fwd *)b_fwd);
   Vbyte_boolean_vars = Fcons (sym, Vbyte_boolean_vars);
 }
@@ -4410,8 +4410,8 @@ defvar_lisp_nopro (struct Lisp_Objfwd *o_fwd,
   sym = intern_c_string (namestring);
   o_fwd->type = Lisp_Fwd_Obj;
   o_fwd->objvar = address;
-  XSYMBOL (sym)->declared_special = 1;
-  XSYMBOL (sym)->redirect = SYMBOL_FORWARDED;
+  XSYMBOL (sym)->u.s.declared_special = true;
+  XSYMBOL (sym)->u.s.redirect = SYMBOL_FORWARDED;
   SET_SYMBOL_FWD (XSYMBOL (sym), (union Lisp_Fwd *)o_fwd);
 }
 
@@ -4434,8 +4434,8 @@ defvar_kboard (struct Lisp_Kboard_Objfwd *ko_fwd,
   sym = intern_c_string (namestring);
   ko_fwd->type = Lisp_Fwd_Kboard_Obj;
   ko_fwd->offset = offset;
-  XSYMBOL (sym)->declared_special = 1;
-  XSYMBOL (sym)->redirect = SYMBOL_FORWARDED;
+  XSYMBOL (sym)->u.s.declared_special = true;
+  XSYMBOL (sym)->u.s.redirect = SYMBOL_FORWARDED;
   SET_SYMBOL_FWD (XSYMBOL (sym), (union Lisp_Fwd *)ko_fwd);
 }
 \f
@@ -4769,7 +4769,7 @@ to find all the symbols in an obarray, use `mapatoms'.  */);
   DEFVAR_LISP ("values", Vvalues,
 	       doc: /* List of values of all expressions which were read, evaluated and printed.
 Order is reverse chronological.  */);
-  XSYMBOL (intern ("values"))->declared_special = 0;
+  XSYMBOL (intern ("values"))->u.s.declared_special = true;
 
   DEFVAR_LISP ("standard-input", Vstandard_input,
 	       doc: /* Stream for read to get input from.
diff --git a/src/minibuf.c b/src/minibuf.c
index a2f3324f99..913c93001e 100644
--- a/src/minibuf.c
+++ b/src/minibuf.c
@@ -1280,8 +1280,8 @@ is used to further constrain the set of candidates.  */)
 		error ("Bad data in guts of obarray");
 	      elt = bucket;
 	      eltstring = elt;
-	      if (XSYMBOL (bucket)->next)
-		XSETSYMBOL (bucket, XSYMBOL (bucket)->next);
+	      if (XSYMBOL (bucket)->u.s.next)
+		XSETSYMBOL (bucket, XSYMBOL (bucket)->u.s.next);
 	      else
 		XSETFASTINT (bucket, 0);
 	    }
@@ -1533,8 +1533,8 @@ with a space are ignored unless STRING itself starts with a space.  */)
 		error ("Bad data in guts of obarray");
 	      elt = bucket;
 	      eltstring = elt;
-	      if (XSYMBOL (bucket)->next)
-		XSETSYMBOL (bucket, XSYMBOL (bucket)->next);
+	      if (XSYMBOL (bucket)->u.s.next)
+		XSETSYMBOL (bucket, XSYMBOL (bucket)->u.s.next);
 	      else
 		XSETFASTINT (bucket, 0);
 	    }
@@ -1754,9 +1754,9 @@ the values STRING, PREDICATE and `lambda'.  */)
 			tem = tail;
 			break;
 		      }
-		    if (XSYMBOL (tail)->next == 0)
+		    if (XSYMBOL (tail)->u.s.next == 0)
 		      break;
-		    XSETSYMBOL (tail, XSYMBOL (tail)->next);
+		    XSETSYMBOL (tail, XSYMBOL (tail)->u.s.next);
 		  }
 	    }
 	}
diff --git a/src/thread.c b/src/thread.c
index 7335833cf9..c03cdda0fa 100644
--- a/src/thread.c
+++ b/src/thread.c
@@ -26,7 +26,7 @@ along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.  */
 #include "coding.h"
 #include "syssignal.h"
 
-static struct GCALIGNED thread_state main_thread;
+static struct thread_state main_thread;
 
 struct thread_state *current_thread = &main_thread;
 
diff --git a/src/xterm.c b/src/xterm.c
index dbb8349452..dd184eedfc 100644
--- a/src/xterm.c
+++ b/src/xterm.c
@@ -12504,7 +12504,7 @@ x_term_init (Lisp_Object display_name, char *xrm_option, char *resource_name)
       {
 	terminal->kboard = allocate_kboard (Qx);
 
-	if (!EQ (XSYMBOL (Qvendor_specific_keysyms)->function, Qunbound))
+	if (!EQ (XSYMBOL (Qvendor_specific_keysyms)->u.s.function, Qunbound))
 	  {
 	    char *vendor = ServerVendor (dpy);
 
-- 
2.13.6


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* Re: emacs-26 9e59de9: Use GCALIGNED properly for GCC
  2017-11-11  7:08           ` Paul Eggert
@ 2017-11-11  7:57             ` Paul Eggert
  2017-11-11  8:34               ` martin rudalics
  2017-11-11  8:33             ` martin rudalics
  1 sibling, 1 reply; 20+ messages in thread
From: Paul Eggert @ 2017-11-11  7:57 UTC (permalink / raw)
  To: Eli Zaretskii, martin rudalics; +Cc: rgm, emacs-devel

[-- Attachment #1: Type: text/plain, Size: 296 bytes --]

Paul Eggert wrote:
> It shrinks the source code a bit, which is a 
> good sign.

There's one more place we can simplify the code because Emacs no longer uses 
__attribute__ ((aligned (8))). Further patch attached. As a bonus this 
eliminates the slightly-ridiculous Fcons loop in emacs-module.c.

[-- Attachment #2: 0001-Simplify-by-removing-HAVE_STRUCT_ATTRIBUTE_ALIGNED.patch --]
[-- Type: text/x-patch, Size: 3047 bytes --]

From 5ad538acf5cc34f26420780fa642bce02a88d0ee Mon Sep 17 00:00:00 2001
From: Paul Eggert <eggert@cs.ucla.edu>
Date: Fri, 10 Nov 2017 23:52:29 -0800
Subject: [PATCH] Simplify by removing HAVE_STRUCT_ATTRIBUTE_ALIGNED

* configure.ac (HAVE_STRUCT_ATTRIBUTE_ALIGNED): Remove.  No longer
needed, since we no longer rely on __attribute__ ((aligned (8))).
All uses removed.
* src/emacs-module.c (HAVE_STRUCT_ATTRIBUTE_ALIGNED): Remove.
(lisp_to_value): Simplify now that we no longer need to worry
whether HAVE_STRUCT_ATTRIBUTE_ALIGNED is false.
---
 admin/CPP-DEFINES  |  1 -
 configure.ac       | 16 ----------------
 src/emacs-module.c | 17 -----------------
 3 files changed, 34 deletions(-)

diff --git a/admin/CPP-DEFINES b/admin/CPP-DEFINES
index 10b558d1ad..7a90b3dbe4 100644
--- a/admin/CPP-DEFINES
+++ b/admin/CPP-DEFINES
@@ -103,7 +103,6 @@ HAVE_ALARM
 HAVE_ALLOCA
 HAVE_ALLOCA_H
 HAVE_ALSA
-HAVE_ATTRIBUTE_ALIGNED
 HAVE_BDFFONT
 HAVE_BOXES
 HAVE_C99_STRTOLD
diff --git a/configure.ac b/configure.ac
index 5579342c4e..3c72f168a3 100644
--- a/configure.ac
+++ b/configure.ac
@@ -5113,22 +5113,6 @@ AC_DEFUN
 fi
 AC_SUBST(LIBXMENU)
 
-AC_CACHE_CHECK([for struct alignment],
-  [emacs_cv_struct_alignment],
-  [AC_COMPILE_IFELSE(
-     [AC_LANG_PROGRAM([[#include <stddef.h>
-			struct __attribute__ ((aligned (8))) s { char c; };
-			struct t { char c; struct s s; };
-			char verify[offsetof (struct t, s) == 8 ? 1 : -1];
-		      ]])],
-     [emacs_cv_struct_alignment=yes],
-     [emacs_cv_struct_alignment=no])])
-if test "$emacs_cv_struct_alignment" = yes; then
-  AC_DEFINE([HAVE_STRUCT_ATTRIBUTE_ALIGNED], 1,
-    [Define to 1 if 'struct __attribute__ ((aligned (N)))' aligns the
-     structure to an N-byte boundary.])
-fi
-
 if test "${GNU_MALLOC}" = "yes" ; then
   AC_DEFINE(GNU_MALLOC, 1,
 	    [Define to 1 if you want to use the GNU memory allocator.])
diff --git a/src/emacs-module.c b/src/emacs-module.c
index 6bc91a7e06..b351515c3b 100644
--- a/src/emacs-module.c
+++ b/src/emacs-module.c
@@ -998,10 +998,6 @@ lisp_to_value_bits (Lisp_Object o)
   return (emacs_value) p;
 }
 
-#ifndef HAVE_STRUCT_ATTRIBUTE_ALIGNED
-enum { HAVE_STRUCT_ATTRIBUTE_ALIGNED = 0 };
-#endif
-
 /* Convert O to an emacs_value.  Allocate storage if needed; this can
    signal if memory is exhausted.  Must be an injective function.  */
 static emacs_value
@@ -1029,19 +1025,6 @@ lisp_to_value (emacs_env *env, Lisp_Object o)
       /* Package the incompressible object pointer inside a pair
 	 that is compressible.  */
       Lisp_Object pair = Fcons (o, ltv_mark);
-
-      if (! HAVE_STRUCT_ATTRIBUTE_ALIGNED)
-	{
-	  /* Keep calling Fcons until it returns a compressible pair.
-	     This shouldn't take long.  */
-	  while ((intptr_t) XCONS (pair) & (GCALIGNMENT - 1))
-	    pair = Fcons (o, pair);
-
-	  /* Plant the mark.  The garbage collector will eventually
-	     reclaim any just-allocated incompressible pairs.  */
-	  XSETCDR (pair, ltv_mark);
-	}
-
       v = (emacs_value) ((intptr_t) XCONS (pair) + Lisp_Cons);
     }
 
-- 
2.13.6


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* Re: emacs-26 9e59de9: Use GCALIGNED properly for GCC
  2017-11-11  7:08           ` Paul Eggert
  2017-11-11  7:57             ` Paul Eggert
@ 2017-11-11  8:33             ` martin rudalics
  2017-11-13 18:19               ` Paul Eggert
  1 sibling, 1 reply; 20+ messages in thread
From: martin rudalics @ 2017-11-11  8:33 UTC (permalink / raw)
  To: Paul Eggert, Eli Zaretskii; +Cc: rgm, emacs-devel

 > Patches attached. They work for me on various platforms including gcc
 > -m32 on Fedora 26 x86-64 (which is close to the platform Glenn
 > mentioned). The 2nd patch does the real work: most of it consists of
 > changing private accessors to account for the newly-introduced
 > unions. It shrinks the source code a bit, which is a good sign. I plan
 > to test a bit more before installing; comments welcome.

Builds normally here on a 32-bit Windows XP with GCC 4.8.1.

martin



^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: emacs-26 9e59de9: Use GCALIGNED properly for GCC
  2017-11-11  7:57             ` Paul Eggert
@ 2017-11-11  8:34               ` martin rudalics
  2017-11-11  8:50                 ` Paul Eggert
  0 siblings, 1 reply; 20+ messages in thread
From: martin rudalics @ 2017-11-11  8:34 UTC (permalink / raw)
  To: Paul Eggert, Eli Zaretskii; +Cc: rgm, emacs-devel

 > There's one more place we can simplify the code because Emacs no
 > longer uses __attribute__ ((aligned (8))). Further patch attached. As
 > a bonus this eliminates the slightly-ridiculous Fcons loop in
 > emacs-module.c.

This patch doesn't apply here (on top of the two previous ones).

error: patch failed: admin/CPP-DEFINES:103
error: admin/CPP-DEFINES: patch does not apply
error: patch failed: configure.ac:5113
error: configure.ac: patch does not apply
error: patch failed: src/emacs-module.c:998
error: src/emacs-module.c: patch does not apply

martin



^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: emacs-26 9e59de9: Use GCALIGNED properly for GCC
  2017-11-11  8:34               ` martin rudalics
@ 2017-11-11  8:50                 ` Paul Eggert
  2017-11-11  9:46                   ` martin rudalics
  0 siblings, 1 reply; 20+ messages in thread
From: Paul Eggert @ 2017-11-11  8:50 UTC (permalink / raw)
  To: martin rudalics, Eli Zaretskii; +Cc: rgm, emacs-devel

[-- Attachment #1: Type: text/plain, Size: 564 bytes --]

martin rudalics wrote:
> This patch doesn't apply here (on top of the two previous ones).

Odd, the copy I received via the list is identical to what I sent, and it 
applies here. The copy archived here:

https://lists.gnu.org/archive/html/emacs-devel/2017-11/txtI3snHdSqSz.txt

has ">" prepended to the first "From " line and censors my email address, which 
I think is normal for lists.gnu.org; it has no other changes. Anyway, I'm 
attaching the patch again, this time with a ".txt" extension instead of a 
".patch" extension; sometimes that helps.

[-- Attachment #2: 0001-Simplify-by-removing-HAVE_STRUCT_ATTRIBUTE_ALIGNED.txt --]
[-- Type: text/plain, Size: 3047 bytes --]

From 5ad538acf5cc34f26420780fa642bce02a88d0ee Mon Sep 17 00:00:00 2001
From: Paul Eggert <eggert@cs.ucla.edu>
Date: Fri, 10 Nov 2017 23:52:29 -0800
Subject: [PATCH] Simplify by removing HAVE_STRUCT_ATTRIBUTE_ALIGNED

* configure.ac (HAVE_STRUCT_ATTRIBUTE_ALIGNED): Remove.  No longer
needed, since we no longer rely on __attribute__ ((aligned (8))).
All uses removed.
* src/emacs-module.c (HAVE_STRUCT_ATTRIBUTE_ALIGNED): Remove.
(lisp_to_value): Simplify now that we no longer need to worry
whether HAVE_STRUCT_ATTRIBUTE_ALIGNED is false.
---
 admin/CPP-DEFINES  |  1 -
 configure.ac       | 16 ----------------
 src/emacs-module.c | 17 -----------------
 3 files changed, 34 deletions(-)

diff --git a/admin/CPP-DEFINES b/admin/CPP-DEFINES
index 10b558d1ad..7a90b3dbe4 100644
--- a/admin/CPP-DEFINES
+++ b/admin/CPP-DEFINES
@@ -103,7 +103,6 @@ HAVE_ALARM
 HAVE_ALLOCA
 HAVE_ALLOCA_H
 HAVE_ALSA
-HAVE_ATTRIBUTE_ALIGNED
 HAVE_BDFFONT
 HAVE_BOXES
 HAVE_C99_STRTOLD
diff --git a/configure.ac b/configure.ac
index 5579342c4e..3c72f168a3 100644
--- a/configure.ac
+++ b/configure.ac
@@ -5113,22 +5113,6 @@ AC_DEFUN
 fi
 AC_SUBST(LIBXMENU)
 
-AC_CACHE_CHECK([for struct alignment],
-  [emacs_cv_struct_alignment],
-  [AC_COMPILE_IFELSE(
-     [AC_LANG_PROGRAM([[#include <stddef.h>
-			struct __attribute__ ((aligned (8))) s { char c; };
-			struct t { char c; struct s s; };
-			char verify[offsetof (struct t, s) == 8 ? 1 : -1];
-		      ]])],
-     [emacs_cv_struct_alignment=yes],
-     [emacs_cv_struct_alignment=no])])
-if test "$emacs_cv_struct_alignment" = yes; then
-  AC_DEFINE([HAVE_STRUCT_ATTRIBUTE_ALIGNED], 1,
-    [Define to 1 if 'struct __attribute__ ((aligned (N)))' aligns the
-     structure to an N-byte boundary.])
-fi
-
 if test "${GNU_MALLOC}" = "yes" ; then
   AC_DEFINE(GNU_MALLOC, 1,
 	    [Define to 1 if you want to use the GNU memory allocator.])
diff --git a/src/emacs-module.c b/src/emacs-module.c
index 6bc91a7e06..b351515c3b 100644
--- a/src/emacs-module.c
+++ b/src/emacs-module.c
@@ -998,10 +998,6 @@ lisp_to_value_bits (Lisp_Object o)
   return (emacs_value) p;
 }
 
-#ifndef HAVE_STRUCT_ATTRIBUTE_ALIGNED
-enum { HAVE_STRUCT_ATTRIBUTE_ALIGNED = 0 };
-#endif
-
 /* Convert O to an emacs_value.  Allocate storage if needed; this can
    signal if memory is exhausted.  Must be an injective function.  */
 static emacs_value
@@ -1029,19 +1025,6 @@ lisp_to_value (emacs_env *env, Lisp_Object o)
       /* Package the incompressible object pointer inside a pair
 	 that is compressible.  */
       Lisp_Object pair = Fcons (o, ltv_mark);
-
-      if (! HAVE_STRUCT_ATTRIBUTE_ALIGNED)
-	{
-	  /* Keep calling Fcons until it returns a compressible pair.
-	     This shouldn't take long.  */
-	  while ((intptr_t) XCONS (pair) & (GCALIGNMENT - 1))
-	    pair = Fcons (o, pair);
-
-	  /* Plant the mark.  The garbage collector will eventually
-	     reclaim any just-allocated incompressible pairs.  */
-	  XSETCDR (pair, ltv_mark);
-	}
-
       v = (emacs_value) ((intptr_t) XCONS (pair) + Lisp_Cons);
     }
 
-- 
2.13.6


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* Re: emacs-26 9e59de9: Use GCALIGNED properly for GCC
  2017-11-11  8:50                 ` Paul Eggert
@ 2017-11-11  9:46                   ` martin rudalics
  0 siblings, 0 replies; 20+ messages in thread
From: martin rudalics @ 2017-11-11  9:46 UTC (permalink / raw)
  To: Paul Eggert, Eli Zaretskii; +Cc: rgm, emacs-devel

 > Anyway, I'm attaching the patch again, this time with a
 > ".txt" extension instead of a ".patch" extension; sometimes that
 > helps.

Applies and builds normally here now.

Thanks, martin



^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: emacs-26 9e59de9: Use GCALIGNED properly for GCC
  2017-11-11  8:33             ` martin rudalics
@ 2017-11-13 18:19               ` Paul Eggert
  2017-11-13 18:45                 ` martin rudalics
  0 siblings, 1 reply; 20+ messages in thread
From: Paul Eggert @ 2017-11-13 18:19 UTC (permalink / raw)
  To: martin rudalics, Eli Zaretskii; +Cc: rgm, emacs-devel

martin rudalics wrote:
> Builds normally here on a 32-bit Windows XP with GCC 4.8.1.

Thanks for checking. I tested it a bit on more-obscure platforms, and found and 
worked around a related problem on AIX xlc (a compiler bug), and installed the 
result on the emacs-26 branch.



^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: emacs-26 9e59de9: Use GCALIGNED properly for GCC
  2017-11-13 18:19               ` Paul Eggert
@ 2017-11-13 18:45                 ` martin rudalics
  0 siblings, 0 replies; 20+ messages in thread
From: martin rudalics @ 2017-11-13 18:45 UTC (permalink / raw)
  To: Paul Eggert, Eli Zaretskii; +Cc: rgm, emacs-devel

 > Thanks for checking. I tested it a bit on more-obscure platforms, and
 > found and worked around a related problem on AIX xlc (a compiler bug),
 > and installed the result on the emacs-26 branch.

Thanks.  I suppose you can close a couple of bugs then ...

martin



^ permalink raw reply	[flat|nested] 20+ messages in thread

end of thread, other threads:[~2017-11-13 18:45 UTC | newest]

Thread overview: 20+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
     [not found] <20171109031206.7056.28312@vcs0.savannah.gnu.org>
     [not found] ` <20171109031208.D2CAF2033E@vcs0.savannah.gnu.org>
2017-11-09 23:31   ` emacs-26 9e59de9: Use GCALIGNED properly for GCC Glenn Morris
2017-11-10  7:10     ` martin rudalics
2017-11-10  8:06       ` Eli Zaretskii
2017-11-10  8:26         ` Paul Eggert
2017-11-10  9:57           ` Eli Zaretskii
2017-11-10 16:23             ` Stefan Monnier
2017-11-10 17:58               ` Paul Eggert
2017-11-10 18:02                 ` Stefan Monnier
2017-11-10 18:11                   ` Philipp Stephani
2017-11-10 19:19                     ` Paul Eggert
2017-11-10 20:31                       ` Stefan Monnier
2017-11-10 20:45                         ` Paul Eggert
2017-11-11  7:08           ` Paul Eggert
2017-11-11  7:57             ` Paul Eggert
2017-11-11  8:34               ` martin rudalics
2017-11-11  8:50                 ` Paul Eggert
2017-11-11  9:46                   ` martin rudalics
2017-11-11  8:33             ` martin rudalics
2017-11-13 18:19               ` Paul Eggert
2017-11-13 18:45                 ` martin rudalics

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).