]> git.ipfire.org Git - thirdparty/postgresql.git/commitdiff
Refactor static_assert() support.
authorPeter Eisentraut <peter@eisentraut.org>
Mon, 15 Dec 2025 10:43:11 +0000 (11:43 +0100)
committerPeter Eisentraut <peter@eisentraut.org>
Mon, 15 Dec 2025 10:54:23 +0000 (11:54 +0100)
HAVE__STATIC_ASSERT was really a test for GCC statement expressions,
as needed for StaticAssertExpr() now that _Static_assert could be
assumed to be available through our C11 requirement.  This
artificially prevented Visual Studio from being able to use
static_assert() in other contexts.

Instead, make a new test for HAVE_STATEMENT_EXPRESSIONS, and use that
to control only whether StaticAssertExpr() uses fallback code, not the
other variants.  This improves the quality of failure messages in the
(much more common) other variants under Visual Studio.

Also get rid of the two separate implementations for C++, since the C
implementation is also also valid as C++11.  While it is a stretch to
apply HAVE_STATEMENT_EXPRESSIONS tested with $CC to a C++ compiler,
the previous C++ coding assumed that the C++ compiler had them
unconditionally, so it isn't a new stretch.  In practice, the C and
C++ compilers are very likely to agree, and if a combination is ever
reported that falsifies this assumption we can always reconsider that.

Author: Thomas Munro <thomas.munro@gmail.com>
Reviewed-by: Chao Li <li.evan.chao@gmail.com>
Discussion: https://postgr.es/m/CA%2BhUKGKvr0x_oGmQTUkx%3DODgSksT2EtgCA6LmGx_jQFG%3DsDUpg%40mail.gmail.com

config/c-compiler.m4
configure
configure.ac
meson.build
src/include/c.h
src/include/pg_config.h.in

index e309a5e3e40acd08f818121b28a3459d5f937a67..1509dbfa2abe7b018d277fd6c0da0394635d4192 100644 (file)
@@ -150,23 +150,19 @@ fi])# PGAC_TYPE_128BIT_INT
 
 
 
-# PGAC_C_STATIC_ASSERT
-# --------------------
-# Check if the C compiler understands _Static_assert(),
-# and define HAVE__STATIC_ASSERT if so.
-#
-# We actually check the syntax ({ _Static_assert(...) }), because we need
-# gcc-style compound expressions to be able to wrap the thing into macros.
-AC_DEFUN([PGAC_C_STATIC_ASSERT],
-[AC_CACHE_CHECK(for _Static_assert, pgac_cv__static_assert,
+# 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__static_assert=yes],
-[pgac_cv__static_assert=no])])
-if test x"$pgac_cv__static_assert" = xyes ; then
-AC_DEFINE(HAVE__STATIC_ASSERT, 1,
-          [Define to 1 if your compiler understands _Static_assert.])
-fi])# PGAC_C_STATIC_ASSERT
+[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
 
 
 
index 5ee3c265b1c1f9a709cf5d9295756f06d07430fe..14ad0a5006fa47897bbdb18fdf8e63064bbb63e7 100755 (executable)
--- a/configure
+++ b/configure
@@ -14846,9 +14846,9 @@ cat >>confdefs.h <<_ACEOF
 _ACEOF
 
 
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for _Static_assert" >&5
-$as_echo_n "checking for _Static_assert... " >&6; }
-if ${pgac_cv__static_assert+:} false; then :
+{ $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
@@ -14863,18 +14863,18 @@ main ()
 }
 _ACEOF
 if ac_fn_c_try_link "$LINENO"; then :
-  pgac_cv__static_assert=yes
+  pgac_cv_statement_expressions=yes
 else
-  pgac_cv__static_assert=no
+  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__static_assert" >&5
-$as_echo "$pgac_cv__static_assert" >&6; }
-if test x"$pgac_cv__static_assert" = xyes ; then
+{ $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__STATIC_ASSERT 1" >>confdefs.h
+$as_echo "#define HAVE_STATEMENT_EXPRESSIONS 1" >>confdefs.h
 
 fi
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for typeof" >&5
index 4ba3967db0fe64560ab64f3b556009dee44b05fe..01b3bbc1be82a8fdfb5cb94c65aa424f59fba04f 100644 (file)
@@ -1677,7 +1677,7 @@ AC_C_BIGENDIAN
 AC_C_INLINE
 PGAC_PRINTF_ARCHETYPE
 PGAC_CXX_PRINTF_ARCHETYPE
-PGAC_C_STATIC_ASSERT
+PGAC_C_STATEMENT_EXPRESSIONS
 PGAC_C_TYPEOF
 PGAC_C_TYPES_COMPATIBLE
 PGAC_C_BUILTIN_CONSTANT_P
index 1256094fa571c6348bdf203a7963df3c84721f68..d7c5193d4cee45a1f6862752f4d0bc4d49774464 100644 (file)
@@ -1880,20 +1880,16 @@ if cc.compiles('''
 endif
 
 
-# Check if the C compiler understands _Static_assert(),
-# and define HAVE__STATIC_ASSERT if so.
-#
-# We actually check the syntax ({ _Static_assert(...) }), because we need
-# gcc-style compound expressions to be able to wrap the thing into macros.
+# Check if the C compiler supports GCC-style statement expressions.
 if cc.compiles('''
     int main(int arg, char **argv)
     {
         ({ _Static_assert(1, "foo"); });
     }
     ''',
-    name: '_Static_assert',
+    name: 'statement expressions',
     args: test_c_args)
-  cdata.set('HAVE__STATIC_ASSERT', 1)
+  cdata.set('HAVE_STATEMENT_EXPRESSIONS', 1)
 endif
 
 
index d2cdc76644c57a83591c827befa0c7de9b0d0696..811d6d0110c04b5b6f522f7ca382d932a3e48990 100644 (file)
@@ -923,52 +923,31 @@ pg_noreturn extern void ExceptionalCondition(const char *conditionName,
  * If the "condition" (a compile-time-constant expression) evaluates to false,
  * throw a compile error using the "errmessage" (a string literal).
  *
- * C11 has _Static_assert(), and most C99 compilers already support that.  For
- * portability, we wrap it into StaticAssertDecl().  _Static_assert() is a
- * "declaration", and so it must be placed where for example a variable
+ * We require C11 and C++11, so static_assert() is expected to be there.
+ * StaticAssertDecl() was previously used for portability, but it's now just a
+ * plain wrapper and doesn't need to be used in new code.  static_assert() is
+ * a "declaration", and so it must be placed where for example a variable
  * declaration would be valid.  As long as we compile with
  * -Wno-declaration-after-statement, that also means it cannot be placed after
  * statements in a function.  Macros StaticAssertStmt() and StaticAssertExpr()
  * make it safe to use as a statement or in an expression, respectively.
  *
- * For compilers without _Static_assert(), we fall back on a kluge that
- * assumes the compiler will complain about a negative width for a struct
+ * 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.
  */
-#ifndef __cplusplus
-#ifdef HAVE__STATIC_ASSERT
-#define StaticAssertDecl(condition, errmessage) \
-       _Static_assert(condition, errmessage)
-#define StaticAssertStmt(condition, errmessage) \
-       do { _Static_assert(condition, errmessage); } while(0)
-#define StaticAssertExpr(condition, errmessage) \
-       ((void) ({ StaticAssertStmt(condition, errmessage); true; }))
-#else                                                  /* !HAVE__STATIC_ASSERT */
-#define StaticAssertDecl(condition, errmessage) \
-       extern void static_assert_func(int static_assert_failure[(condition) ? 1 : -1])
-#define StaticAssertStmt(condition, errmessage) \
-       ((void) sizeof(struct { int static_assert_failure : (condition) ? 1 : -1; }))
-#define StaticAssertExpr(condition, errmessage) \
-       StaticAssertStmt(condition, errmessage)
-#endif                                                 /* HAVE__STATIC_ASSERT */
-#else                                                  /* C++ */
-#if defined(__cpp_static_assert) && __cpp_static_assert >= 200410
 #define StaticAssertDecl(condition, errmessage) \
        static_assert(condition, errmessage)
 #define StaticAssertStmt(condition, errmessage) \
-       static_assert(condition, errmessage)
+       do { static_assert(condition, errmessage); } while(0)
+#ifdef HAVE_STATEMENT_EXPRESSIONS
 #define StaticAssertExpr(condition, errmessage) \
-       ({ static_assert(condition, errmessage); })
-#else                                                  /* !__cpp_static_assert */
-#define StaticAssertDecl(condition, errmessage) \
-       extern void static_assert_func(int static_assert_failure[(condition) ? 1 : -1])
-#define StaticAssertStmt(condition, errmessage) \
-       do { struct static_assert_struct { int static_assert_failure : (condition) ? 1 : -1; }; } while(0)
+       ((void) ({ static_assert(condition, errmessage); true; }))
+#else
 #define StaticAssertExpr(condition, errmessage) \
-       ((void) ({ StaticAssertStmt(condition, errmessage); }))
-#endif                                                 /* __cpp_static_assert */
-#endif                                                 /* C++ */
+       ((void) sizeof(struct { int static_assert_failure : (condition) ? 1 : -1; }))
+#endif                                                 /* HAVE_STATEMENT_EXPRESSIONS */
 
 
 /*
index 3a7edb1f0a02a6aecdcf13e34eef4da3548ce491..92fcc5f30639b52fdefc50b86003197788d9436e 100644 (file)
 /* Define to 1 if you have the `SSL_CTX_set_num_tickets' function. */
 #undef HAVE_SSL_CTX_SET_NUM_TICKETS
 
+/* Define to 1 if your compiler supports statement expressions. */
+#undef HAVE_STATEMENT_EXPRESSIONS
+
 /* Define to 1 if you have the <stdint.h> header file. */
 #undef HAVE_STDINT_H
 
 /* Define to 1 if you have __get_cpuid_count. */
 #undef HAVE__GET_CPUID_COUNT
 
-/* Define to 1 if your compiler understands _Static_assert. */
-#undef HAVE__STATIC_ASSERT
-
 /* Define as the maximum alignment requirement of any C data type. */
 #undef MAXIMUM_ALIGNOF