On Tue, 9 Dec 2025 at 13:43, Jelte Fennema-Nio <[email protected]> wrote:
You mean use const_cast in c++ instead of a C-style cast? Would you still want to keep the static asserts.
I now understand that you meant to not remove these lines: -#if defined(__cplusplus) -#define unconstify(underlying_type, expr) const_cast<underlying_type>(expr) -#define unvolatize(underlying_type, expr) const_cast<underlying_type>(expr) So like the attached. I think that makes sense.
From b77214510b9c5cdf2b0d0130526f98d3ab8a7864 Mon Sep 17 00:00:00 2001 From: Thomas Munro <[email protected]> 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
