Support using copyObject in standard C++

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
master
Peter Eisentraut 2 weeks ago
parent 386ca3908d
commit 1887d822f1
  1. 29
      config/c-compiler.m4
  2. 54
      configure
  3. 1
      configure.ac
  4. 25
      meson.build
  5. 21
      src/include/c.h
  6. 7
      src/include/pg_config.h.in
  7. 2
      src/test/modules/test_cplusplusext/test_cplusplusext.cpp

@ -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,

54
configure vendored

@ -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 :

@ -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

@ -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

@ -424,6 +424,27 @@
#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.

@ -69,6 +69,10 @@
/* 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
@ -780,6 +784,9 @@
/* 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

@ -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)
{

Loading…
Cancel
Save