]> git.ipfire.org Git - thirdparty/postgresql.git/commitdiff
Support using copyObject in standard C++
authorPeter Eisentraut <peter@eisentraut.org>
Mon, 2 Mar 2026 10:46:02 +0000 (11:46 +0100)
committerPeter Eisentraut <peter@eisentraut.org>
Mon, 2 Mar 2026 10:48:13 +0000 (11:48 +0100)
Calling copyObject in C++ without GNU extensions (e.g. when using
-std=c++11 instead of -std=gnu++11) fails with an error like this:

error: use of undeclared identifier 'typeof'; did you mean 'typeid'

This is due to the C compiler used to compile PostgreSQL supporting
typeof, but that function actually not being present in the C++
compiler.  This fixes that by explicitely checking for typeof support
in C++, and then either use that or define typeof ourselves as:

    std::remove_reference_t<decltype(x)>

According to the paper that led to adding typeof to the C standard,
that's the C++ equivalent of the C typeof:
https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2927.htm#existing-decltype

Author: Author: Jelte Fennema-Nio <postgres@jeltef.nl>
Discussion: https://www.postgresql.org/message-id/flat/DGPW5WCFY7WY.1IHCDNIVVT300%2540jeltef.nl

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

index 1509dbfa2abe7b018d277fd6c0da0394635d4192..5b3cbc7e8e8eefc2d1a1d02db90a658d141c474b 100644 (file)
@@ -193,6 +193,35 @@ fi])# PGAC_C_TYPEOF
 
 
 
+# PGAC_CXX_TYPEOF
+# ----------------
+# Check if the C++ compiler understands typeof or a variant.  Define
+# HAVE_CXX_TYPEOF if so, and define 'pg_cxx_typeof' to the actual key word.
+#
+AC_DEFUN([PGAC_CXX_TYPEOF],
+[AC_CACHE_CHECK(for C++ typeof, pgac_cv_cxx_typeof,
+[pgac_cv_cxx_typeof=no
+AC_LANG_PUSH(C++)
+for pgac_kw in typeof __typeof__; do
+  AC_COMPILE_IFELSE([AC_LANG_PROGRAM([],
+[int x = 0;
+$pgac_kw(x) y;
+y = x;
+return y;])],
+[pgac_cv_cxx_typeof=$pgac_kw])
+  test "$pgac_cv_cxx_typeof" != no && break
+done
+AC_LANG_POP([])])
+if test "$pgac_cv_cxx_typeof" != no; then
+  AC_DEFINE(HAVE_CXX_TYPEOF, 1,
+            [Define to 1 if your C++ compiler understands `typeof' or something similar.])
+  if test "$pgac_cv_cxx_typeof" != typeof; then
+    AC_DEFINE_UNQUOTED(pg_cxx_typeof, $pgac_cv_cxx_typeof, [Define to how the C++ compiler spells `typeof'.])
+  fi
+fi])# PGAC_CXX_TYPEOF
+
+
+
 # PGAC_C_TYPES_COMPATIBLE
 # -----------------------
 # Check if the C compiler understands __builtin_types_compatible_p,
index ec4798fe5196212a1edd8d7f928150cb0f26485c..b30b98a586e72d7f6135c20c484d22f7380eaaae 100755 (executable)
--- a/configure
+++ b/configure
@@ -15078,6 +15078,60 @@ _ACEOF
 
   fi
 fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C++ typeof" >&5
+$as_echo_n "checking for C++ typeof... " >&6; }
+if ${pgac_cv_cxx_typeof+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  pgac_cv_cxx_typeof=no
+ac_ext=cpp
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+
+for pgac_kw in typeof __typeof__; 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_cxx_try_compile "$LINENO"; then :
+  pgac_cv_cxx_typeof=$pgac_kw
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+  test "$pgac_cv_cxx_typeof" != no && break
+done
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $pgac_cv_cxx_typeof" >&5
+$as_echo "$pgac_cv_cxx_typeof" >&6; }
+if test "$pgac_cv_cxx_typeof" != no; then
+
+$as_echo "#define HAVE_CXX_TYPEOF 1" >>confdefs.h
+
+  if test "$pgac_cv_cxx_typeof" != typeof; then
+
+cat >>confdefs.h <<_ACEOF
+#define pg_cxx_typeof $pgac_cv_cxx_typeof
+_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 :
index b2f6fdbe6acc041f2a7012434a083244811f0c5f..f4e3bd307c8425e923a20aded4f3cb19af147e76 100644 (file)
@@ -1732,6 +1732,7 @@ PGAC_PRINTF_ARCHETYPE
 PGAC_CXX_PRINTF_ARCHETYPE
 PGAC_C_STATEMENT_EXPRESSIONS
 PGAC_C_TYPEOF
+PGAC_CXX_TYPEOF
 PGAC_C_TYPES_COMPATIBLE
 PGAC_C_BUILTIN_CONSTANT_P
 PGAC_C_BUILTIN_OP_OVERFLOW
index 3ee8c2325f98e522e4240b9dd62bf0cddceb336b..ddf5172982fb6e78b8bfd108c33458b94ed40941 100644 (file)
@@ -2953,6 +2953,31 @@ int main(void)
   endif
 endforeach
 
+# Check if the C++ compiler understands typeof or a variant.
+if have_cxx
+  foreach kw : ['typeof', '__typeof__']
+    if cxx.compiles('''
+int main(void)
+{
+    int x = 0;
+    @0@(x) y;
+    y = x;
+    return y;
+}
+'''.format(kw),
+      name: 'C++ ' + kw,
+      args: test_c_args, include_directories: postgres_inc)
+
+      cdata.set('HAVE_CXX_TYPEOF', 1)
+      if kw != 'typeof'
+        cdata.set('pg_cxx_typeof', kw)
+      endif
+
+      break
+    endif
+  endforeach
+endif
+
 
 # MSVC doesn't cope well with defining restrict to __restrict, the
 # spelling it understands, because it conflicts with
index fb0ea1bc680b68ff032f3e186f38e0ea7ea4bb09..a4fee84398d040a584d6d254a5069da52f8b3ae6 100644 (file)
 #define unlikely(x) ((x) != 0)
 #endif
 
+/*
+ * Provide typeof in C++ for C++ compilers that don't support typeof natively.
+ * It might be spelled __typeof__ instead of typeof, in which case
+ * pg_cxx_typeof provides that mapping. If neither is supported, we can use
+ * decltype, but to make it equivalent to C's typeof, we need to remove
+ * references from the result [1]. Also ensure HAVE_TYPEOF is set so that
+ * typeof-dependent code is always enabled in C++ mode.
+ *
+ * [1]: https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2927.htm#existing-decltype
+ */
+#if defined(__cplusplus)
+#ifdef pg_cxx_typeof
+#define typeof(x) pg_cxx_typeof(x)
+#elif !defined(HAVE_CXX_TYPEOF)
+#define typeof(x) std::remove_reference_t<decltype(x)>
+#endif
+#ifndef HAVE_TYPEOF
+#define HAVE_TYPEOF 1
+#endif
+#endif
+
 /*
  * CppAsString
  *             Convert the argument to a string, using the C preprocessor.
index 538822cbc70566357fd63e67b924ddc79a4bcc49..f64b198738bc949e21cb861ab475b2b87f4c13df 100644 (file)
 /* Define to 1 if you have the <crtdefs.h> header file. */
 #undef HAVE_CRTDEFS_H
 
+/* Define to 1 if your C++ compiler understands `typeof' or something similar.
+   */
+#undef HAVE_CXX_TYPEOF
+
 /* Define to 1 if you have the declaration of `fdatasync', and to 0 if you
    don't. */
 #undef HAVE_DECL_FDATASYNC
 /* Define for large files, on AIX-style hosts. */
 #undef _LARGE_FILES
 
+/* Define to how the C++ compiler spells `typeof'. */
+#undef pg_cxx_typeof
+
 /* Define to keyword to use for C99 restrict support, or to nothing if not
    supported */
 #undef pg_restrict
index eb129dd15d46794de63fb6c460b423291b6f7ccf..ea04a761184ea46445fc3227637252bdf05755cb 100644 (file)
@@ -37,6 +37,7 @@ test_cplusplus_add(PG_FUNCTION_ARGS)
        int32           a = PG_GETARG_INT32(0);
        int32           b = PG_GETARG_INT32(1);
        RangeTblRef *node = makeNode(RangeTblRef);
+       RangeTblRef *copy = copyObject(node);
        List       *list = list_make1(node);
 
        foreach_ptr(RangeTblRef, rtr, list)
@@ -54,6 +55,7 @@ test_cplusplus_add(PG_FUNCTION_ARGS)
 
        list_free(list);
        pfree(node);
+       pfree(copy);
 
        switch (a)
        {