Ok, now that we have seemingly stabilized the VS 2019 upgrade, here is
the next patch set to actually raise the compiler requirement to C11.
Viewed from very far away, this just adjusts the existing places that
say C99 and replaces them with a C11 analogue.
The details are a bit of a longer story.
configure.ac previously used AC_PROG_CC_C99 to activate C99. But there
is no AC_PROG_CC_C11 in Autoconf 2.69, because it's too old. Also,
post-2.69, the AC_PROG_CC_Cnn macros were deprecated and AC_PROG_CC
activates the last supported C mode.
So, at this point, we could "just" update the Autoconf version requirement.
But somehow I don't feel like doing that, as it's just another
non-trivial project to negotiate. Instead, I just hand-coded some test
for C11 using some inspiration from later Autoconf versions. But
instead of writing an elaborate test program that exercises many
different features, I kept it simple and just check __STDC_VERSION__,
which should be good enough in practice.
(If someone later wanted to update the Autoconf version, they could just
delete that code again.)
In meson.build, there is an existing hand-coded C99 test that I update
to C11, but again just checking for __STDC_VERSION__.
I also moved the test a bit earlier in meson.build, as a separate patch,
because between the place where the compiler is first set up and the
place where we detected the C99 options, if any, there were already some
tests run that use the compiler. I don't think this was a big problem
in practice, but it seems a bit incorrect, so it makes sense to correct it.
Note, we don't use the "official" way to set the C standard in Meson
using the c_std project option, because that is IMO impossible to use
correctly (see <https://github.com/mesonbuild/meson/issues/14717>).
(Well, that is my reason now. I don't know what the reason was
previously.) The disadvantage is that meson will complain like
meson.build:3013: WARNING: Consider using the built-in option for
language standard version instead of using "/std:c11".
But you will get warnings from meson with MSVC anyway, so, uh, another
one will not make a significant difference. (Also, this issue exists
with the existing C99 detection code as well, except that in practice
you don't need an option, so the warning does not appear.)
Note that gcc and clang switched to C11 by default a long time ago
(gcc-5 and clang-3.6), so for most users all these tests won't need to
do anything. If you want to test it, you could simulate an older
default like
./configure CC='gcc -std=c99'
and then the test should decide that it needs to add another option to
override the C mode.
From ee5fd55153d5f407b1062e2ce5ff741a7d503c44 Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <pe...@eisentraut.org>
Date: Fri, 18 Jul 2025 13:26:40 +0300
Subject: [PATCH v1 1/2] meson: Move C99 test earlier
That way, if any command-line options are needed, subsequent tests
will also use them.
---
meson.build | 85 ++++++++++++++++++++++++++---------------------------
1 file changed, 42 insertions(+), 43 deletions(-)
diff --git a/meson.build b/meson.build
index 5365aaf95e6..0b9d7224cd6 100644
--- a/meson.build
+++ b/meson.build
@@ -550,6 +550,48 @@ dir_doc_extension = dir_doc / 'extension'
# used, they need to be added to test_c_args as well.
###############################################################
+# Do we need -std=c99 to compile C99 code? We don't want to add -std=c99
+# unnecessarily, because we optionally rely on newer features.
+c99_test = '''
+#include <stdbool.h>
+#include <complex.h>
+#include <tgmath.h>
+#include <inttypes.h>
+
+struct named_init_test {
+ int a;
+ int b;
+};
+
+extern void structfunc(struct named_init_test);
+
+int main(int argc, char **argv)
+{
+ struct named_init_test nit = {
+ .a = 3,
+ .b = 5,
+ };
+
+ for (int loop_var = 0; loop_var < 3; loop_var++)
+ {
+ nit.a += nit.b;
+ }
+
+ structfunc((struct named_init_test){1, 0});
+
+ return nit.a != 0;
+}
+'''
+
+if not cc.compiles(c99_test, name: 'c99')
+ if cc.compiles(c99_test, name: 'c99 with -std=c99', args: ['-std=c99'])
+ cflags += '-std=c99'
+ else
+ error('C compiler does not support C99')
+ endif
+endif
+
+
postgres_inc = [include_directories(postgres_inc_d)]
test_lib_d = postgres_lib_d
test_c_args = cppflags + cflags
@@ -1704,49 +1746,6 @@ endif
# Compiler tests
###############################################################
-# Do we need -std=c99 to compile C99 code? We don't want to add -std=c99
-# unnecessarily, because we optionally rely on newer features.
-c99_test = '''
-#include <stdbool.h>
-#include <complex.h>
-#include <tgmath.h>
-#include <inttypes.h>
-
-struct named_init_test {
- int a;
- int b;
-};
-
-extern void structfunc(struct named_init_test);
-
-int main(int argc, char **argv)
-{
- struct named_init_test nit = {
- .a = 3,
- .b = 5,
- };
-
- for (int loop_var = 0; loop_var < 3; loop_var++)
- {
- nit.a += nit.b;
- }
-
- structfunc((struct named_init_test){1, 0});
-
- return nit.a != 0;
-}
-'''
-
-if not cc.compiles(c99_test, name: 'c99', args: test_c_args)
- if cc.compiles(c99_test, name: 'c99 with -std=c99',
- args: test_c_args + ['-std=c99'])
- test_c_args += '-std=c99'
- cflags += '-std=c99'
- else
- error('C compiler does not support C99')
- endif
-endif
-
if host_machine.endian() == 'big'
cdata.set('WORDS_BIGENDIAN', 1)
endif
base-commit: 5022ff250eeba2367fb4e74fed8ee65bcddb6c99
--
2.50.0
From 316cf64618bda13706fbc513e76938b4a8946239 Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <pe...@eisentraut.org>
Date: Fri, 18 Jul 2025 13:53:52 +0300
Subject: [PATCH v1 2/2] Raise C requirement to C11
This changes configure and meson.build to require at least C11,
instead of the previous C99. The installation documentation is
updated accordingly.
configure.ac previously used AC_PROG_CC_C99 to activate C99. But
there is no AC_PROG_CC_C11 in Autoconf 2.69, because it's too
old. (Also, post-2.69, the AC_PROG_CC_Cnn macros were deprecated and
AC_PROG_CC activates the last supported C mode.) We could update the
required Autoconf version, but that might be a separate project that
no one wants to undertake at the moment. Instead, we open-code the
test for C11 using some inspiration from later Autoconf versions. But
instead of writing an elaborate test program, we keep it simple and
just check __STDC_VERSION__, which should be good enough in practice.
In meson.build, we update the existing C99 test to C11, but again we
just check for __STDC_VERSION__.
This also removes the separate option for the conforming preprocessor
on MSVC, added by commit 8fd9bb1d965, since that is activated
automatically in C11 mode.
Note, we don't use the "official" way to set the C standard in Meson
using the c_std project option, because that is impossible to use
correctly (see <https://github.com/mesonbuild/meson/issues/14717>).
---
configure | 204 +++++----------------------------
configure.ac | 29 ++++-
doc/src/sgml/installation.sgml | 7 +-
doc/src/sgml/sources.sgml | 12 +-
meson.build | 59 ++++------
5 files changed, 83 insertions(+), 228 deletions(-)
diff --git a/configure b/configure
index 6d7c22e153f..3dca5fe340a 100755
--- a/configure
+++ b/configure
@@ -4475,190 +4475,49 @@ ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext
>&5'
ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext
$LIBS >&5'
ac_compiler_gnu=$ac_cv_c_compiler_gnu
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept
ISO C99" >&5
-$as_echo_n "checking for $CC option to accept ISO C99... " >&6; }
-if ${ac_cv_prog_cc_c99+:} false; then :
+
+# Detect option needed for C11
+# loosely modeled after code in later Autoconf versions
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO
C11" >&5
+$as_echo_n "checking for $CC option to accept ISO C11... " >&6; }
+
+if ${pgac_cv_prog_cc_c11+:} false; then :
$as_echo_n "(cached) " >&6
else
- ac_cv_prog_cc_c99=no
-ac_save_CC=$CC
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+ pgac_cv_prog_cc_c11=no
+pgac_save_CC=$CC
+for pgac_arg in '' '-std=gnu11' '-std=c11'; do
+ CC="$pgac_save_CC $pgac_arg"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
-#include <stdarg.h>
-#include <stdbool.h>
-#include <stdlib.h>
-#include <wchar.h>
-#include <stdio.h>
-
-// Check varargs macros. These examples are taken from C99 6.10.3.5.
-#define debug(...) fprintf (stderr, __VA_ARGS__)
-#define showlist(...) puts (#__VA_ARGS__)
-#define report(test,...) ((test) ? puts (#test) : printf (__VA_ARGS__))
-static void
-test_varargs_macros (void)
-{
- int x = 1234;
- int y = 5678;
- debug ("Flag");
- debug ("X = %d\n", x);
- showlist (The first, second, and third items.);
- report (x>y, "x is %d but y is %d", x, y);
-}
-
-// Check long long types.
-#define BIG64 18446744073709551615ull
-#define BIG32 4294967295ul
-#define BIG_OK (BIG64 / BIG32 == 4294967297ull && BIG64 % BIG32 == 0)
-#if !BIG_OK
- your preprocessor is broken;
-#endif
-#if BIG_OK
-#else
- your preprocessor is broken;
+#if !defined __STDC_VERSION__ || __STDC_VERSION__ < 201112L
+# error "Compiler does not advertise C11 conformance"
#endif
-static long long int bignum = -9223372036854775807LL;
-static unsigned long long int ubignum = BIG64;
-
-struct incomplete_array
-{
- int datasize;
- double data[];
-};
-
-struct named_init {
- int number;
- const wchar_t *name;
- double average;
-};
-
-typedef const char *ccp;
-
-static inline int
-test_restrict (ccp restrict text)
-{
- // See if C++-style comments work.
- // Iterate through items via the restricted pointer.
- // Also check for declarations in for loops.
- for (unsigned int i = 0; *(text+i) != '\0'; ++i)
- continue;
- return 0;
-}
-
-// Check varargs and va_copy.
-static void
-test_varargs (const char *format, ...)
-{
- va_list args;
- va_start (args, format);
- va_list args_copy;
- va_copy (args_copy, args);
-
- const char *str;
- int number;
- float fnumber;
-
- while (*format)
- {
- switch (*format++)
- {
- case 's': // string
- str = va_arg (args_copy, const char *);
- break;
- case 'd': // int
- number = va_arg (args_copy, int);
- break;
- case 'f': // float
- fnumber = va_arg (args_copy, double);
- break;
- default:
- break;
- }
- }
- va_end (args_copy);
- va_end (args);
-}
-
-int
-main ()
-{
-
- // Check bool.
- _Bool success = false;
-
- // Check restrict.
- if (test_restrict ("String literal") == 0)
- success = true;
- char *restrict newvar = "Another string";
-
- // Check varargs.
- test_varargs ("s, d' f .", "string", 65, 34.234);
- test_varargs_macros ();
-
- // Check flexible array members.
- struct incomplete_array *ia =
- malloc (sizeof (struct incomplete_array) + (sizeof (double) * 10));
- ia->datasize = 10;
- for (int i = 0; i < ia->datasize; ++i)
- ia->data[i] = i * 1.234;
-
- // Check named initializers.
- struct named_init ni = {
- .number = 34,
- .name = L"Test wide string",
- .average = 543.34343,
- };
-
- ni.number = 58;
-
- int dynamic_array[ni.number];
- dynamic_array[ni.number - 1] = 543;
-
- // work around unused variable warnings
- return (!success || bignum == 0LL || ubignum == 0uLL || newvar[0] == 'x'
- || dynamic_array[ni.number - 1] != 543);
-
- ;
- return 0;
-}
_ACEOF
-for ac_arg in '' -std=gnu99 -std=c99 -c99 -AC99 -D_STDC_C99= -qlanglvl=extc99
-do
- CC="$ac_save_CC $ac_arg"
- if ac_fn_c_try_compile "$LINENO"; then :
- ac_cv_prog_cc_c99=$ac_arg
+if ac_fn_c_try_compile "$LINENO"; then :
+ pgac_cv_prog_cc_c11=$pgac_arg
fi
-rm -f core conftest.err conftest.$ac_objext
- test "x$ac_cv_prog_cc_c99" != "xno" && break
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ test x"$pgac_cv_prog_cc_c11" != x"no" && break
done
-rm -f conftest.$ac_ext
-CC=$ac_save_CC
-
-fi
-# AC_CACHE_VAL
-case "x$ac_cv_prog_cc_c99" in
- x)
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
-$as_echo "none needed" >&6; } ;;
- xno)
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
-$as_echo "unsupported" >&6; } ;;
- *)
- CC="$CC $ac_cv_prog_cc_c99"
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c99" >&5
-$as_echo "$ac_cv_prog_cc_c99" >&6; } ;;
-esac
-if test "x$ac_cv_prog_cc_c99" != xno; then :
-
+CC=$pgac_save_CC
fi
-
-# Error out if the compiler does not support C99, as the codebase
-# relies on that.
-if test "$ac_cv_prog_cc_c99" = no; then
- as_fn_error $? "C compiler \"$CC\" does not support C99" "$LINENO" 5
+if test x"$pgac_cv_prog_cc_c11" = x"no"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
+$as_echo "unsupported" >&6; }
+ as_fn_error $? "C compiler \"$CC\" does not support C11" "$LINENO" 5
+elif test x"$pgac_cv_prog_cc_c11" = x""; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
+$as_echo "none needed" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $pgac_cv_prog_cc_c11" >&5
+$as_echo "$pgac_cv_prog_cc_c11" >&6; }
+ CC="$CC $pgac_cv_prog_cc_c11"
fi
+
ac_ext=cpp
ac_cpp='$CXXCPP $CPPFLAGS'
ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
@@ -4920,7 +4779,6 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu
# Check if it's Intel's compiler, which (usually) pretends to be gcc,
# but has idiosyncrasies of its own. We assume icc will define
# __INTEL_COMPILER regardless of CFLAGS.
-
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
diff --git a/configure.ac b/configure.ac
index c2877e36935..9d84a410916 100644
--- a/configure.ac
+++ b/configure.ac
@@ -364,14 +364,33 @@ pgac_cc_list="gcc cc"
pgac_cxx_list="g++ c++"
AC_PROG_CC([$pgac_cc_list])
-AC_PROG_CC_C99()
-# Error out if the compiler does not support C99, as the codebase
-# relies on that.
-if test "$ac_cv_prog_cc_c99" = no; then
- AC_MSG_ERROR([C compiler "$CC" does not support C99])
+# Detect option needed for C11
+# loosely modeled after code in later Autoconf versions
+AC_MSG_CHECKING([for $CC option to accept ISO C11])
+AC_CACHE_VAL([pgac_cv_prog_cc_c11],
+[pgac_cv_prog_cc_c11=no
+pgac_save_CC=$CC
+for pgac_arg in '' '-std=gnu11' '-std=c11'; do
+ CC="$pgac_save_CC $pgac_arg"
+ AC_COMPILE_IFELSE([AC_LANG_SOURCE([[#if !defined __STDC_VERSION__ ||
__STDC_VERSION__ < 201112L
+# error "Compiler does not advertise C11 conformance"
+#endif]])], [[pgac_cv_prog_cc_c11=$pgac_arg]])
+ test x"$pgac_cv_prog_cc_c11" != x"no" && break
+done
+CC=$pgac_save_CC])
+
+if test x"$pgac_cv_prog_cc_c11" = x"no"; then
+ AC_MSG_RESULT([unsupported])
+ AC_MSG_ERROR([C compiler "$CC" does not support C11])
+elif test x"$pgac_cv_prog_cc_c11" = x""; then
+ AC_MSG_RESULT([none needed])
+else
+ AC_MSG_RESULT([$pgac_cv_prog_cc_c11])
+ CC="$CC $pgac_cv_prog_cc_c11"
fi
+
AC_PROG_CXX([$pgac_cxx_list])
# Check if it's Intel's compiler, which (usually) pretends to be gcc,
diff --git a/doc/src/sgml/installation.sgml b/doc/src/sgml/installation.sgml
index 8e5da767c48..a4ad80a6782 100644
--- a/doc/src/sgml/installation.sgml
+++ b/doc/src/sgml/installation.sgml
@@ -71,10 +71,9 @@ <title>Requirements</title>
<listitem>
<para>
- You need an <acronym>ISO</acronym>/<acronym>ANSI</acronym> C compiler
(at least
- C99-compliant). Recent
- versions of <productname>GCC</productname> are recommended, but
- <productname>PostgreSQL</productname> is known to build using a wide
variety
+ You need a C compiler that supports at least C11. Recent versions of
+ <productname>GCC</productname> are recommended, but
+ <productname>PostgreSQL</productname> is known to build using a variety
of compilers from different vendors.
</para>
</listitem>
diff --git a/doc/src/sgml/sources.sgml b/doc/src/sgml/sources.sgml
index fa68d4d024a..261f19b3534 100644
--- a/doc/src/sgml/sources.sgml
+++ b/doc/src/sgml/sources.sgml
@@ -907,12 +907,12 @@ <title>Miscellaneous Coding Conventions</title>
<title>C Standard</title>
<para>
Code in <productname>PostgreSQL</productname> should only rely on language
- features available in the C99 standard. That means a conforming
- C99 compiler has to be able to compile postgres, at least aside
+ features available in the C11 standard. That means a conforming
+ C11 compiler has to be able to compile postgres, at least aside
from a few platform dependent pieces.
</para>
<para>
- A few features included in the C99 standard are, at this time, not
+ A few features included in the C11 standard are, at this time, not
permitted to be used in core <productname>PostgreSQL</productname>
code. This currently includes variable length arrays, intermingled
declarations and code, <literal>//</literal> comments, universal
@@ -924,13 +924,11 @@ <title>C Standard</title>
features can be used, if a fallback is provided.
</para>
<para>
- For example <literal>_Static_assert()</literal> and
+ For example <literal>typeof()</literal> and
<literal>__builtin_constant_p</literal> are currently used, even though
they are from newer revisions of the C standard and a
<productname>GCC</productname> extension respectively. If not available
- we respectively fall back to using a C99 compatible replacement that
- performs the same checks, but emits rather cryptic messages and do not
- use <literal>__builtin_constant_p</literal>.
+ we do not use them.
</para>
</simplesect>
diff --git a/meson.build b/meson.build
index 0b9d7224cd6..5713a366464 100644
--- a/meson.build
+++ b/meson.build
@@ -280,10 +280,6 @@ elif host_system == 'windows'
# define before including <time.h> for getting localtime_r() etc. on MinGW
cppflags += '-D_POSIX_C_SOURCE'
endif
- if cc.get_id() == 'msvc'
- # required for VA_ARGS_NARGS() in c.h; requires VS 2019
- cppflags += '/Zc:preprocessor'
- endif
export_file_format = 'win'
export_file_suffix = 'def'
@@ -550,44 +546,29 @@ dir_doc_extension = dir_doc / 'extension'
# used, they need to be added to test_c_args as well.
###############################################################
-# Do we need -std=c99 to compile C99 code? We don't want to add -std=c99
-# unnecessarily, because we optionally rely on newer features.
-c99_test = '''
-#include <stdbool.h>
-#include <complex.h>
-#include <tgmath.h>
-#include <inttypes.h>
-
-struct named_init_test {
- int a;
- int b;
-};
-
-extern void structfunc(struct named_init_test);
-
-int main(int argc, char **argv)
-{
- struct named_init_test nit = {
- .a = 3,
- .b = 5,
- };
-
- for (int loop_var = 0; loop_var < 3; loop_var++)
- {
- nit.a += nit.b;
- }
-
- structfunc((struct named_init_test){1, 0});
-
- return nit.a != 0;
-}
+# Do we need an option to enable C11?
+c11_test = '''
+#if !defined __STDC_VERSION__ || __STDC_VERSION__ < 201112L
+# error "Compiler does not advertise C11 conformance"
+#endif
'''
-if not cc.compiles(c99_test, name: 'c99')
- if cc.compiles(c99_test, name: 'c99 with -std=c99', args: ['-std=c99'])
- cflags += '-std=c99'
+if not cc.compiles(c11_test, name: 'C11')
+ c11_ok = false
+ if cc.get_id() == 'msvc'
+ c11_test_args = ['/std:c11']
else
- error('C compiler does not support C99')
+ c11_test_args = ['-std=gnu11', '-std=c11']
+ endif
+ foreach arg : c11_test_args
+ if cc.compiles(c11_test, name: 'C11 with @0@'.format(arg), args: [arg])
+ c11_ok = true
+ cflags += arg
+ break
+ endif
+ endforeach
+ if not c11_ok
+ error('C compiler does not support C11')
endif
endif
--
2.50.0