From cb57b403ee7819f7512a5e5edcd4ce1cb876ee46 Mon Sep 17 00:00:00 2001
From: Jelte Fennema-Nio <postgres@jeltef.nl>
Date: Fri, 5 Dec 2025 15:37:59 +0100
Subject: [PATCH v8 3/6] Support using copyObject in C++

Calling copyObject in C++ without GNU extensions (e.g. then 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 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 whether it's a C or C++ compiler. While
pg_typeof would have been a more natural name, that name 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 ++--
 .../modules/test_cplusplusext/test_cplusplusext.cpp |  2 ++
 3 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/src/include/c.h b/src/include/c.h
index 3fc09ec1e4a..9f418e432ea 100644
--- a/src/include/c.h
+++ b/src/include/c.h
@@ -412,6 +412,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 59a7df31aba..a03c85f1b01 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
diff --git a/src/test/modules/test_cplusplusext/test_cplusplusext.cpp b/src/test/modules/test_cplusplusext/test_cplusplusext.cpp
index 8c2eabcca43..5e6c8f85f6f 100644
--- a/src/test/modules/test_cplusplusext/test_cplusplusext.cpp
+++ b/src/test/modules/test_cplusplusext/test_cplusplusext.cpp
@@ -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);
 
 	PG_RETURN_INT32(a + b);
 }
-- 
2.52.0

