C11 alignas instead of unions
authorPeter Eisentraut <peter@eisentraut.org>
Fri, 21 Nov 2025 08:57:06 +0000 (09:57 +0100)
committerPeter Eisentraut <peter@eisentraut.org>
Fri, 21 Nov 2025 09:08:24 +0000 (10:08 +0100)
This changes a few union members that only existed to ensure
alignments and replaces them with the C11 alignas specifier.

This change only uses fundamental alignments (meaning approximately
alignments of basic types), which all C11 compilers must support.
There are opportunities for similar changes using extended alignments,
for example in PGIOAlignedBlock, but these are not necessarily
supported by all compilers, so they are kept as a separate change.

Reviewed-by: Chao Li <li.evan.chao@gmail.com>
Discussion: https://www.postgresql.org/message-id/flat/46f05236-d4d4-4b4e-84d4-faa500f14691%40eisentraut.org

src/backend/access/common/toast_internals.c
src/backend/commands/async.c
src/backend/storage/large_object/inv_api.c
src/include/c.h

index 81dbd67c72587c6ee2210f0c423fbf7dbcf28b67..63b848473f8a67c5dac55f66794761325582c44e 100644 (file)
@@ -287,11 +287,9 @@ toast_save_datum(Relation rel, Datum value,
        bool        t_isnull[3] = {0};
        union
        {
-           struct varlena hdr;
+           alignas(int32) struct varlena hdr;
            /* this is to make the union big enough for a chunk: */
            char        data[TOAST_MAX_CHUNK_SIZE + VARHDRSZ];
-           /* ensure union is aligned well enough: */
-           int32       align_it;
        }           chunk_data;
        int32       chunk_size;
 
index e1cf659485ab7283bc0a337494e211ca2e2d3b55..eb86402cae43cc63bc09a2eaa68d57aeb7889b09 100644 (file)
@@ -1987,14 +1987,10 @@ asyncQueueProcessPageEntries(QueuePosition *current,
    /*
     * We copy the entries into a local buffer to avoid holding the SLRU lock
     * while we transmit them to our frontend.  The local buffer must be
-    * adequately aligned, so use a union.
+    * adequately aligned.
     */
-   union
-   {
-       char        buf[QUEUE_PAGESIZE];
-       AsyncQueueEntry align;
-   }           local_buf;
-   char       *local_buf_end = local_buf.buf;
+   alignas(AsyncQueueEntry) char local_buf[QUEUE_PAGESIZE];
+   char       *local_buf_end = local_buf;
 
    slotno = SimpleLruReadPage_ReadOnly(NotifyCtl, curpage,
                                        InvalidTransactionId);
@@ -2082,8 +2078,8 @@ asyncQueueProcessPageEntries(QueuePosition *current,
     * Now that we have let go of the SLRU bank lock, send the notifications
     * to our backend
     */
-   Assert(local_buf_end - local_buf.buf <= BLCKSZ);
-   for (char *p = local_buf.buf; p < local_buf_end;)
+   Assert(local_buf_end - local_buf <= BLCKSZ);
+   for (char *p = local_buf; p < local_buf_end;)
    {
        AsyncQueueEntry *qe = (AsyncQueueEntry *) p;
 
index f6d2f9dba13d012ac96519a8bcae29203ffffacc..2bd872d6581f8f65e0d5a840f96e630d457d45c5 100644 (file)
@@ -556,11 +556,9 @@ inv_write(LargeObjectDesc *obj_desc, const char *buf, int nbytes)
    bool        pfreeit;
    union
    {
-       bytea       hdr;
+       alignas(int32) bytea hdr;
        /* this is to make the union big enough for a LO data chunk: */
        char        data[LOBLKSIZE + VARHDRSZ];
-       /* ensure union is aligned well enough: */
-       int32       align_it;
    }           workbuf = {0};
    char       *workb = VARDATA(&workbuf.hdr);
    HeapTuple   newtup;
@@ -747,11 +745,9 @@ inv_truncate(LargeObjectDesc *obj_desc, int64 len)
    Form_pg_largeobject olddata;
    union
    {
-       bytea       hdr;
+       alignas(int32) bytea hdr;
        /* this is to make the union big enough for a LO data chunk: */
        char        data[LOBLKSIZE + VARHDRSZ];
-       /* ensure union is aligned well enough: */
-       int32       align_it;
    }           workbuf = {0};
    char       *workb = VARDATA(&workbuf.hdr);
    HeapTuple   newtup;
index 8e887bec0b208f959eafdef0a5e51a70e70635b3..729eb8a27de82cf921da88a77d3f07807e91d044 100644 (file)
@@ -1117,15 +1117,11 @@ pg_noreturn extern void ExceptionalCondition(const char *conditionName,
  * Use this, not "char buf[BLCKSZ]", to declare a field or local variable
  * holding a page buffer, if that page might be accessed as a page.  Otherwise
  * the variable might be under-aligned, causing problems on alignment-picky
- * hardware.  We include both "double" and "int64" in the union to ensure that
- * the compiler knows the value must be MAXALIGN'ed (cf. configure's
- * computation of MAXIMUM_ALIGNOF).
+ * hardware.
  */
-typedef union PGAlignedBlock
+typedef struct PGAlignedBlock
 {
-   char        data[BLCKSZ];
-   double      force_align_d;
-   int64       force_align_i64;
+   alignas(MAXIMUM_ALIGNOF) char data[BLCKSZ];
 } PGAlignedBlock;
 
 /*