alignas (C11)

Started by Peter Eisentraut2 months ago9 messages
#1Peter Eisentraut
peter@eisentraut.org
4 attachment(s)

Here is another patch set to sprinkle some C11 features around the
code. My aim is to make a little bit of use of several C11 features
as examples and encouragement for future code, and to test compilers.

Here, I'm proposing to make some use of the alignas specifier. This
takes the place of compiler extensions such as
__attribute__((aligned(a))) and __declspec(align(a)), packaged up as
pg_attribute_aligned(a), which are used in a variety of places. Also,
we can simplify some places where unions are used to encourage
alignment, and remove a few workaround for lack of alignment attribute
support.

Some detail notes:

- Technically, compilers are only required to support alignas up to
(handwaving over some terminology) the largest alignment of a built-in
type, so maybe 8 or 16. Support for larger alignments like
alignas(PG_CACHE_LINE_SIZE) is implementation-defined. I have split up
my patches so that fundamental and extended alignments are in separate
patches, so this could be eased into, but I'm expecting that all
compilers in practical use support alignments up to PG_IO_ALIGN_SIZE.
(For MSVC, 4096 appears to be the actual limit by default, per [0]https://learn.microsoft.com/en-us/cpp/build/reference/align-section-alignment?view=msvc-170, but
this is independent of using alignas or __declspec. I haven't found any
explicit documentation for clang or gcc.)

[0]: https://learn.microsoft.com/en-us/cpp/build/reference/align-section-alignment?view=msvc-170
https://learn.microsoft.com/en-us/cpp/build/reference/align-section-alignment?view=msvc-170

- You cannot use alignas on a typedef. So some uses of the attribute
pg_attribute_aligned() like for PgAioUringContext or the whole int128
business cannot be converted directly. The solution for cases like
PgAioUringContext could be to move the alignas into the struct, but I
haven't studied this code closely enough, so I'm leaving it. For
int128, there is no straightforward solution, so I'm also leaving that
as is.

(The reason for this restriction is that typedefs are supposed to be
type aliases that are interchangeable. But if you have two otherwise
compatible typedefs with different alignments, this kind of violates the
C type system and the compiler has to do some nonstandard magic to
handle this (or fail to, see "checking for __int128 alignment bug").)

- You cannot use alignas to underalign a type. So again, int128 cannot
be handled by this.

For at least these reasons, I'm leaving pg_attribute_aligned() and some
of its more tricky uses in place and unchanged.

Attachments:

0001-Add-stdalign.h-to-c.h.patchtext/plain; charset=UTF-8; name=0001-Add-stdalign.h-to-c.h.patchDownload
From 228f3973b64c38c7e715eba5cfa069c7c5b4501b Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <peter@eisentraut.org>
Date: Wed, 12 Nov 2025 11:55:29 +0100
Subject: [PATCH 1/4] Add <stdalign.h> to c.h

This allows using the C11 constructs alignas and alignof (not done in
this patch).
---
 src/include/c.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/src/include/c.h b/src/include/c.h
index 757dfff4782..b3bf1b412ee 100644
--- a/src/include/c.h
+++ b/src/include/c.h
@@ -60,6 +60,7 @@
 
 /* System header files that should be available everywhere in Postgres */
 #include <inttypes.h>
+#include <stdalign.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>

base-commit: 2ddc8d9e9baae28ba63a9f1c85f0a36deb9112aa
-- 
2.51.0

0002-C11-alignas-instead-of-unions.patchtext/plain; charset=UTF-8; name=0002-C11-alignas-instead-of-unions.patchDownload
From e31938294770cc997a309c97c38424a8fe31834c Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <peter@eisentraut.org>
Date: Wed, 12 Nov 2025 11:55:29 +0100
Subject: [PATCH 2/4] C11 alignas instead of unions

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.
---
 src/backend/access/common/toast_internals.c |  4 +---
 src/backend/commands/async.c                | 12 ++++--------
 src/backend/storage/large_object/inv_api.c  |  8 ++------
 src/include/c.h                             | 10 +++-------
 4 files changed, 10 insertions(+), 24 deletions(-)

diff --git a/src/backend/access/common/toast_internals.c b/src/backend/access/common/toast_internals.c
index 81dbd67c725..63b848473f8 100644
--- a/src/backend/access/common/toast_internals.c
+++ b/src/backend/access/common/toast_internals.c
@@ -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;
 
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index 4bd37d5beb5..4bdf21c319c 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -1854,12 +1854,8 @@ asyncQueueReadAllNotifications(void)
 	QueuePosition head;
 	Snapshot	snapshot;
 
-	/* page_buffer must be adequately aligned, so use a union */
-	union
-	{
-		char		buf[QUEUE_PAGESIZE];
-		AsyncQueueEntry align;
-	}			page_buffer;
+	/* page_buffer must be adequately aligned */
+	alignas(AsyncQueueEntry) char page_buffer[QUEUE_PAGESIZE];
 
 	/* Fetch current state */
 	LWLockAcquire(NotifyQueueLock, LW_SHARED);
@@ -1957,7 +1953,7 @@ asyncQueueReadAllNotifications(void)
 				/* fetch all the rest of the page */
 				copysize = QUEUE_PAGESIZE - curoffset;
 			}
-			memcpy(page_buffer.buf + curoffset,
+			memcpy(page_buffer + curoffset,
 				   NotifyCtl->shared->page_buffer[slotno] + curoffset,
 				   copysize);
 			/* Release lock that we got from SimpleLruReadPage_ReadOnly() */
@@ -1979,7 +1975,7 @@ asyncQueueReadAllNotifications(void)
 			 * while sending the notifications to the frontend.
 			 */
 			reachedStop = asyncQueueProcessPageEntries(&pos, head,
-													   page_buffer.buf,
+													   page_buffer,
 													   snapshot);
 		} while (!reachedStop);
 	}
diff --git a/src/backend/storage/large_object/inv_api.c b/src/backend/storage/large_object/inv_api.c
index f6d2f9dba13..2bd872d6581 100644
--- a/src/backend/storage/large_object/inv_api.c
+++ b/src/backend/storage/large_object/inv_api.c
@@ -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;
diff --git a/src/include/c.h b/src/include/c.h
index b3bf1b412ee..250d9c1d40b 100644
--- a/src/include/c.h
+++ b/src/include/c.h
@@ -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;
 
 /*
-- 
2.51.0

0003-Use-C11-alignas-in-pg_atomic_uint64-definitions.patchtext/plain; charset=UTF-8; name=0003-Use-C11-alignas-in-pg_atomic_uint64-definitions.patchDownload
From 00afcc6891b29c7c91a4aec9e414773bbf9b2468 Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <peter@eisentraut.org>
Date: Wed, 12 Nov 2025 11:55:29 +0100
Subject: [PATCH 3/4] Use C11 alignas in pg_atomic_uint64 definitions

XXX This is just separate from the previous patch because it's harder
to test.
---
 src/include/port/atomics/arch-ppc.h     | 2 +-
 src/include/port/atomics/generic-gcc.h  | 2 +-
 src/include/port/atomics/generic-msvc.h | 4 ++--
 3 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/src/include/port/atomics/arch-ppc.h b/src/include/port/atomics/arch-ppc.h
index b93f6766d29..2b3c3283469 100644
--- a/src/include/port/atomics/arch-ppc.h
+++ b/src/include/port/atomics/arch-ppc.h
@@ -36,7 +36,7 @@ typedef struct pg_atomic_uint32
 #define PG_HAVE_ATOMIC_U64_SUPPORT
 typedef struct pg_atomic_uint64
 {
-	volatile uint64 value pg_attribute_aligned(8);
+	alignas(8) volatile uint64 value;
 } pg_atomic_uint64;
 
 #endif
diff --git a/src/include/port/atomics/generic-gcc.h b/src/include/port/atomics/generic-gcc.h
index a0751f2286a..18ea8787199 100644
--- a/src/include/port/atomics/generic-gcc.h
+++ b/src/include/port/atomics/generic-gcc.h
@@ -103,7 +103,7 @@ typedef struct pg_atomic_uint32
 
 typedef struct pg_atomic_uint64
 {
-	volatile uint64 value pg_attribute_aligned(8);
+	alignas(8) volatile uint64 value;
 } pg_atomic_uint64;
 
 #endif /* defined(HAVE_GCC__ATOMIC_INT64_CAS) || defined(HAVE_GCC__SYNC_INT64_CAS) */
diff --git a/src/include/port/atomics/generic-msvc.h b/src/include/port/atomics/generic-msvc.h
index a6ea5f1c2e7..3d3c5363446 100644
--- a/src/include/port/atomics/generic-msvc.h
+++ b/src/include/port/atomics/generic-msvc.h
@@ -37,9 +37,9 @@ typedef struct pg_atomic_uint32
 } pg_atomic_uint32;
 
 #define PG_HAVE_ATOMIC_U64_SUPPORT
-typedef struct pg_attribute_aligned(8) pg_atomic_uint64
+typedef struct pg_atomic_uint64
 {
-	volatile uint64 value;
+	alignas(8) volatile uint64 value;
 } pg_atomic_uint64;
 
 
-- 
2.51.0

0004-C11-alignas-instead-of-unions-extended-alignments.patchtext/plain; charset=UTF-8; name=0004-C11-alignas-instead-of-unions-extended-alignments.patchDownload
From 0093ad4b8981b9b225fb517b1f9d9a35bc76b588 Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <peter@eisentraut.org>
Date: Wed, 12 Nov 2025 11:55:29 +0100
Subject: [PATCH 4/4] C11 alignas instead of unions -- extended alignments

This replaces some uses of pg_attribute_aligned() with the standard
alignas() for cases where extended alignment (larger than max_align_t)
is required.

This patch stipulates that all supported compilers must support
alignments up to PG_IO_ALIGN_SIZE, but that seems pretty likely.

We can then also desupport the case where direct I/O is disabled
because pg_attribute_aligned is not supported.
---
 src/include/c.h          | 18 ++++--------------
 src/include/storage/fd.h |  5 ++---
 2 files changed, 6 insertions(+), 17 deletions(-)

diff --git a/src/include/c.h b/src/include/c.h
index 250d9c1d40b..61af8487a03 100644
--- a/src/include/c.h
+++ b/src/include/c.h
@@ -1132,25 +1132,15 @@ typedef struct PGAlignedBlock
  * for I/O in general, but may be strictly required on some platforms when
  * using direct I/O.
  */
-typedef union PGIOAlignedBlock
+typedef struct PGIOAlignedBlock
 {
-#ifdef pg_attribute_aligned
-	pg_attribute_aligned(PG_IO_ALIGN_SIZE)
-#endif
-	char		data[BLCKSZ];
-	double		force_align_d;
-	int64		force_align_i64;
+	alignas(PG_IO_ALIGN_SIZE) char data[BLCKSZ];
 } PGIOAlignedBlock;
 
 /* Same, but for an XLOG_BLCKSZ-sized buffer */
-typedef union PGAlignedXLogBlock
+typedef struct PGAlignedXLogBlock
 {
-#ifdef pg_attribute_aligned
-	pg_attribute_aligned(PG_IO_ALIGN_SIZE)
-#endif
-	char		data[XLOG_BLCKSZ];
-	double		force_align_d;
-	int64		force_align_i64;
+	alignas(PG_IO_ALIGN_SIZE) char data[XLOG_BLCKSZ];
 } PGAlignedXLogBlock;
 
 /* msb for char */
diff --git a/src/include/storage/fd.h b/src/include/storage/fd.h
index b77d8e5e30e..2e2091a9159 100644
--- a/src/include/storage/fd.h
+++ b/src/include/storage/fd.h
@@ -85,10 +85,9 @@ extern PGDLLIMPORT int max_safe_fds;
  * to the appropriate Windows flag in src/port/open.c.  We simulate it with
  * fcntl(F_NOCACHE) on macOS inside fd.c's open() wrapper.  We use the name
  * PG_O_DIRECT rather than defining O_DIRECT in that case (probably not a good
- * idea on a Unix).  We can only use it if the compiler will correctly align
- * PGIOAlignedBlock for us, though.
+ * idea on a Unix).
  */
-#if defined(O_DIRECT) && defined(pg_attribute_aligned)
+#if defined(O_DIRECT)
 #define		PG_O_DIRECT O_DIRECT
 #elif defined(F_NOCACHE)
 #define		PG_O_DIRECT 0x80000000
-- 
2.51.0

#2Andres Freund
andres@anarazel.de
In reply to: Peter Eisentraut (#1)
Re: alignas (C11)

Hi,

On 2025-11-12 12:39:19 +0100, Peter Eisentraut wrote:

- You cannot use alignas on a typedef. So some uses of the attribute
pg_attribute_aligned() like for PgAioUringContext or the whole int128
business cannot be converted directly. The solution for cases like
PgAioUringContext could be to move the alignas into the struct, but I
haven't studied this code closely enough, so I'm leaving it. For int128,
there is no straightforward solution, so I'm also leaving that as is.

Maybe I'm confused, but the aligned attribute for PgAioUringContext is on the
struct, not the typedef, no?

Greetings,

Andres Freund

#3Thomas Munro
thomas.munro@gmail.com
In reply to: Peter Eisentraut (#1)
Re: alignas (C11)

On Thu, Nov 13, 2025 at 12:39 AM Peter Eisentraut <peter@eisentraut.org> wrote:

- You cannot use alignas on a typedef. So some uses of the attribute
pg_attribute_aligned() like for PgAioUringContext or the whole int128
business cannot be converted directly. The solution for cases like
PgAioUringContext could be to move the alignas into the struct, but I
haven't studied this code closely enough, so I'm leaving it.

While studying atomics recently I noticed BUFFERALIGN, which was
originally something like PG_IO_ALIGN_SIZE (see pg_config_manual.h),
but is now used as an arbitrary fudge-factor by shared memory
allocator-ish things that either know the memory will hold
pg_atomic_uint64 or don't know what the memory will hold, since i386
has alignof(uint64_t, double) == 4, but alignof(_Atomic(uint64_t)) ==
8, so MAXALIGN is not good enough. I think atomics.h should probably
define MAXATOMICALIGN, or something like that. I prototyped that,
which led me to pay attention to this __int128 (and typedef)
situation, where we went the other way and convinced the compiler to
underalign and generate different instructions to fit palloc(). (If
palloc were ever used for cross-thread allocation motivating atomic
storage, presumably i386 atomics would be an issue there too, but
let's ignore that for now...). I guess today we could just do
palloc_aligned(sizeof(Int128AggState), alignof(Int128AggState),
MCXT_ALLOC_ZERO) for that, and let the compiler worry about the
__int128 and its containing struct? I prototyped that and it seemed
vaguely plausible, though I can see the argument against it is "what
about when the type spreads and someone forgets?", but at first glance
it seems to be much more localised than the atomics/shmem problem.
IDK.

In a very quick hack (so probably missing things) I also seemed to be
able to get rid of all our ALIGNOF_ configure probes and just write
alignof(int) when I want the alignment of int, move the MAXALIGN
derivation into about two lines of c.h, and stuff alignof() inside the
right structs as you said...

#4Chao Li
li.evan.chao@gmail.com
In reply to: Peter Eisentraut (#1)
Re: alignas (C11)

On Nov 12, 2025, at 19:39, Peter Eisentraut <peter@eisentraut.org> wrote:

Here is another patch set to sprinkle some C11 features around the
code. My aim is to make a little bit of use of several C11 features
as examples and encouragement for future code, and to test compilers.

Here, I'm proposing to make some use of the alignas specifier. This takes the place of compiler extensions such as __attribute__((aligned(a))) and __declspec(align(a)), packaged up as pg_attribute_aligned(a), which are used in a variety of places. Also, we can simplify some places where unions are used to encourage alignment, and remove a few workaround for lack of alignment attribute support.

Some detail notes:

- Technically, compilers are only required to support alignas up to (handwaving over some terminology) the largest alignment of a built-in type, so maybe 8 or 16. Support for larger alignments like alignas(PG_CACHE_LINE_SIZE) is implementation-defined. I have split up my patches so that fundamental and extended alignments are in separate patches, so this could be eased into, but I'm expecting that all compilers in practical use support alignments up to PG_IO_ALIGN_SIZE. (For MSVC, 4096 appears to be the actual limit by default, per [0], but this is independent of using alignas or __declspec. I haven't found any explicit documentation for clang or gcc.)

[0]: https://learn.microsoft.com/en-us/cpp/build/reference/align-section-alignment?view=msvc-170

- You cannot use alignas on a typedef. So some uses of the attribute pg_attribute_aligned() like for PgAioUringContext or the whole int128 business cannot be converted directly. The solution for cases like PgAioUringContext could be to move the alignas into the struct, but I haven't studied this code closely enough, so I'm leaving it. For int128, there is no straightforward solution, so I'm also leaving that as is.

(The reason for this restriction is that typedefs are supposed to be type aliases that are interchangeable. But if you have two otherwise compatible typedefs with different alignments, this kind of violates the C type system and the compiler has to do some nonstandard magic to handle this (or fail to, see "checking for __int128 alignment bug").)

- You cannot use alignas to underalign a type. So again, int128 cannot be handled by this.

For at least these reasons, I'm leaving pg_attribute_aligned() and some of its more tricky uses in place and unchanged.
<0001-Add-stdalign.h-to-c.h.patch><0002-C11-alignas-instead-of-unions.patch><0003-Use-C11-alignas-in-pg_atomic_uint64-definitions.patch><0004-C11-alignas-instead-of-unions-extended-alignments.patch>

I can confirm that with this patch, build passed on MacOS 15.6.1, and “make check” passed as well.

0001 is a minimum and straightforward change that enables the use of C11’s alignas and alignof keywords throughout the PostgreSQL source.

0002 simplifies several structures/unions by using alignas, I have a couple of minor comment:

1 - 0002
```
-typedef union PGAlignedBlock
+typedef struct PGAlignedBlock
 {
-	char		data[BLCKSZ];
-	double		force_align_d;
-	int64		force_align_i64;
+	alignas(MAXIMUM_ALIGNOF) char data[BLCKSZ];
 } PGAlignedBlock;
```

As we changes PGAlignedBlock from union to structure, I think we can explicitly mention in the commit message something like “PGAlignedBlock has the same alignment and contiguous array data, thus no ABI change”.

2 - 0002
```
-	/* page_buffer must be adequately aligned, so use a union */
-	union
-	{
-		char		buf[QUEUE_PAGESIZE];
-		AsyncQueueEntry align;
-	}			page_buffer;
+	/* page_buffer must be adequately aligned */
+	alignas(AsyncQueueEntry) char page_buffer[QUEUE_PAGESIZE];
```

To make readers easier to understand the statement, maybe we can explicitly use alignof:

alignas(alignof(AsyncQueueEntry)) char page_buffer[QUEUE_PAGESIZE];

0003 replaces pg_attribute_aligned(8) with alignas(8), no comment.

0004 removes "#ifdef pg_attribute_aligned”, I think that just disables support of very old compilers that we might no longer care about them, which should be okay. For 0004, the same comment as 1.

Best regards,
--
Chao Li (Evan)
HighGo Software Co., Ltd.
https://www.highgo.com/

#5Peter Eisentraut
peter@eisentraut.org
In reply to: Andres Freund (#2)
Re: alignas (C11)

On 12.11.25 15:02, Andres Freund wrote:

Hi,

On 2025-11-12 12:39:19 +0100, Peter Eisentraut wrote:

- You cannot use alignas on a typedef. So some uses of the attribute
pg_attribute_aligned() like for PgAioUringContext or the whole int128
business cannot be converted directly. The solution for cases like
PgAioUringContext could be to move the alignas into the struct, but I
haven't studied this code closely enough, so I'm leaving it. For int128,
there is no straightforward solution, so I'm also leaving that as is.

Maybe I'm confused, but the aligned attribute for PgAioUringContext is on the
struct, not the typedef, no?

Yes, you're right. The immediate problem there is that alignas is not
syntactically valid at all at that position.

#6Andres Freund
andres@anarazel.de
In reply to: Peter Eisentraut (#5)
Re: alignas (C11)

Hi,

On 2025-11-12 16:09:14 +0100, Peter Eisentraut wrote:

On 12.11.25 15:02, Andres Freund wrote:

Hi,

On 2025-11-12 12:39:19 +0100, Peter Eisentraut wrote:

- You cannot use alignas on a typedef. So some uses of the attribute
pg_attribute_aligned() like for PgAioUringContext or the whole int128
business cannot be converted directly. The solution for cases like
PgAioUringContext could be to move the alignas into the struct, but I
haven't studied this code closely enough, so I'm leaving it. For int128,
there is no straightforward solution, so I'm also leaving that as is.

Maybe I'm confused, but the aligned attribute for PgAioUringContext is on the
struct, not the typedef, no?

Yes, you're right. The immediate problem there is that alignas is not
syntactically valid at all at that position.

Argh, why couldn't C copy the C++ rules for this :(.

Just moving it to completion_lock would be fine though...

Greetings,

Andres Freund

#7Peter Eisentraut
peter@eisentraut.org
In reply to: Thomas Munro (#3)
Re: alignas (C11)

On 12.11.25 15:17, Thomas Munro wrote:

In a very quick hack (so probably missing things) I also seemed to be
able to get rid of all our ALIGNOF_ configure probes and just write
alignof(int) when I want the alignment of int,

According to my research, using alignof could be quite dangerous for our
use, because it does not necessarily match what the ALIGNOF_ probes
return. The latter just answer the question, what is the offset if I
stick this in a struct as the second field, but that could be larger
than the smallest valid alignment for a type. And there are
platforms/ABIs where they are actually different.

If we didn't have to worry about on-disk compatibility, then using
alignof would in theory be better, because if the minimal alignment is
actually smaller than the current configure probes compute, then we
could save storage. But for the system catalog structs we actually do
want the offset-in-struct interpretation, so we're tied to that anyway.

(Also, something about AIX here ... :-/)

So, I don't know, better be careful with this ...

move the MAXALIGN
derivation into about two lines of c.h,

Yes, I had also arrived at that. Just to unify some configure and meson
code.

#8Peter Eisentraut
peter@eisentraut.org
In reply to: Chao Li (#4)
Re: alignas (C11)

On 12.11.25 15:27, Chao Li wrote:

0002 simplifies several structures/unions by using alignas, I have a couple of minor comment:

1 - 0002
```
-typedef union PGAlignedBlock
+typedef struct PGAlignedBlock
{
-	char		data[BLCKSZ];
-	double		force_align_d;
-	int64		force_align_i64;
+	alignas(MAXIMUM_ALIGNOF) char data[BLCKSZ];
} PGAlignedBlock;
```

As we changes PGAlignedBlock from union to structure, I think we can explicitly mention in the commit message something like “PGAlignedBlock has the same alignment and contiguous array data, thus no ABI change”.

We don't care about ABI changes in major releases.

2 - 0002
```
-	/* page_buffer must be adequately aligned, so use a union */
-	union
-	{
-		char		buf[QUEUE_PAGESIZE];
-		AsyncQueueEntry align;
-	}			page_buffer;
+	/* page_buffer must be adequately aligned */
+	alignas(AsyncQueueEntry) char page_buffer[QUEUE_PAGESIZE];
```

To make readers easier to understand the statement, maybe we can explicitly use alignof:

alignas(alignof(AsyncQueueEntry)) char page_buffer[QUEUE_PAGESIZE];

I don't know. alignas(type) is standard C and seems pretty intuitive to
me. Writing it the long way would be potentially more confusing IMO.

#9Peter Eisentraut
peter@eisentraut.org
In reply to: Peter Eisentraut (#1)
Re: alignas (C11)

On 12.11.25 12:39, Peter Eisentraut wrote:

Here, I'm proposing to make some use of the alignas specifier.  This
takes the place of compiler extensions such as
__attribute__((aligned(a))) and __declspec(align(a)), packaged up as
pg_attribute_aligned(a), which are used in a variety of places.  Also,
we can simplify some places where unions are used to encourage
alignment, and remove a few workaround for lack of alignment attribute
support.

This patch set has been committed, it looks like without buildfarm
complaints.