]> git.ipfire.org Git - thirdparty/postgresql.git/commitdiff
Replace __builtin_types_compatible_p with _Generic master github/master
authorPeter Eisentraut <peter@eisentraut.org>
Tue, 14 Jul 2026 08:28:04 +0000 (10:28 +0200)
committerPeter Eisentraut <peter@eisentraut.org>
Tue, 14 Jul 2026 08:30:46 +0000 (10:30 +0200)
_Generic is the C11 standard equivalent (and superset) of
__builtin_types_compatible_p, so by replacing the latter with the
former, we can now rely on this working on all compilers, instead of
previously just with GCC-compatible ones.  And we can drop a configure
test.

This affects StaticAssertVariableIsOfType() and
StaticAssertVariableIsOfTypeMacro() and indirectly unconstify() and
unvolatize().

Neither _Generic nor __builtin_types_compatible_p works in C++, so
this does not change that, but this adds an explicit code comment
about that.

There are some subtle behavior changes, but these do not affect cases
that are in use or likely to be useful.  _Generic does lvalue
conversion on the controlling expression, which means it drops
top-level qualifiers and converts arrays to pointers.
__builtin_types_compatible_p on the other hand, supports arrays and
just ignores qualifiers.  So before, StaticAssertVariableIsOfType(x,
const int) might have worked, but now it does not.  (But note that it
would previously have succeeded even if x was a non-const int, so this
usage would always have been dubious.)  Also,
StaticAssertVariableIsOfType(y, char[]) would have worked, but now you
need to write char *.  (But this is not backward compatible, because
char * would previously not have succeeded.)  Similarly, unconstify of
non-pointers, like unconstify(const int, x) would previously have
worked, but this was just by accident and never useful (you can just
assign directly, without a cast), and the C++ implementation rejects
non-pointers anyway.  Some comments are added to explain this a bit.
There are no current uses affected by this.

Note that even though we have required C11 since f5e0186f865, we have
not made use of _Generic until now (except in an MSVC-specific case in
commit 59c2f03d1ec).  This now raises the effective compiler
requirement on the trailing edge slightly from GCC 4.8 to GCC 4.9.
This in turn means that we effectively drop support for RHEL 7.

Author: Peter Eisentraut <peter@eisentraut.org>
Co-authored-by: Thomas Munro <thomas.munro@gmail.com>
Co-authored-by: Jelte Fennema-Nio <postgres@jeltef.nl>
Discussion: https://www.postgresql.org/message-id/flat/CA+hUKGL7trhWiJ4qxpksBztMMTWDyPnP1QN+Lq341V7QL775DA@mail.gmail.com

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

index 3eab0da9cb6c2420f0c4aeba6e0981b4c0bb0a8a..f05b744667c9fd27741ffa8bb83159b570625aea 100644 (file)
@@ -267,25 +267,6 @@ fi])# PGAC_CXX_TYPEOF_UNQUAL
 
 
 
-# PGAC_C_TYPES_COMPATIBLE
-# -----------------------
-# Check if the C compiler understands __builtin_types_compatible_p,
-# and define HAVE__BUILTIN_TYPES_COMPATIBLE_P if so.
-#
-# We check usage with __typeof__, though it's unlikely any compiler would
-# have the former and not the latter.
-AC_DEFUN([PGAC_C_TYPES_COMPATIBLE],
-[AC_CACHE_CHECK(for __builtin_types_compatible_p, pgac_cv__types_compatible,
-[AC_COMPILE_IFELSE([AC_LANG_PROGRAM([],
-[[ int x; static int y[__builtin_types_compatible_p(__typeof__(x), int)]; ]])],
-[pgac_cv__types_compatible=yes],
-[pgac_cv__types_compatible=no])])
-if test x"$pgac_cv__types_compatible" = xyes ; then
-AC_DEFINE(HAVE__BUILTIN_TYPES_COMPATIBLE_P, 1,
-          [Define to 1 if your compiler understands __builtin_types_compatible_p.])
-fi])# PGAC_C_TYPES_COMPATIBLE
-
-
 # PGAC_C_BUILTIN_CONSTANT_P
 # -------------------------
 # Check if the C compiler understands __builtin_constant_p(),
index 35b0b72f0a70f57fcda890c0d87713d2b756e15c..5fc85a245194a2740c20d3fb3d507ea93cf78fdf 100755 (executable)
--- a/configure
+++ b/configure
@@ -15181,36 +15181,6 @@ cat >>confdefs.h <<_ACEOF
 _ACEOF
 
   fi
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for __builtin_types_compatible_p" >&5
-$as_echo_n "checking for __builtin_types_compatible_p... " >&6; }
-if ${pgac_cv__types_compatible+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-
-int
-main ()
-{
- int x; static int y[__builtin_types_compatible_p(__typeof__(x), int)];
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
-  pgac_cv__types_compatible=yes
-else
-  pgac_cv__types_compatible=no
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $pgac_cv__types_compatible" >&5
-$as_echo "$pgac_cv__types_compatible" >&6; }
-if test x"$pgac_cv__types_compatible" = xyes ; then
-
-$as_echo "#define HAVE__BUILTIN_TYPES_COMPATIBLE_P 1" >>confdefs.h
-
 fi
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for __builtin_constant_p" >&5
 $as_echo_n "checking for __builtin_constant_p... " >&6; }
index 0e624fe36b96d94293cd8f87b893a57cd7be2048..dc4532126cb6f6cf3833b33098a8bc21fc53ef2b 100644 (file)
@@ -1727,7 +1727,6 @@ PGAC_C_TYPEOF
 PGAC_CXX_TYPEOF
 PGAC_C_TYPEOF_UNQUAL
 PGAC_CXX_TYPEOF_UNQUAL
-PGAC_C_TYPES_COMPATIBLE
 PGAC_C_BUILTIN_CONSTANT_P
 PGAC_C_BUILTIN_OP_OVERFLOW
 PGAC_C_BUILTIN_UNREACHABLE
index d88a7a70308780555726a608aa1e8c6e673f2c1a..8dea31e62df28ef0caeb556fccc8dff51fde0c0b 100644 (file)
@@ -2062,21 +2062,6 @@ foreach builtin : builtins
 endforeach
 
 
-# Check if the C compiler understands __builtin_types_compatible_p,
-# and define HAVE__BUILTIN_TYPES_COMPATIBLE_P if so.
-#
-# We check usage with __typeof__, though it's unlikely any compiler would
-# have the former and not the latter.
-if cc.compiles('''
-    static int x;
-    static int y[__builtin_types_compatible_p(__typeof__(x), int)];
-    ''',
-    name: '__builtin_types_compatible_p',
-    args: test_c_args)
-  cdata.set('HAVE__BUILTIN_TYPES_COMPATIBLE_P', 1)
-endif
-
-
 # Check if the C compiler understands __builtin_$op_overflow(),
 # and define HAVE__BUILTIN_OP_OVERFLOW if so.
 #
index 0e8053d1fe3d2fa6a39c3bca0e80d83c61dbab59..8d1aa4b639d81b64f350985ef2cc1df9cc229984 100644 (file)
@@ -1108,29 +1108,24 @@ pg_noreturn extern void ExceptionalCondition(const char *conditionName,
 /*
  * Compile-time checks that a variable (or expression) has the specified type.
  *
+ * The type must not have top-level qualifiers (const, volatile) and must not
+ * be an array (use pointer instead).  (This wouldn't work because _Generic
+ * does lvalue conversion on the controlling expression, which drops
+ * qualifiers and converts arrays to pointers.)  Qualifiers inside pointers
+ * are allowed.
+ *
  * StaticAssertVariableIsOfType() can be used as a declaration.
  * StaticAssertVariableIsOfTypeMacro() is intended for use in macros, eg
  *             #define foo(x) (StaticAssertVariableIsOfTypeMacro(x, int), bar(x))
  *
- * If we don't have __builtin_types_compatible_p, we can still assert that
- * the types have the same size.  This is far from ideal (especially on 32-bit
- * platforms) but it provides at least some coverage.
+ * Note that these do not work in C++.
  */
-#ifdef HAVE__BUILTIN_TYPES_COMPATIBLE_P
-#define StaticAssertVariableIsOfType(varname, typename) \
-       StaticAssertDecl(__builtin_types_compatible_p(typeof(varname), typename), \
-       CppAsString(varname) " does not have type " CppAsString(typename))
-#define StaticAssertVariableIsOfTypeMacro(varname, typename) \
-       (StaticAssertExpr(__builtin_types_compatible_p(typeof(varname), typename), \
-        CppAsString(varname) " does not have type " CppAsString(typename)))
-#else                                                  /* !HAVE__BUILTIN_TYPES_COMPATIBLE_P */
 #define StaticAssertVariableIsOfType(varname, typename) \
-       StaticAssertDecl(sizeof(varname) == sizeof(typename), \
+       StaticAssertDecl(_Generic((varname), typename: 1, default: 0), \
        CppAsString(varname) " does not have type " CppAsString(typename))
 #define StaticAssertVariableIsOfTypeMacro(varname, typename) \
-       (StaticAssertExpr(sizeof(varname) == sizeof(typename), \
+       (StaticAssertExpr(_Generic((varname), typename: 1, default: 0), \
         CppAsString(varname) " does not have type " CppAsString(typename)))
-#endif                                                 /* HAVE__BUILTIN_TYPES_COMPATIBLE_P */
 
 
 /* ----------------------------------------------------------------
@@ -1367,8 +1362,13 @@ typedef struct PGAlignedXLogBlock PGAlignedXLogBlock;
 
 /*
  * Macro that allows to cast constness and volatile away from an expression, but doesn't
- * allow changing the underlying type.  Enforcement of the latter
- * currently only works for gcc like compilers.
+ * allow changing the underlying type.
+ *
+ * This is only meant to work for qualifiers behind at least one level of
+ * pointer.  (In the C implementation, the StaticAssertVariableIsOfTypeMacro
+ * will drop top-level qualifiers, so with a non-pointer, the static assertion
+ * will fail.  In the C++ implementation, const_cast will error for
+ * non-pointers.)
  *
  * Please note IT IS NOT SAFE to cast constness away if the result will ever
  * be modified (it would be undefined behaviour). Doing so anyway can cause
index 4f8113c144b0c0bcc1da42a4babc1c8b671b240b..661c4a9b1684fd98b5a1b2d862f4876fc9905017 100644 (file)
 /* Define to 1 if your compiler understands __builtin_$op_overflow. */
 #undef HAVE__BUILTIN_OP_OVERFLOW
 
-/* Define to 1 if your compiler understands __builtin_types_compatible_p. */
-#undef HAVE__BUILTIN_TYPES_COMPATIBLE_P
-
 /* Define to 1 if your compiler understands __builtin_unreachable. */
 #undef HAVE__BUILTIN_UNREACHABLE