From 377b3b68c073c1b62bc0e5c357eed50624022cb5 Mon Sep 17 00:00:00 2001
From: Jelte Fennema-Nio <postgres@jeltef.nl>
Date: Sun, 15 Mar 2026 22:39:45 +0100
Subject: [PATCH v1] Check CLANG for typeof_unqual

Turns out that CLANG on the buildfarm is sometimes significantly older
than the CC compiler, and thus supports different features. This
explicitly checks typeof_unqual support for CLANG, because that's the
feature that sometimes seems to be lacking in practice.
---
 config/c-compiler.m4       | 45 +++++++++++++++++++++-----
 configure                  | 65 +++++++++++++++++++++++++++++++++-----
 configure.ac               |  6 ++++
 src/include/c.h            | 16 ++++++++++
 src/include/pg_config.h.in |  7 ++++
 5 files changed, 123 insertions(+), 16 deletions(-)

diff --git a/config/c-compiler.m4 b/config/c-compiler.m4
index 88333ef301d..6ae57199b1c 100644
--- a/config/c-compiler.m4
+++ b/config/c-compiler.m4
@@ -181,16 +181,12 @@ fi])# PGAC_C_TYPEOF
 # Check if the C compiler understands typeof_unqual or a variant.  Define
 # HAVE_TYPEOF_UNQUAL if so, and define 'typeof_unqual' to the actual key word.
 #
+# Test with a void pointer, because MSVC doesn't handle that, and we
+# need that for copyObject().
 AC_DEFUN([PGAC_C_TYPEOF_UNQUAL],
 [AC_CACHE_CHECK(for typeof_unqual, pgac_cv_c_typeof_unqual,
 [pgac_cv_c_typeof_unqual=no
-# Test the underscore variant first so that there is a higher chance
-# that clang used for bitcode also supports it, since we don't test
-# that separately.
-#
-# Test with a void pointer, because MSVC doesn't handle that, and we
-# need that for copyObject().
-for pgac_kw in __typeof_unqual__ typeof_unqual; do
+for pgac_kw in typeof_unqual __typeof_unqual__; do
   AC_COMPILE_IFELSE([AC_LANG_PROGRAM([],
 [int x = 0;
 $pgac_kw(x) y;
@@ -248,7 +244,7 @@ AC_DEFUN([PGAC_CXX_TYPEOF_UNQUAL],
 [AC_CACHE_CHECK(for C++ typeof_unqual, pgac_cv_cxx_typeof_unqual,
 [pgac_cv_cxx_typeof_unqual=no
 AC_LANG_PUSH(C++)
-for pgac_kw in __typeof_unqual__ typeof_unqual; do
+for pgac_kw in typeof_unqual __typeof_unqual__; do
   AC_COMPILE_IFELSE([AC_LANG_PROGRAM([],
 [int x = 0;
 $pgac_kw(x) y;
@@ -270,6 +266,39 @@ if test "$pgac_cv_cxx_typeof_unqual" != no; then
 fi])# PGAC_CXX_TYPEOF_UNQUAL
 
 
+# PGAC_CLANG_TYPEOF_UNQUAL
+# ------------------------
+# Check if CLANG (used for LLVM bitcode compilation) understands
+# typeof_unqual or a variant.  Define HAVE_CLANG_TYPEOF_UNQUAL if so, and
+# define 'pg_clang_typeof_unqual' to the actual key word.
+#
+AC_DEFUN([PGAC_CLANG_TYPEOF_UNQUAL],
+[AC_CACHE_CHECK(for CLANG typeof_unqual, pgac_cv_clang_typeof_unqual,
+[pgac_cv_clang_typeof_unqual=no
+pgac_save_CC=$CC
+CC="$CLANG"
+for pgac_kw in typeof_unqual __typeof_unqual__; do
+  _AC_COMPILE_IFELSE([AC_LANG_PROGRAM([],
+[int x = 0;
+$pgac_kw(x) y;
+const void *a;
+void *b;
+y = x;
+b = ($pgac_kw(*a) *) a;
+return y;])],
+[pgac_cv_clang_typeof_unqual=$pgac_kw])
+  test "$pgac_cv_clang_typeof_unqual" != no && break
+done
+CC="$pgac_save_CC"])
+if test "$pgac_cv_clang_typeof_unqual" != no; then
+  AC_DEFINE(HAVE_CLANG_TYPEOF_UNQUAL, 1,
+            [Define to 1 if CLANG for bitcode understands `typeof_unqual' or something similar.])
+  if test "$pgac_cv_clang_typeof_unqual" != typeof_unqual; then
+    AC_DEFINE_UNQUOTED(pg_clang_typeof_unqual, $pgac_cv_clang_typeof_unqual, [Define to how CLANG for bitcode spells `typeof_unqual'.])
+  fi
+fi])# PGAC_CLANG_TYPEOF_UNQUAL
+
+
 
 # PGAC_C_TYPES_COMPATIBLE
 # -----------------------
diff --git a/configure b/configure
index 4c789bd9289..80e29ff3ead 100755
--- a/configure
+++ b/configure
@@ -7077,6 +7077,9 @@ fi
 if test "$with_llvm" = yes ; then
   CLANGXX="$CLANG -xc++"
 
+  BITCODE_CFLAGS="$BITCODE_CFLAGS -DPG_COMPILING_BITCODE"
+  BITCODE_CXXFLAGS="$BITCODE_CXXFLAGS -DPG_COMPILING_BITCODE"
+
   { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${CLANG} supports -fno-strict-aliasing, for BITCODE_CFLAGS" >&5
 $as_echo_n "checking whether ${CLANG} supports -fno-strict-aliasing, for BITCODE_CFLAGS... " >&6; }
 if ${pgac_cv_prog_CLANG_cflags__fno_strict_aliasing+:} false; then :
@@ -15107,13 +15110,7 @@ if ${pgac_cv_c_typeof_unqual+:} false; then :
   $as_echo_n "(cached) " >&6
 else
   pgac_cv_c_typeof_unqual=no
-# Test the underscore variant first so that there is a higher chance
-# that clang used for bitcode also supports it, since we don't test
-# that separately.
-#
-# Test with a void pointer, because MSVC doesn't handle that, and we
-# need that for copyObject().
-for pgac_kw in __typeof_unqual__ typeof_unqual; do
+for pgac_kw in typeof_unqual __typeof_unqual__; do
   cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
 
@@ -15164,7 +15161,7 @@ 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_unqual__ typeof_unqual; do
+for pgac_kw in typeof_unqual __typeof_unqual__; do
   cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
 
@@ -15208,6 +15205,58 @@ cat >>confdefs.h <<_ACEOF
 _ACEOF
 
   fi
+fi
+if test "$with_llvm" = yes; then :
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for CLANG typeof_unqual" >&5
+$as_echo_n "checking for CLANG typeof_unqual... " >&6; }
+if ${pgac_cv_clang_typeof_unqual+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  pgac_cv_clang_typeof_unqual=no
+pgac_save_CC=$CC
+CC="$CLANG"
+for pgac_kw in typeof_unqual __typeof_unqual__; do
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+int x = 0;
+$pgac_kw(x) y;
+const void *a;
+void *b;
+y = x;
+b = ($pgac_kw(*a) *) a;
+return y;
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  pgac_cv_clang_typeof_unqual=$pgac_kw
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+  test "$pgac_cv_clang_typeof_unqual" != no && break
+done
+CC="$pgac_save_CC"
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $pgac_cv_clang_typeof_unqual" >&5
+$as_echo "$pgac_cv_clang_typeof_unqual" >&6; }
+if test "$pgac_cv_clang_typeof_unqual" != no; then
+
+$as_echo "#define HAVE_CLANG_TYPEOF_UNQUAL 1" >>confdefs.h
+
+  if test "$pgac_cv_clang_typeof_unqual" != typeof_unqual; then
+
+cat >>confdefs.h <<_ACEOF
+#define pg_clang_typeof_unqual $pgac_cv_clang_typeof_unqual
+_ACEOF
+
+  fi
+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; }
diff --git a/configure.ac b/configure.ac
index 9edffe481a6..69ad014238f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -686,6 +686,9 @@ AC_SUBST(CXXFLAGS_SL_MODULE)
 if test "$with_llvm" = yes ; then
   CLANGXX="$CLANG -xc++"
 
+  BITCODE_CFLAGS="$BITCODE_CFLAGS -DPG_COMPILING_BITCODE"
+  BITCODE_CXXFLAGS="$BITCODE_CXXFLAGS -DPG_COMPILING_BITCODE"
+
   PGAC_PROG_VARCC_VARFLAGS_OPT(CLANG, BITCODE_CFLAGS, [-fno-strict-aliasing])
   PGAC_PROG_VARCXX_VARFLAGS_OPT(CLANGXX, BITCODE_CXXFLAGS, [-fno-strict-aliasing])
   PGAC_PROG_VARCC_VARFLAGS_OPT(CLANG, BITCODE_CFLAGS, [-fwrapv])
@@ -1734,6 +1737,9 @@ PGAC_C_TYPEOF
 PGAC_CXX_TYPEOF
 PGAC_C_TYPEOF_UNQUAL
 PGAC_CXX_TYPEOF_UNQUAL
+AS_IF([test "$with_llvm" = yes], [
+  PGAC_CLANG_TYPEOF_UNQUAL
+])
 PGAC_C_TYPES_COMPATIBLE
 PGAC_C_BUILTIN_CONSTANT_P
 PGAC_C_BUILTIN_OP_OVERFLOW
diff --git a/src/include/c.h b/src/include/c.h
index 29fef2f54e1..e0dfb897529 100644
--- a/src/include/c.h
+++ b/src/include/c.h
@@ -466,6 +466,22 @@ extern "C++"
 #endif
 #endif							/* __cplusplus */
 
+/*
+ * Override typeof_unqual for LLVM bitcode compilation when CLANG doesn't
+ * support the same keyword as CC.  Analogous to the C++ override above.
+ * PG_COMPILING_BITCODE is defined in BITCODE_CFLAGS.
+ */
+#if defined(PG_COMPILING_BITCODE) && !defined(__cplusplus)
+#undef HAVE_TYPEOF_UNQUAL
+#undef typeof_unqual
+#ifdef pg_clang_typeof_unqual
+#define typeof_unqual(x) pg_clang_typeof_unqual(x)
+#define HAVE_TYPEOF_UNQUAL 1
+#elif defined(HAVE_CLANG_TYPEOF_UNQUAL)
+#define HAVE_TYPEOF_UNQUAL 1
+#endif
+#endif							/* PG_COMPILING_BITCODE && !__cplusplus */
+
 /*
  * CppAsString
  *		Convert the argument to a string, using the C preprocessor.
diff --git a/src/include/pg_config.h.in b/src/include/pg_config.h.in
index 79379a4d125..b1c20ce754a 100644
--- a/src/include/pg_config.h.in
+++ b/src/include/pg_config.h.in
@@ -54,6 +54,10 @@
 /* Define to 1 if you have the `backtrace_symbols' function. */
 #undef HAVE_BACKTRACE_SYMBOLS
 
+/* Define to 1 if CLANG for bitcode understands `typeof_unqual' or something
+   similar. */
+#undef HAVE_CLANG_TYPEOF_UNQUAL
+
 /* Define to 1 if your compiler handles computed gotos. */
 #undef HAVE_COMPUTED_GOTO
 
@@ -789,6 +793,9 @@
 /* Define for large files, on AIX-style hosts. */
 #undef _LARGE_FILES
 
+/* Define to how CLANG for bitcode spells `typeof_unqual'. */
+#undef pg_clang_typeof_unqual
+
 /* Define to how the C++ compiler spells `typeof'. */
 #undef pg_cxx_typeof
 

base-commit: a793677e57bc27c674cb94b230164b2c28f4cbae
-- 
2.53.0

