v2-0001-Add-pg_expr_has_type_p-for-type-check-assertions.patch
text/x-patch
Filename: v2-0001-Add-pg_expr_has_type_p-for-type-check-assertions.patch
Type: text/x-patch
Part: 0
From b77214510b9c5cdf2b0d0130526f98d3ab8a7864 Mon Sep 17 00:00:00 2001
From: Thomas Munro <thomas.munro@gmail.com>
Date: Fri, 31 Oct 2025 06:07:15 +1300
Subject: [PATCH v2] Add pg_expr_has_type_p() for type check assertions.
Remove use of GCC builtins, so our existing type check macros can work
on Visual Studio too. This relies on new features in C11/C++11.
XXX works on Visual Studio 2022, crashes on Visual Studio 2019:
[23:39:47.176] ../src/common/file_utils.c(712): fatal error C1001: Internal compiler error.
[23:39:47.176] (compiler file 'msc1.cpp', line 1603)
[23:39:47.176] To work around this problem, try simplifying or changing the program near the locations listed above.
---
config/c-compiler.m4 | 19 ------------------
configure | 30 ----------------------------
configure.ac | 1 -
meson.build | 15 --------------
src/include/c.h | 41 +++++++++++++++++---------------------
src/include/pg_config.h.in | 3 ---
src/include/utils/relptr.h | 16 ++++-----------
7 files changed, 22 insertions(+), 103 deletions(-)
diff --git a/config/c-compiler.m4 b/config/c-compiler.m4
index 236a59e8536..26d5269e58a 100644
--- a/config/c-compiler.m4
+++ b/config/c-compiler.m4
@@ -161,25 +161,6 @@ fi])# PGAC_C_TYPEOF
-# 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(),
diff --git a/configure b/configure
index ec35de5ba65..48c3799af46 100755
--- a/configure
+++ b/configure
@@ -14828,36 +14828,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; }
diff --git a/configure.ac b/configure.ac
index 7284f1ff622..fe7e2610f70 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1678,7 +1678,6 @@ AC_C_INLINE
PGAC_PRINTF_ARCHETYPE
PGAC_C_STATIC_ASSERT
PGAC_C_TYPEOF
-PGAC_C_TYPES_COMPATIBLE
PGAC_C_BUILTIN_CONSTANT_P
PGAC_C_BUILTIN_OP_OVERFLOW
PGAC_C_BUILTIN_UNREACHABLE
diff --git a/meson.build b/meson.build
index 622598546ae..2b67500af8b 100644
--- a/meson.build
+++ b/meson.build
@@ -1950,21 +1950,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.
#
diff --git a/src/include/c.h b/src/include/c.h
index 62cbf7a2eec..2ccdfd10fa7 100644
--- a/src/include/c.h
+++ b/src/include/c.h
@@ -81,6 +81,13 @@
#endif
#ifdef ENABLE_NLS
#include <libintl.h>
+#endif
+
+#ifdef __cplusplus
+extern "C++"
+{
+#include <type_traits>
+}
#endif
/* Pull in fundamental symbols that we also expose to applications */
@@ -967,26 +974,19 @@ pg_noreturn extern void ExceptionalCondition(const char *conditionName,
* AssertVariableIsOfType() can be used as a statement.
* AssertVariableIsOfTypeMacro() is intended for use in macros, eg
* #define foo(x) (AssertVariableIsOfTypeMacro(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.
*/
-#ifdef HAVE__BUILTIN_TYPES_COMPATIBLE_P
-#define AssertVariableIsOfType(varname, typename) \
- StaticAssertStmt(__builtin_types_compatible_p(__typeof__(varname), typename), \
- CppAsString(varname) " does not have type " CppAsString(typename))
-#define AssertVariableIsOfTypeMacro(varname, typename) \
- (StaticAssertExpr(__builtin_types_compatible_p(__typeof__(varname), typename), \
- CppAsString(varname) " does not have type " CppAsString(typename)))
-#else /* !HAVE__BUILTIN_TYPES_COMPATIBLE_P */
+#ifdef __cplusplus
+#define pg_expr_has_type_p(expr, typename) \
+ std::is_same<std::remove_reference<decltype(expr)>::type, typename>::value
+#else
+#define pg_expr_has_type_p(expr, typename) _Generic((expr), typename: 1, default: 0)
+#endif
#define AssertVariableIsOfType(varname, typename) \
- StaticAssertStmt(sizeof(varname) == sizeof(typename), \
+ StaticAssertStmt(pg_expr_has_type_p(varname, typename), \
CppAsString(varname) " does not have type " CppAsString(typename))
#define AssertVariableIsOfTypeMacro(varname, typename) \
- (StaticAssertExpr(sizeof(varname) == sizeof(typename), \
+ (StaticAssertExpr(pg_expr_has_type_p(varname, typename), \
CppAsString(varname) " does not have type " CppAsString(typename)))
-#endif /* HAVE__BUILTIN_TYPES_COMPATIBLE_P */
/* ----------------------------------------------------------------
@@ -1223,20 +1223,15 @@ typedef struct PGAlignedXLogBlock
#if defined(__cplusplus)
#define unconstify(underlying_type, expr) const_cast<underlying_type>(expr)
#define unvolatize(underlying_type, expr) const_cast<underlying_type>(expr)
-#elif defined(HAVE__BUILTIN_TYPES_COMPATIBLE_P)
+#else
#define unconstify(underlying_type, expr) \
- (StaticAssertExpr(__builtin_types_compatible_p(__typeof(expr), const underlying_type), \
+ (StaticAssertExpr(pg_expr_has_type_p((expr), const underlying_type), \
"wrong cast"), \
(underlying_type) (expr))
#define unvolatize(underlying_type, expr) \
- (StaticAssertExpr(__builtin_types_compatible_p(__typeof(expr), volatile underlying_type), \
+ (StaticAssertExpr(pg_expr_has_type_p((expr), volatile underlying_type), \
"wrong cast"), \
(underlying_type) (expr))
-#else
-#define unconstify(underlying_type, expr) \
- ((underlying_type) (expr))
-#define unvolatize(underlying_type, expr) \
- ((underlying_type) (expr))
#endif
/* ----------------------------------------------------------------
diff --git a/src/include/pg_config.h.in b/src/include/pg_config.h.in
index b0b0cfdaf79..4a25155239e 100644
--- a/src/include/pg_config.h.in
+++ b/src/include/pg_config.h.in
@@ -547,9 +547,6 @@
/* Define to 1 if your compiler understands __builtin_popcount. */
#undef HAVE__BUILTIN_POPCOUNT
-/* 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
diff --git a/src/include/utils/relptr.h b/src/include/utils/relptr.h
index ea340fee657..48e394dba71 100644
--- a/src/include/utils/relptr.h
+++ b/src/include/utils/relptr.h
@@ -38,16 +38,12 @@
#define relptr_declare(type, relptrtype) \
typedef relptr(type) relptrtype
-#ifdef HAVE__BUILTIN_TYPES_COMPATIBLE_P
+#ifdef HAVE_TYPEOF
#define relptr_access(base, rp) \
(AssertVariableIsOfTypeMacro(base, char *), \
- (__typeof__((rp).relptr_type)) ((rp).relptr_off == 0 ? NULL : \
+ (typeof((rp).relptr_type)) ((rp).relptr_off == 0 ? NULL : \
(base) + (rp).relptr_off - 1))
#else
-/*
- * If we don't have __builtin_types_compatible_p, assume we might not have
- * __typeof__ either.
- */
#define relptr_access(base, rp) \
(AssertVariableIsOfTypeMacro(base, char *), \
(void *) ((rp).relptr_off == 0 ? NULL : (base) + (rp).relptr_off - 1))
@@ -72,16 +68,12 @@ relptr_store_eval(char *base, char *val)
}
}
-#ifdef HAVE__BUILTIN_TYPES_COMPATIBLE_P
+#ifdef HAVE_TYPEOF
#define relptr_store(base, rp, val) \
(AssertVariableIsOfTypeMacro(base, char *), \
- AssertVariableIsOfTypeMacro(val, __typeof__((rp).relptr_type)), \
+ AssertVariableIsOfTypeMacro(val, typeof((rp).relptr_type)), \
(rp).relptr_off = relptr_store_eval((base), (char *) (val)))
#else
-/*
- * If we don't have __builtin_types_compatible_p, assume we might not have
- * __typeof__ either.
- */
#define relptr_store(base, rp, val) \
(AssertVariableIsOfTypeMacro(base, char *), \
(rp).relptr_off = relptr_store_eval((base), (char *) (val)))
base-commit: f231a4e8c7f2ce93203cedea7a02ef3eeb744647
--
2.52.0