On Sun Dec 7, 2025 at 8:45 PM CET, Tom Lane wrote:
#ifdef __cplusplus #undef typeof #define typeof decltype #define HAVE_TYPEOF 1 #endif
Went with defining pg_exprtype (pg_typeof already exists). Undefining typeof seemed a bit heavy-handed. Especially since I think it would be nice to backport this so C++ extensions can use copyObject directly.
BTW, grepping finds a number of random references to __typeof__ and __typeof, which probably ought to be updated to be just typeof.
Added a follow on patch that starts using pg_exrtype in all those places.
From 5a076be8b919034c7ff469e39a92d76c78590a59 Mon Sep 17 00:00:00 2001 From: Jelte Fennema-Nio <[email protected]> Date: Fri, 5 Dec 2025 15:37:59 +0100 Subject: [PATCH v2 1/2] Make copyObject work in C++ Calling copyObject fails in C++ with an error like in most setups: error: use of undeclared identifier 'typeof'; did you mean 'typeid' This is due to the C compiler supporting used to compile postgres supporting typeof, but that function actually not being present in the C++ compiler. This fixes that by defining pg_exprtype which maps to typeof or decltype depending on the compiler. While pg_typeof would have been a more natural name, that one is already taken in our codebase as the implementation of the pg_typeof UDF. --- src/include/c.h | 13 +++++++++++++ src/include/nodes/nodes.h | 4 ++-- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/include/c.h b/src/include/c.h index ccd2b654d45..46a97f11ae7 100644 --- a/src/include/c.h +++ b/src/include/c.h @@ -407,6 +407,19 @@ #define unlikely(x) ((x) != 0) #endif +/* + * pg_exprtype + * Get the type of an expression at compile time. + * + * In C++ we use decltype since typeof is not standard C++, while in C we use + * typeof when available. + */ +#if defined(__cplusplus) +#define pg_exprtype(x) decltype(x) +#elif defined(HAVE_TYPEOF) +#define pg_exprtype(x) typeof(x) +#endif + /* * CppAsString * Convert the argument to a string, using the C preprocessor. diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h index fb3957e75e5..a8f42431828 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 pg_exprtype +#define copyObject(obj) ((pg_exprtype(obj)) copyObjectImpl(obj)) #else #define copyObject(obj) copyObjectImpl(obj) #endif base-commit: 31280d96a64850f5a9a924088890ab43a2905237 -- 2.52.0
From 62f920e519004d692b14659c5d00546baa6be87c Mon Sep 17 00:00:00 2001 From: Jelte Fennema-Nio <[email protected]> Date: Mon, 8 Dec 2025 08:13:51 +0100 Subject: [PATCH v2 2/2] Use pg_exprtype instead of __typeof__ or __typeof The previous commit introduced pg_exprtype. This starts using that in a few more places. --- src/include/c.h | 8 ++++---- src/include/utils/relptr.h | 16 ++++------------ 2 files changed, 8 insertions(+), 16 deletions(-) diff --git a/src/include/c.h b/src/include/c.h index 46a97f11ae7..230ea2d10af 100644 --- a/src/include/c.h +++ b/src/include/c.h @@ -987,10 +987,10 @@ pg_noreturn extern void ExceptionalCondition(const char *conditionName, */ #ifdef HAVE__BUILTIN_TYPES_COMPATIBLE_P #define AssertVariableIsOfType(varname, typename) \ - StaticAssertStmt(__builtin_types_compatible_p(__typeof__(varname), typename), \ + StaticAssertStmt(__builtin_types_compatible_p(pg_exprtype(varname), typename), \ CppAsString(varname) " does not have type " CppAsString(typename)) #define AssertVariableIsOfTypeMacro(varname, typename) \ - (StaticAssertExpr(__builtin_types_compatible_p(__typeof__(varname), typename), \ + (StaticAssertExpr(__builtin_types_compatible_p(pg_exprtype(varname), typename), \ CppAsString(varname) " does not have type " CppAsString(typename))) #else /* !HAVE__BUILTIN_TYPES_COMPATIBLE_P */ #define AssertVariableIsOfType(varname, typename) \ @@ -1238,11 +1238,11 @@ typedef struct PGAlignedXLogBlock #define unvolatize(underlying_type, expr) const_cast<underlying_type>(expr) #elif defined(HAVE__BUILTIN_TYPES_COMPATIBLE_P) #define unconstify(underlying_type, expr) \ - (StaticAssertExpr(__builtin_types_compatible_p(__typeof(expr), const underlying_type), \ + (StaticAssertExpr(__builtin_types_compatible_p(pg_exprtype(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(__builtin_types_compatible_p(pg_exprtype(expr), volatile underlying_type), \ "wrong cast"), \ (underlying_type) (expr)) #else diff --git a/src/include/utils/relptr.h b/src/include/utils/relptr.h index ea340fee657..dac61b13118 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 pg_exprtype #define relptr_access(base, rp) \ (AssertVariableIsOfTypeMacro(base, char *), \ - (__typeof__((rp).relptr_type)) ((rp).relptr_off == 0 ? NULL : \ + (pg_exprtype((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 pg_exprtype #define relptr_store(base, rp, val) \ (AssertVariableIsOfTypeMacro(base, char *), \ - AssertVariableIsOfTypeMacro(val, __typeof__((rp).relptr_type)), \ + AssertVariableIsOfTypeMacro(val, pg_exprtype((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))) -- 2.52.0
