On Sun, 15 Mar 2026 at 23:13, Tom Lane <[email protected]> wrote:

"Jelte Fennema-Nio" <[email protected]> writes:
> If not, then I'm starting to think that actually checking support for
> this feature for CLANG is probably easier to understand (and less
> fragile) than combining all of these tricks together. Attached is a
> patch to do so.

+1 for concept, but don't you need to fix meson.build too?

I believe that we don't have fully working bc compilation for meson[1],
so I'm not entirely sure how to test out if it actually works. But the
attached now does *something* for meson too at least.

[1]: 
https://www.postgresql.org/message-id/flat/206b001d-1884-4081-bd02-bed5c92f02ba%40eisentraut.org
From 2058a59b52b17ce15752b7f488082929967429c3 Mon Sep 17 00:00:00 2001
From: Jelte Fennema-Nio <[email protected]>
Date: Sun, 15 Mar 2026 22:39:45 +0100
Subject: [PATCH v2] 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 ++++++++++++++++++----
 config/test_typeof_unqual.c      | 20 ++++++++++
 configure                        | 65 ++++++++++++++++++++++++++++----
 configure.ac                     |  6 +++
 meson.build                      | 32 +++++++++++++---
 src/backend/jit/llvm/meson.build |  2 +-
 src/include/c.h                  | 16 ++++++++
 src/include/pg_config.h.in       |  7 ++++
 8 files changed, 170 insertions(+), 23 deletions(-)
 create mode 100644 config/test_typeof_unqual.c

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/config/test_typeof_unqual.c b/config/test_typeof_unqual.c
new file mode 100644
index 00000000000..108c8f5468b
--- /dev/null
+++ b/config/test_typeof_unqual.c
@@ -0,0 +1,20 @@
+/*
+ * Test program for typeof_unqual detection.
+ *
+ * Used by meson.build to check whether clang used for LLVM bitcode
+ * compilation supports typeof_unqual or a variant.  Pass -DKW=<keyword>
+ * to test a specific spelling.
+ */
+int
+main(void)
+{
+	int			x = 0;
+
+	KW(x) y;
+	const void *a;
+	void	   *b;
+
+	y = x;
+	b = (KW(*a) *) a;
+	return y;
+}
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/meson.build b/meson.build
index f7a87edcc94..f17970f1ae2 100644
--- a/meson.build
+++ b/meson.build
@@ -2969,13 +2969,9 @@ endif
 # 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 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().
-foreach kw : ['__typeof_unqual__', 'typeof_unqual']
+foreach kw : ['typeof_unqual', '__typeof_unqual__']
   if cc.compiles('''
 int main(void)
 {
@@ -3002,7 +2998,7 @@ endforeach
 
 # Check if the C++ compiler understands typeof_unqual or a variant.
 if have_cxx
-  foreach kw : ['__typeof_unqual__', 'typeof_unqual']
+  foreach kw : ['typeof_unqual', '__typeof_unqual__']
     if cxx.compiles('''
 int main(void)
 {
@@ -3028,6 +3024,30 @@ int main(void)
   endforeach
 endif
 
+# Check if CLANG (used for LLVM bitcode compilation) understands
+# typeof_unqual or a variant.  We use run_command with a test file
+# because clang is a program, not a meson compiler object, so
+# cc.compiles() cannot be used.
+if llvm.found()
+  clang_typeof_unqual_found = false
+  foreach kw : ['typeof_unqual', '__typeof_unqual__']
+    if not clang_typeof_unqual_found
+      r = run_command(clang, '-fsyntax-only', '-DKW=' + kw,
+        files('config/test_typeof_unqual.c'), check: false)
+      if r.returncode() == 0
+        message('CLANG supports ' + kw)
+        clang_typeof_unqual_found = true
+        cdata.set('HAVE_CLANG_TYPEOF_UNQUAL', 1)
+        if kw != 'typeof_unqual'
+          cdata.set('pg_clang_typeof_unqual', kw)
+        endif
+      else
+        message('CLANG does not support ' + kw)
+      endif
+    endif
+  endforeach
+endif
+
 
 # MSVC doesn't cope well with defining restrict to __restrict, the
 # spelling it understands, because it conflicts with
diff --git a/src/backend/jit/llvm/meson.build b/src/backend/jit/llvm/meson.build
index 7df8453ad6f..7270143771e 100644
--- a/src/backend/jit/llvm/meson.build
+++ b/src/backend/jit/llvm/meson.build
@@ -60,7 +60,7 @@ endif
 
 
 # XXX: Need to determine proper version of the function cflags for clang
-bitcode_cflags = ['-fno-strict-aliasing', '-fwrapv']
+bitcode_cflags = ['-DPG_COMPILING_BITCODE', '-fno-strict-aliasing', '-fwrapv']
 bitcode_cflags += get_option('c_args')
 bitcode_cflags += cppflags
 
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

Reply via email to