From 2d7130aab09383c88ca8c98d666144df70d0f2da 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 v7 2/5] Support using copyObject in C++

Calling copyObject in C++ without GNU extensions 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 the 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 |  6 ++++++
 3 files changed, 21 insertions(+), 2 deletions(-)

diff --git a/src/include/c.h b/src/include/c.h
index c0be07a4566..08490641906 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 b6ad28618ab..f5e17e670b7 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 7108e5b1cc5..48741f27949 100644
--- a/src/test/modules/test_cplusplusext/test_cplusplusext.cpp
+++ b/src/test/modules/test_cplusplusext/test_cplusplusext.cpp
@@ -17,6 +17,7 @@
 extern "C" {
 #include "postgres.h"
 #include "fmgr.h"
+#include "nodes/parsenodes.h"
 
 PG_MODULE_MAGIC_EXT("test_cplusplusext", "1.2");
 
@@ -32,6 +33,11 @@ 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);
+
+	pfree(copy);
+	pfree(node);
 
 	PG_RETURN_INT32(a + b);
 }
-- 
2.52.0

