The current implementation of StaticAssertExpr() uses the GCC extension
statement expressions.
In this patch, I'm proposing a different implementation that doesn't
require nonstandard extensions. The trick is to put the static_assert()
into a struct definition. This appears to be a common way to do this.
(See [0] for references.)
Unfortunately, MSVC before version 19.33 fails to compile this, but
since it was fixed later, I think this was just a bug that was later
fixed. I'm keeping the old workaround code as a fallback for this case,
but eventually we can remove that.
For C++, the struct trick doesn't work, but I found a different
implementation that works on all supported compilers, using lambda
expressions. I found this at [1].
[0]: https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3715.pdf
[1]: https://stackoverflow.com/questions/31311748
From 58b18135fca550b6de4892bdb8a66e0ea0aca2b1 Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <[email protected]>
Date: Mon, 23 Feb 2026 07:57:16 +0100
Subject: [PATCH] Portable StaticAssertExpr
Use a different way to write StaticAssertExpr() that does not require
the GCC extension statement expressions.
For C, we put the static_assert into a struct. This appears to be a
common approach.
We still need to keep the fallback implementation to support buggy
MSVC < 19.33.
For C++, we put it into a lambda expression. (The C approach doesn't
work; it's not permitted to define a new type inside sizeof.)
---
config/c-compiler.m4 | 16 ----------------
configure | 31 -------------------------------
configure.ac | 1 -
meson.build | 13 -------------
src/include/c.h | 30 ++++++++++++++++++++++--------
5 files changed, 22 insertions(+), 69 deletions(-)
diff --git a/config/c-compiler.m4 b/config/c-compiler.m4
index 1509dbfa2ab..f9e86bcf0f5 100644
--- a/config/c-compiler.m4
+++ b/config/c-compiler.m4
@@ -150,22 +150,6 @@ fi])# PGAC_TYPE_128BIT_INT
-# PGAC_C_STATEMENT_EXPRESSIONS
-# ----------------------------
-# Check if the C compiler understands GCC statement expressions.
-AC_DEFUN([PGAC_C_STATEMENT_EXPRESSIONS],
-[AC_CACHE_CHECK(for statement expressions, pgac_cv_statement_expressions,
-[AC_LINK_IFELSE([AC_LANG_PROGRAM([],
-[({ _Static_assert(1, "foo"); })])],
-[pgac_cv_statement_expressions=yes],
-[pgac_cv_statement_expressions=no])])
-if test x"$pgac_cv_statement_expressions" = xyes ; then
-AC_DEFINE(HAVE_STATEMENT_EXPRESSIONS, 1,
- [Define to 1 if your compiler supports statement expressions.])
-fi])# PGAC_C_STATEMENT_EXPRESSIONS
-
-
-
# PGAC_C_TYPEOF
# -------------
# Check if the C compiler understands typeof or a variant. Define
diff --git a/configure b/configure
index e1a08129974..5128e60803d 100755
--- a/configure
+++ b/configure
@@ -14895,37 +14895,6 @@ cat >>confdefs.h <<_ACEOF
_ACEOF
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for statement expressions"
>&5
-$as_echo_n "checking for statement expressions... " >&6; }
-if ${pgac_cv_statement_expressions+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-
-int
-main ()
-{
-({ _Static_assert(1, "foo"); })
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
- pgac_cv_statement_expressions=yes
-else
- pgac_cv_statement_expressions=no
-fi
-rm -f core conftest.err conftest.$ac_objext \
- conftest$ac_exeext conftest.$ac_ext
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result:
$pgac_cv_statement_expressions" >&5
-$as_echo "$pgac_cv_statement_expressions" >&6; }
-if test x"$pgac_cv_statement_expressions" = xyes ; then
-
-$as_echo "#define HAVE_STATEMENT_EXPRESSIONS 1" >>confdefs.h
-
-fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for typeof" >&5
$as_echo_n "checking for typeof... " >&6; }
if ${pgac_cv_c_typeof+:} false; then :
diff --git a/configure.ac b/configure.ac
index cc85c233c03..2ea629a2172 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1714,7 +1714,6 @@ m4_defun([AC_PROG_CC_STDC], []) dnl We don't want that.
AC_C_BIGENDIAN
PGAC_PRINTF_ARCHETYPE
PGAC_CXX_PRINTF_ARCHETYPE
-PGAC_C_STATEMENT_EXPRESSIONS
PGAC_C_TYPEOF
PGAC_C_TYPES_COMPATIBLE
PGAC_C_BUILTIN_CONSTANT_P
diff --git a/meson.build b/meson.build
index 055e96315d0..9ce9ec7dcd1 100644
--- a/meson.build
+++ b/meson.build
@@ -1935,19 +1935,6 @@ if cc.compiles('''
endif
-# Check if the C compiler supports GCC-style statement expressions.
-if cc.compiles('''
- int main(int arg, char **argv)
- {
- ({ _Static_assert(1, "foo"); });
- }
- ''',
- name: 'statement expressions',
- args: test_c_args)
- cdata.set('HAVE_STATEMENT_EXPRESSIONS', 1)
-endif
-
-
# Select the format archetype to be used to check printf-type functions.
#
# Need to check a call with %m because netbsd supports gnu_printf but emits a
diff --git a/src/include/c.h b/src/include/c.h
index 7ee4751992f..788249c9dec 100644
--- a/src/include/c.h
+++ b/src/include/c.h
@@ -960,18 +960,32 @@ pg_noreturn extern void ExceptionalCondition(const char
*conditionName,
/*
* StaticAssertExpr() is for use in an expression.
*
- * For compilers without GCC statement expressions, we fall back on a kluge
- * that assumes the compiler will complain about a negative width for a struct
- * bit-field. This will not include a helpful error message, but it beats not
- * getting an error at all.
+ * See <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3715.pdf> for some
+ * rationale for the precise behavior of this implementation. See
+ * <https://stackoverflow.com/questions/31311748> about the C++
+ * implementation.
+ *
+ * For compilers that don't support this, we fall back on a kluge that assumes
+ * the compiler will complain about a negative width for a struct bit-field.
+ * This will not include a helpful error message, but it beats not getting an
+ * error at all.
*/
-#ifdef HAVE_STATEMENT_EXPRESSIONS
+#ifndef __cplusplus
+#if !defined(_MSC_VER) || _MSC_VER >= 1933
#define StaticAssertExpr(condition, errmessage) \
- ((void) ({ static_assert(condition, errmessage); true; }))
-#else
+ ((void) sizeof(struct {static_assert(condition, errmessage); char a;}))
+#else /* _MSC_VER < 1933 */
+/*
+ * This compiler is buggy and fails to compile the previous variant; use a
+ * fallback implementation.
+ */
#define StaticAssertExpr(condition, errmessage) \
((void) sizeof(struct { int static_assert_failure : (condition) ? 1 :
-1; }))
-#endif /*
HAVE_STATEMENT_EXPRESSIONS */
+#endif /* _MSC_VER < 1933 */
+#else /* __cplusplus */
+#define StaticAssertExpr(condition, errmessage) \
+ ([]{static_assert(condition, errmessage);})
+#endif
/*
--
2.53.0