From 437a8aece153c5dc24c0e2708c034fe1718ea3bf Mon Sep 17 00:00:00 2001
From: Jelte Fennema-Nio <postgres@jeltef.nl>
Date: Fri, 13 Feb 2026 09:39:34 +0100
Subject: [PATCH v10 4/4] Add C++ version of __builtin_types_compatible_p

StaticAssertVariableIsOfType would fail to compile in C++ extensions if
meson/autoconf has detected HAVE__BUILTIN_TYPES_COMPATIBLE_P to be true
for the C compiler. Basically equivalent to the PG_PRINTF_ATTRIBUTE
situation in 0909380e4c9.

This fixes that problem by defining __builtin_types_compatible_p in C++
using an equivalent STL constructs.
---
 src/include/c.h                               | 22 +++++++++++++++++++
 .../test_cplusplusext/test_cplusplusext.cpp   | 20 ++++++++++++++++-
 2 files changed, 41 insertions(+), 1 deletion(-)

diff --git a/src/include/c.h b/src/include/c.h
index c92b214f6b0..ba629a3503b 100644
--- a/src/include/c.h
+++ b/src/include/c.h
@@ -80,6 +80,12 @@
 #ifdef HAVE_XLOCALE_H
 #include <xlocale.h>
 #endif
+#ifdef __cplusplus
+extern "C++"
+{
+#include <type_traits>
+}
+#endif
 #ifdef ENABLE_NLS
 #include <libintl.h>
 #endif
@@ -443,7 +449,23 @@
 #ifndef HAVE_TYPEOF
 #define HAVE_TYPEOF 1
 #endif
+/*
+ * Provide __builtin_types_compatible_p for C++ by comparing types with
+ * std::is_same after stripping cv-qualifiers. The second branch handles
+ * GCC's special case where an incomplete array (e.g. int[]) is considered
+ * compatible with a complete array of the same element type (e.g. int[3]).
+ */
+#define __builtin_types_compatible_p(x, y) \
+	(std::is_same<std::remove_cv_t<x>, std::remove_cv_t<y>>::value || \
+	 (std::is_array<x>::value && std::is_array<y>::value && \
+	  (std::extent<x>::value == 0 || std::extent<y>::value == 0) && \
+	  std::is_same<std::remove_cv_t<std::remove_extent_t<x>>, \
+				   std::remove_cv_t<std::remove_extent_t<y>>>::value))
+#ifndef HAVE__BUILTIN_TYPES_COMPATIBLE_P
+#define HAVE__BUILTIN_TYPES_COMPATIBLE_P 1
 #endif
+#endif
+
 
 /*
  * CppAsString
diff --git a/src/test/modules/test_cplusplusext/test_cplusplusext.cpp b/src/test/modules/test_cplusplusext/test_cplusplusext.cpp
index ea04a761184..936ca422c76 100644
--- a/src/test/modules/test_cplusplusext/test_cplusplusext.cpp
+++ b/src/test/modules/test_cplusplusext/test_cplusplusext.cpp
@@ -34,11 +34,14 @@ StaticAssertDecl(sizeof(int32) == 4, "int32 should be 4 bytes");
 extern "C" Datum
 test_cplusplus_add(PG_FUNCTION_ARGS)
 {
-	int32		a = PG_GETARG_INT32(0);
+	const int32		a = PG_GETARG_INT32(0);
 	int32		b = PG_GETARG_INT32(1);
+	const char *p = "";
 	RangeTblRef *node = makeNode(RangeTblRef);
 	RangeTblRef *copy = copyObject(node);
 	List	   *list = list_make1(node);
+	const int32 int_array[3] = {0};
+	extern int32 incomplete_array[];
 
 	foreach_ptr(RangeTblRef, rtr, list)
 	{
@@ -52,6 +55,21 @@ test_cplusplus_add(PG_FUNCTION_ARGS)
 
 	StaticAssertStmt(sizeof(int32) == 4, "int32 should be 4 bytes");
 	(void) StaticAssertExpr(sizeof(int64) == 8, "int64 should be 8 bytes");
+	StaticAssertVariableIsOfType(a, int32);
+	StaticAssertVariableIsOfType(a, const int32);
+	StaticAssertVariableIsOfType(b, const int32);
+	StaticAssertVariableIsOfType(int_array, int32[3]);
+	StaticAssertVariableIsOfType(int_array, const int32[3]);
+	StaticAssertVariableIsOfType(p, const char *);
+	StaticAssertVariableIsOfTypeMacro(a, int32);
+	StaticAssertVariableIsOfTypeMacro(a, const int32);
+	StaticAssertVariableIsOfTypeMacro(b, int32);
+	StaticAssertVariableIsOfTypeMacro(int_array, int32[3]);
+	StaticAssertVariableIsOfTypeMacro(int_array, const int32[3]);
+	StaticAssertVariableIsOfTypeMacro(p, const char *);
+	/* incomplete array matches complete array type */
+	StaticAssertVariableIsOfType(incomplete_array, int32[3]);
+	StaticAssertVariableIsOfTypeMacro(incomplete_array, int32[3]);
 
 	list_free(list);
 	pfree(node);
-- 
2.53.0

