From a4001ba4fa6be03d81375f1a54b0a5aa9c6df97b Mon Sep 17 00:00:00 2001 From: Jeroen Vermeulen Date: Sat, 5 Oct 2024 21:24:00 +0200 Subject: [PATCH] Fix `assume()` chneck for clang C++17/C++20 build. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In clang 19, all of a sudden the compile-time feature check for `[[assume()]]` support started issuing a warning: it says that attribute is a "C++23 extension." And the maintainer-mode build treats warnings as wrrors, so... Kaboom. The problem is that in this mode, clang 19 does define the feature test macro for this attribute even in C++ 17, but when you actually _use_ the attribute, clang warns (at least with strict checking options) that it is not part of C++17 (or C++20, as the case may be). To get around that, I wrote a more substantial feature check and ran it at _configure_ time. This is where my work on systematising the feature check mechanism really pays off — a few years ago this would have been a fairly substantial change, with lots of opportunities to do it wrong. --- cmake/pqxx_cxx_feature_checks.cmake | 4 ++++ config-tests/PQXX_HAVE_ASSUME.cxx | 5 +++++ configitems | 1 + configure | 28 ++++++++++++++++++++++++++++ include/pqxx/config.h.in | 7 +++++-- include/pqxx/internal/header-pre.hxx | 9 +++------ pqxx_cxx_feature_checks.ac | 10 ++++++++++ 7 files changed, 56 insertions(+), 8 deletions(-) create mode 100644 config-tests/PQXX_HAVE_ASSUME.cxx diff --git a/cmake/pqxx_cxx_feature_checks.cmake b/cmake/pqxx_cxx_feature_checks.cmake index 2e305d1a4..baaea07a8 100644 --- a/cmake/pqxx_cxx_feature_checks.cmake +++ b/cmake/pqxx_cxx_feature_checks.cmake @@ -1,5 +1,9 @@ # Configuration for feature checks. Generated by generate_check_config.py. include(CheckCXXSourceCompiles) +try_compile( + PQXX_HAVE_ASSUME ${PROJECT_BINARY_DIR} + SOURCES ${PROJECT_SOURCE_DIR}/config-tests/PQXX_HAVE_ASSUME.cxx +) try_compile( PQXX_HAVE_CHARCONV_FLOAT ${PROJECT_BINARY_DIR} SOURCES ${PROJECT_SOURCE_DIR}/config-tests/PQXX_HAVE_CHARCONV_FLOAT.cxx diff --git a/config-tests/PQXX_HAVE_ASSUME.cxx b/config-tests/PQXX_HAVE_ASSUME.cxx new file mode 100644 index 000000000..41f5d4f02 --- /dev/null +++ b/config-tests/PQXX_HAVE_ASSUME.cxx @@ -0,0 +1,5 @@ +int main(int argc, char **argv) +{ + [[assume(argv != nullptr)]]; + return argc - 1; +} diff --git a/configitems b/configitems index 083d1692b..da97c35db 100644 --- a/configitems +++ b/configitems @@ -4,6 +4,7 @@ PACKAGE_NAME internal autotools PACKAGE_STRING internal autotools PACKAGE_TARNAME internal autotools PACKAGE_VERSION internal autotools +PQXX_HAVE_ASSUME public compiler PQXX_HAVE_CHARCONV_INT internal compiler PQXX_HAVE_CHARCONV_FLOAT internal compiler PQXX_HAVE_CMP public compiler diff --git a/configure b/configure index d0c60d819..891beb2b8 100755 --- a/configure +++ b/configure @@ -17223,6 +17223,34 @@ fi # End of gcc-specific part. # Configuration for feature checks. Generated by generate_check_config.py. +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking PQXX_HAVE_ASSUME" >&5 +printf %s "checking PQXX_HAVE_ASSUME... " >&6; } +PQXX_HAVE_ASSUME=yes +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +int main(int argc, char **argv) + +{ + + [[assume(argv != nullptr)]]; + + return argc - 1; + +} + + +_ACEOF +if ac_fn_cxx_try_compile "$LINENO" +then : + +printf "%s\n" "#define PQXX_HAVE_ASSUME 1" >>confdefs.h + +else $as_nop + PQXX_HAVE_ASSUME=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $PQXX_HAVE_ASSUME" >&5 +printf "%s\n" "$PQXX_HAVE_ASSUME" >&6; } { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking PQXX_HAVE_CHARCONV_FLOAT" >&5 printf %s "checking PQXX_HAVE_CHARCONV_FLOAT... " >&6; } PQXX_HAVE_CHARCONV_FLOAT=yes diff --git a/include/pqxx/config.h.in b/include/pqxx/config.h.in index 4e3f94608..22e12c162 100644 --- a/include/pqxx/config.h.in +++ b/include/pqxx/config.h.in @@ -6,7 +6,7 @@ /* Define to 1 if you have the header file. */ #undef HAVE_INTTYPES_H -/* Define to 1 if you have the `pq' library (-lpq). */ +/* Define to 1 if you have the 'pq' library (-lpq). */ #undef HAVE_LIBPQ /* Define to 1 if you have the header file. */ @@ -57,6 +57,9 @@ /* Define to the version of this package. */ #undef PACKAGE_VERSION +/* Define if this feature is available. */ +#undef PQXX_HAVE_ASSUME + /* Define if this feature is available. */ #undef PQXX_HAVE_CHARCONV_FLOAT @@ -114,7 +117,7 @@ /* Define if this feature is available. */ #undef PQXX_HAVE_YEAR_MONTH_DAY -/* Define to 1 if all of the C90 standard headers exist (not just the ones +/* Define to 1 if all of the C89 standard headers exist (not just the ones required in a freestanding environment). This macro is provided for backward compatibility; new code need not use it. */ #undef STDC_HEADERS diff --git a/include/pqxx/internal/header-pre.hxx b/include/pqxx/internal/header-pre.hxx index fdd301c3e..8417e2983 100644 --- a/include/pqxx/internal/header-pre.hxx +++ b/include/pqxx/internal/header-pre.hxx @@ -181,11 +181,8 @@ // C++23: Assume support. -// C++20: Assume __has_cpp_attribute is defined. -#if !defined(__has_cpp_attribute) -# define PQXX_ASSUME(condition) while (false) -#elif !__has_cpp_attribute(assume) -# define PQXX_ASSUME(condition) while (false) -#else +#if defined(PQXX_HAVE_ASSUME) # define PQXX_ASSUME(condition) [[assume(condition)]] +#else +# define PQXX_ASSUME(condition) while (false) #endif diff --git a/pqxx_cxx_feature_checks.ac b/pqxx_cxx_feature_checks.ac index 025ed182b..325608f29 100644 --- a/pqxx_cxx_feature_checks.ac +++ b/pqxx_cxx_feature_checks.ac @@ -1,4 +1,14 @@ # Configuration for feature checks. Generated by generate_check_config.py. +AC_MSG_CHECKING([PQXX_HAVE_ASSUME]) +PQXX_HAVE_ASSUME=yes +AC_COMPILE_IFELSE( + [read_test(PQXX_HAVE_ASSUME.cxx)], + AC_DEFINE( + [PQXX_HAVE_ASSUME], + 1, + [Define if this feature is available.]), + PQXX_HAVE_ASSUME=no) +AC_MSG_RESULT($PQXX_HAVE_ASSUME) AC_MSG_CHECKING([PQXX_HAVE_CHARCONV_FLOAT]) PQXX_HAVE_CHARCONV_FLOAT=yes AC_COMPILE_IFELSE(