From df6d9e8d1bb955d9cffe3095cc27d4209de1ce33 Mon Sep 17 00:00:00 2001
From: Jelte Fennema-Nio <postgres@jeltef.nl>
Date: Sun, 29 Mar 2026 13:01:37 +0200
Subject: [PATCH v12 3/4] Add support for C++ extensions with MSVC

To build C++ extensions we need support for designated initializers,
because PG_MODULE_MAGIC uses it. Designated initializers only got
standardized in C++20. In GCC and Clang they also work when using
earlier C++ versions, but MSVC really only supports them when its
configured to be in C++20 mode or higher.

This extends C++11 feature test to also check for designated initializer
support.

When passing both -pedantic and -Werror even Clang and GCC can fail this
new feature test if they're old enough that they don't compile with
C++20 by default. So this also changes meson and configure to try C++20
if using C++11 didn't work. Before this patch this such a setup would
pass the C++11 check but would then fail to compile test_cplusplusext.
---
 configure.ac                                  | 13 ++++++----
 doc/src/sgml/xfunc.sgml                       |  5 ++++
 meson.build                                   | 26 +++++++++++--------
 .../modules/test_cplusplusext/meson.build     |  5 ----
 4 files changed, 28 insertions(+), 21 deletions(-)

diff --git a/configure.ac b/configure.ac
index 2baac5e9da7..e4570a805c6 100644
--- a/configure.ac
+++ b/configure.ac
@@ -398,17 +398,20 @@ AC_SUBST(have_cxx)
 
 if test "$have_cxx" = yes; then
 
-# Detect option needed for C++11
-AC_MSG_CHECKING([for $CXX option to accept ISO C++11])
+# Detect option needed for C++11 with designated initializers. We need
+# designated initializers because we use them in many of our headers, including
+# in the PG_MODULE_MAGIC definition.
+AC_MSG_CHECKING([for $CXX option to accept ISO C++11 with designated initializers])
 AC_CACHE_VAL([pgac_cv_prog_cxx_cxx11],
 [pgac_cv_prog_cxx_cxx11=no
 pgac_save_CXX=$CXX
 AC_LANG_PUSH([C++])
-for pgac_arg in '' '-std=gnu++11' '-std=c++11'; do
+for pgac_arg in '' '-std=gnu++11' '-std=c++11' '-std=gnu++20' '-std=c++20'; do
   CXX="$pgac_save_CXX $pgac_arg"
   AC_COMPILE_IFELSE([AC_LANG_SOURCE([[#if !defined __cplusplus || __cplusplus < 201103L
 # error "Compiler does not advertise C++11 conformance"
-#endif]])], [[pgac_cv_prog_cxx_cxx11=$pgac_arg]])
+#endif
+struct S { int x; } s = { .x = 1 };]])], [[pgac_cv_prog_cxx_cxx11=$pgac_arg]])
   test x"$pgac_cv_prog_cxx_cxx11" != x"no" && break
 done
 AC_LANG_POP([C++])
@@ -416,7 +419,7 @@ CXX=$pgac_save_CXX])
 
 if test x"$pgac_cv_prog_cxx_cxx11" = x"no"; then
   AC_MSG_RESULT([unsupported])
-  AC_MSG_WARN([C++ compiler "$CXX" does not support C++11])
+  AC_MSG_WARN([C++ compiler "$CXX" does not support C++11 with designated initializers])
   have_cxx=no
 elif test x"$pgac_cv_prog_cxx_cxx11" = x""; then
   AC_MSG_RESULT([none needed])
diff --git a/doc/src/sgml/xfunc.sgml b/doc/src/sgml/xfunc.sgml
index 70e815b8a2c..6895fe483c1 100644
--- a/doc/src/sgml/xfunc.sgml
+++ b/doc/src/sgml/xfunc.sgml
@@ -4026,6 +4026,11 @@ extern PgStat_Kind pgstat_register_kind(PgStat_Kind kind,
 
      <itemizedlist>
       <listitem>
+       <para>
+         You need a C++ compiler that supports C++11 and designated
+         initializers (GCC and Clang support this in C++11 mode, but MSVC only
+         supports it in C++20 mode).
+       </para>
        <para>
          All functions accessed by the backend must present a C interface
          to the backend;  these C functions can then call C++ functions.
diff --git a/meson.build b/meson.build
index 64a5bb888d6..bcad5f4fc01 100644
--- a/meson.build
+++ b/meson.build
@@ -647,29 +647,33 @@ if not cc.compiles(c11_test, name: 'C11')
 endif
 
 
-# Do we need an option to enable C++11?
-cxx11_test = '''
+# Do we need an option to enable C++11 and/or designated initializers? We need
+# designated initiliazers because we use them in many of our headers, including
+# in the PG_MODULE_MAGIC definition. Clang and gcc support designated
+# initializers in C++11 mode, but MSVC only supports them in C++20 mode.
+cxx_features_test = '''
 #if !defined __cplusplus || __cplusplus < 201103L
 # error "Compiler does not advertise C++11 conformance"
 #endif
+struct S { int x; } s = { .x = 1 };
 '''
 
-if have_cxx and not cxx.compiles(cxx11_test, name: 'C++11')
-  cxx11_ok = false
+if have_cxx and not cxx.compiles(cxx_features_test, name: 'C++11 with designated initializers')
+  cxx_features_ok = false
   if cxx.get_id() == 'msvc'
-    cxx11_test_args = ['/std:c++14']  # oldest version supported
+    cxx_features_test_args = ['/std:c++20']
   else
-    cxx11_test_args = ['-std=gnu++11', '-std=c++11']
+    cxx_features_test_args = ['-std=gnu++11', '-std=c++11', '-std=gnu++20', 'std=c++20']
   endif
-  foreach arg : cxx11_test_args
-    if cxx.compiles(cxx11_test, name: 'C++11 with @0@'.format(arg), args: [arg])
-      cxx11_ok = true
+  foreach arg : cxx_features_test_args
+    if cxx.compiles(cxx_features_test, name: 'C++11 with designated initializers with @0@'.format(arg), args: [arg])
+      cxx_features_ok = true
       cxxflags += arg
       break
     endif
   endforeach
-  if not cxx11_ok
-    error('C++ compiler does not support C++11')
+  if not cxx_features_ok
+    error('C++ compiler does not support C++11 with designated initializers')
   endif
 endif
 
diff --git a/src/test/modules/test_cplusplusext/meson.build b/src/test/modules/test_cplusplusext/meson.build
index d13210ca593..24a9cf16dca 100644
--- a/src/test/modules/test_cplusplusext/meson.build
+++ b/src/test/modules/test_cplusplusext/meson.build
@@ -4,11 +4,6 @@ if not have_cxx
   subdir_done()
 endif
 
-# Currently not supported, to be fixed.
-if cc.get_id() == 'msvc'
-  subdir_done()
-endif
-
 test_cplusplusext_sources = files(
   'test_cplusplusext.cpp',
 )
-- 
2.53.0

