From 1e733f16f116be638cbd4f6a359a01541c9a5d24 Mon Sep 17 00:00:00 2001 From: Peter Eisentraut Date: Mon, 8 Dec 2025 08:33:18 +0100 Subject: [PATCH] Change copyObject() to use typeof_unqual The new implementation ensures that the result of copyObject() is not const-qualified when the input is. This was previously incorrect, since the point of copyObject() is to make a copy to mutate, but apparently no code ran into it. --- config/c-compiler.m4 | 25 +++++++++++++++++++++++ configure | 42 ++++++++++++++++++++++++++++++++++++++ configure.ac | 1 + meson.build | 24 ++++++++++++++++++++++ src/include/nodes/nodes.h | 4 ++-- src/include/pg_config.h.in | 7 +++++++ 6 files changed, 101 insertions(+), 2 deletions(-) diff --git a/config/c-compiler.m4 b/config/c-compiler.m4 index 236a59e8536..8ee860c9091 100644 --- a/config/c-compiler.m4 +++ b/config/c-compiler.m4 @@ -160,6 +160,31 @@ if test "$pgac_cv_c_typeof" != no; then fi])# PGAC_C_TYPEOF +# PGAC_C_TYPEOF_UNQUAL +# -------------------- +# Check if the C compiler understands typeof_unqual or a variant. Define +# HAVE_TYPEOF_UNQUAL if so, and define 'typeof_unqual' to the actual key word. +# +AC_DEFUN([PGAC_C_TYPEOF_UNQUAL], +[AC_CACHE_CHECK(for typeof_unqual, pgac_cv_c_typeof_unqual, +[pgac_cv_c_typeof_unqual=no +for pgac_kw in typeof_unqual __typeof_unqual__; do + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([], +[int x = 0; +$pgac_kw(x) y; +y = x; +return y;])], +[pgac_cv_c_typeof_unqual=$pgac_kw]) + test "$pgac_cv_c_typeof_unqual" != no && break +done]) +if test "$pgac_cv_c_typeof_unqual" != no; then + AC_DEFINE(HAVE_TYPEOF_UNQUAL, 1, + [Define to 1 if your compiler understands `typeof_unqual' or something similar.]) + if test "$pgac_cv_c_typeof_unqual" != typeof_unqual; then + AC_DEFINE_UNQUOTED(typeof_unqual, $pgac_cv_c_typeof_unqual, [Define to how the compiler spells `typeof_unqual'.]) + fi +fi])# PGAC_C_TYPEOF_UNQUAL + # PGAC_C_TYPES_COMPATIBLE # ----------------------- diff --git a/configure b/configure index 3a0ed11fa8e..af856b20f0b 100755 --- a/configure +++ b/configure @@ -14787,6 +14787,48 @@ _ACEOF fi fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for typeof_unqual" >&5 +$as_echo_n "checking for typeof_unqual... " >&6; } +if ${pgac_cv_c_typeof_unqual+:} false; then : + $as_echo_n "(cached) " >&6 +else + pgac_cv_c_typeof_unqual=no +for pgac_kw in typeof_unqual __typeof_unqual__; do + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +int x = 0; +$pgac_kw(x) y; +y = x; +return y; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + pgac_cv_c_typeof_unqual=$pgac_kw +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + test "$pgac_cv_c_typeof_unqual" != no && break +done +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $pgac_cv_c_typeof_unqual" >&5 +$as_echo "$pgac_cv_c_typeof_unqual" >&6; } +if test "$pgac_cv_c_typeof_unqual" != no; then + +$as_echo "#define HAVE_TYPEOF_UNQUAL 1" >>confdefs.h + + if test "$pgac_cv_c_typeof_unqual" != typeof_unqual; then + +cat >>confdefs.h <<_ACEOF +#define typeof_unqual $pgac_cv_c_typeof_unqual +_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 : diff --git a/configure.ac b/configure.ac index c2413720a18..8eced24beb5 100644 --- a/configure.ac +++ b/configure.ac @@ -1676,6 +1676,7 @@ AC_C_INLINE PGAC_PRINTF_ARCHETYPE PGAC_C_STATIC_ASSERT PGAC_C_TYPEOF +PGAC_C_TYPEOF_UNQUAL PGAC_C_TYPES_COMPATIBLE PGAC_C_BUILTIN_CONSTANT_P PGAC_C_BUILTIN_OP_OVERFLOW diff --git a/meson.build b/meson.build index 6e7ddd74683..85b98ad81db 100644 --- a/meson.build +++ b/meson.build @@ -2818,6 +2818,30 @@ int main(void) endif endforeach +# Check if the C compiler understands typeof_unqual or a variant. Define +# HAVE_TYPEOF_UNQUAL if so, and define 'typeof_unqual' to the actual key word. +foreach kw : ['typeof_unqual', '__typeof_unqual__'] + if cc.compiles(''' +int main(void) +{ + int x = 0; + @0@(x) y; + y = x; + return y; +} +'''.format(kw), + name: kw, + args: test_c_args, include_directories: postgres_inc) + + cdata.set('HAVE_TYPEOF_UNQUAL', 1) + if kw != 'typeof_unqual' + cdata.set('typeof_unqual', kw) + endif + + break + endif +endforeach + # Even though restrict is in C99 and should be supported by all # supported compilers, this indirection is useful because __restrict diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h index fb3957e75e5..0ac0be1b288 100644 --- a/src/include/nodes/nodes.h +++ b/src/include/nodes/nodes.h @@ -226,8 +226,8 @@ extern int16 *readAttrNumberCols(int numCols); extern void *copyObjectImpl(const void *from); /* cast result back to argument type, if supported by compiler */ -#ifdef HAVE_TYPEOF -#define copyObject(obj) ((typeof(obj)) copyObjectImpl(obj)) +#ifdef HAVE_TYPEOF_UNQUAL +#define copyObject(obj) ((typeof_unqual(*(obj)) *) copyObjectImpl(obj)) #else #define copyObject(obj) copyObjectImpl(obj) #endif diff --git a/src/include/pg_config.h.in b/src/include/pg_config.h.in index b0b0cfdaf79..503467ca092 100644 --- a/src/include/pg_config.h.in +++ b/src/include/pg_config.h.in @@ -472,6 +472,10 @@ /* Define to 1 if your compiler understands `typeof' or something similar. */ #undef HAVE_TYPEOF +/* Define to 1 if your compiler understands `typeof_unqual' or something + similar. */ +#undef HAVE_TYPEOF_UNQUAL + /* Define to 1 if you have the header file. */ #undef HAVE_UCHAR_H @@ -815,3 +819,6 @@ /* Define to how the compiler spells `typeof'. */ #undef typeof + +/* Define to how the compiler spells `typeof_unqual'. */ +#undef typeof_unqual -- 2.52.0