1 # ===========================================================================
2 # https://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx.html
3 # ===========================================================================
7 # AX_CXX_COMPILE_STDCXX(VERSION, [ext|noext], [mandatory|optional])
11 # Check for baseline language coverage in the compiler for the specified
12 # version of the C++ standard. If necessary, add switches to CXX and
13 # CXXCPP to enable support. VERSION may be '11', '14', '17', '20', or
14 # '23' for the respective C++ standard version.
16 # The second argument, if specified, indicates whether you insist on an
17 # extended mode (e.g. -std=gnu++11) or a strict conformance mode (e.g.
18 # -std=c++11). If neither is specified, you get whatever works, with
19 # preference for no added switch, and then for an extended mode.
21 # The third argument, if specified 'mandatory' or if left unspecified,
22 # indicates that baseline support for the specified C++ standard is
23 # required and that the macro should error out if no mode with that
24 # support is found. If specified 'optional', then configuration proceeds
25 # regardless, after defining HAVE_CXX${VERSION} if and only if a
26 # supporting mode is found.
30 # Copyright (c) 2008 Benjamin Kosnik <bkoz@redhat.com>
31 # Copyright (c) 2012 Zack Weinberg <zackw@panix.com>
32 # Copyright (c) 2013 Roy Stogner <roystgnr@ices.utexas.edu>
33 # Copyright (c) 2014, 2015 Google Inc.; contributed by Alexey Sokolov <sokolov@google.com>
34 # Copyright (c) 2015 Paul Norman <penorman@mac.com>
35 # Copyright (c) 2015 Moritz Klammler <moritz@klammler.eu>
36 # Copyright (c) 2016, 2018 Krzesimir Nowak <qdlacz@gmail.com>
37 # Copyright (c) 2019 Enji Cooper <yaneurabeya@gmail.com>
38 # Copyright (c) 2020 Jason Merrill <jason@redhat.com>
39 # Copyright (c) 2021 Jörn Heusipp <osmanx@problemloesungsmaschine.de>
40 # Copyright (c) 2015, 2022, 2023, 2024 Olly Betts
42 # Copying and distribution of this file, with or without modification, are
43 # permitted in any medium without royalty provided the copyright notice
44 # and this notice are preserved. This file is offered as-is, without any
49 dnl This macro is based on the code from the AX_CXX_COMPILE_STDCXX_11 macro
50 dnl (serial version number 13).
52 AC_DEFUN([AX_CXX_COMPILE_STDCXX], [dnl
53 m4_if([$1], [11], [ax_cxx_compile_alternatives="11 0x"],
54 [$1], [14], [ax_cxx_compile_alternatives="14 1y"],
55 [$1], [17], [ax_cxx_compile_alternatives="17 1z"],
56 [$1], [20], [ax_cxx_compile_alternatives="20"],
57 [$1], [23], [ax_cxx_compile_alternatives="23"],
58 [m4_fatal([invalid first argument `$1' to AX_CXX_COMPILE_STDCXX])])dnl
62 [m4_fatal([invalid second argument `$2' to AX_CXX_COMPILE_STDCXX])])dnl
63 m4_if([$3], [], [ax_cxx_compile_cxx$1_required=true],
64 [$3], [mandatory], [ax_cxx_compile_cxx$1_required=true],
65 [$3], [optional], [ax_cxx_compile_cxx$1_required=false],
66 [m4_fatal([invalid third argument `$3' to AX_CXX_COMPILE_STDCXX])])
67 AC_LANG_PUSH([C++])dnl
71 AC_CACHE_CHECK(whether $CXX supports C++$1 features by default,
72 ax_cv_cxx_compile_cxx$1,
73 [AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])],
74 [ax_cv_cxx_compile_cxx$1=yes],
75 [ax_cv_cxx_compile_cxx$1=no])])
76 if test x$ax_cv_cxx_compile_cxx$1 = xyes; then
80 m4_if([$2], [noext], [], [dnl
81 if test x$ac_success = xno; then
82 for alternative in ${ax_cxx_compile_alternatives}; do
83 switch="-std=gnu++${alternative}"
84 cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch])
85 AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch,
89 AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])],
93 if eval test x\$$cachevar = xyes; then
95 if test -n "$CXXCPP" ; then
96 CXXCPP="$CXXCPP $switch"
104 m4_if([$2], [ext], [], [dnl
105 if test x$ac_success = xno; then
106 dnl HP's aCC needs +std=c++11 according to:
107 dnl http://h21007.www2.hp.com/portal/download/files/unprot/aCxx/PDF_Release_Notes/769149-001.pdf
108 dnl Cray's crayCC needs "-h std=c++11"
109 dnl MSVC needs -std:c++NN for C++17 and later (default is C++14)
110 for alternative in ${ax_cxx_compile_alternatives}; do
111 for switch in -std=c++${alternative} +std=c++${alternative} "-h std=c++${alternative}" MSVC; do
112 if test x"$switch" = xMSVC; then
113 dnl AS_TR_SH maps both `:` and `=` to `_` so -std:c++17 would collide
114 dnl with -std=c++17. We suffix the cache variable name with _MSVC to
116 switch=-std:c++${alternative}
117 cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_${switch}_MSVC])
119 cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch])
121 AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch,
125 AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])],
126 [eval $cachevar=yes],
129 if eval test x\$$cachevar = xyes; then
131 if test -n "$CXXCPP" ; then
132 CXXCPP="$CXXCPP $switch"
138 if test x$ac_success = xyes; then
144 if test x$ax_cxx_compile_cxx$1_required = xtrue; then
145 if test x$ac_success = xno; then
146 AC_MSG_ERROR([*** A compiler with support for C++$1 language features is required.])
149 if test x$ac_success = xno; then
151 AC_MSG_NOTICE([No compiler with C++$1 support was found])
154 AC_DEFINE(HAVE_CXX$1,1,
155 [define if the compiler supports basic C++$1 syntax])
161 dnl Test body for checking C++11 support
163 m4_define([_AX_CXX_COMPILE_STDCXX_testbody_11],
164 _AX_CXX_COMPILE_STDCXX_testbody_new_in_11
167 dnl Test body for checking C++14 support
169 m4_define([_AX_CXX_COMPILE_STDCXX_testbody_14],
170 _AX_CXX_COMPILE_STDCXX_testbody_new_in_11
171 _AX_CXX_COMPILE_STDCXX_testbody_new_in_14
174 dnl Test body for checking C++17 support
176 m4_define([_AX_CXX_COMPILE_STDCXX_testbody_17],
177 _AX_CXX_COMPILE_STDCXX_testbody_new_in_11
178 _AX_CXX_COMPILE_STDCXX_testbody_new_in_14
179 _AX_CXX_COMPILE_STDCXX_testbody_new_in_17
182 dnl Test body for checking C++20 support
184 m4_define([_AX_CXX_COMPILE_STDCXX_testbody_20],
185 _AX_CXX_COMPILE_STDCXX_testbody_new_in_11
186 _AX_CXX_COMPILE_STDCXX_testbody_new_in_14
187 _AX_CXX_COMPILE_STDCXX_testbody_new_in_17
188 _AX_CXX_COMPILE_STDCXX_testbody_new_in_20
191 dnl Test body for checking C++23 support
193 m4_define([_AX_CXX_COMPILE_STDCXX_testbody_23],
194 _AX_CXX_COMPILE_STDCXX_testbody_new_in_11
195 _AX_CXX_COMPILE_STDCXX_testbody_new_in_14
196 _AX_CXX_COMPILE_STDCXX_testbody_new_in_17
197 _AX_CXX_COMPILE_STDCXX_testbody_new_in_20
198 _AX_CXX_COMPILE_STDCXX_testbody_new_in_23
202 dnl Tests for new features in C++11
204 m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_11], [[
206 // If the compiler admits that it is not ready for C++11, why torture it?
207 // Hopefully, this will speed up the test.
211 #error "This is not a C++ compiler"
213 // MSVC always sets __cplusplus to 199711L in older versions; newer versions
214 // only set it correctly if /Zc:__cplusplus is specified as well as a
215 // /std:c++NN switch:
217 // https://devblogs.microsoft.com/cppblog/msvc-now-correctly-reports-__cplusplus/
219 // The value __cplusplus ought to have is available in _MSVC_LANG since
220 // Visual Studio 2015 Update 3:
222 // https://learn.microsoft.com/en-us/cpp/preprocessor/predefined-macros
224 // This was also the first MSVC version to support C++14 so we can't use the
225 // value of either __cplusplus or _MSVC_LANG to quickly rule out MSVC having
226 // C++11 or C++14 support, but we can check _MSVC_LANG for C++17 and later.
227 #elif __cplusplus < 201103L && !defined _MSC_VER
229 #error "This is not a C++11 compiler"
236 namespace test_static_assert
239 template <typename T>
242 static_assert(sizeof(int) <= sizeof(T), "not big enough");
247 namespace test_final_override
256 struct Derived : public Base
258 virtual ~Derived() override {}
259 virtual void f() override {}
264 namespace test_double_right_angle_brackets
267 template < typename T >
270 typedef check<void> single_type;
271 typedef check<check<void>> double_type;
272 typedef check<check<check<void>>> triple_type;
273 typedef check<check<check<check<void>>>> quadruple_type;
277 namespace test_decltype
290 namespace test_type_deduction
293 template < typename T1, typename T2 >
296 static const bool value = false;
299 template < typename T >
302 static const bool value = true;
305 template < typename T1, typename T2 >
307 add(T1 a1, T2 a2) -> decltype(a1 + a2)
313 test(const int c, volatile int v)
315 static_assert(is_same<int, decltype(0)>::value == true, "");
316 static_assert(is_same<int, decltype(c)>::value == false, "");
317 static_assert(is_same<int, decltype(v)>::value == false, "");
320 auto sumi = ac + av + 'x';
321 auto sumf = ac + av + 1.0;
322 static_assert(is_same<int, decltype(ac)>::value == true, "");
323 static_assert(is_same<int, decltype(av)>::value == true, "");
324 static_assert(is_same<int, decltype(sumi)>::value == true, "");
325 static_assert(is_same<int, decltype(sumf)>::value == false, "");
326 static_assert(is_same<int, decltype(add(c, v))>::value == true, "");
327 return (sumf > 0.0) ? sumi : add(c, v);
332 namespace test_noexcept
335 int f() { return 0; }
336 int g() noexcept { return 0; }
338 static_assert(noexcept(f()) == false, "");
339 static_assert(noexcept(g()) == true, "");
343 namespace test_constexpr
346 template < typename CharT >
347 unsigned long constexpr
348 strlen_c_r(const CharT *const s, const unsigned long acc) noexcept
350 return *s ? strlen_c_r(s + 1, acc + 1) : acc;
353 template < typename CharT >
354 unsigned long constexpr
355 strlen_c(const CharT *const s) noexcept
357 return strlen_c_r(s, 0UL);
360 static_assert(strlen_c("") == 0UL, "");
361 static_assert(strlen_c("1") == 1UL, "");
362 static_assert(strlen_c("example") == 7UL, "");
363 static_assert(strlen_c("another\0example") == 7UL, "");
367 namespace test_rvalue_references
373 static constexpr int value = N;
376 answer<1> f(int&) { return answer<1>(); }
377 answer<2> f(const int&) { return answer<2>(); }
378 answer<3> f(int&&) { return answer<3>(); }
385 static_assert(decltype(f(i))::value == 1, "");
386 static_assert(decltype(f(c))::value == 2, "");
387 static_assert(decltype(f(0))::value == 3, "");
392 namespace test_uniform_initialization
397 static const int zero {};
398 static const int one {1};
401 static_assert(test::zero == 0, "");
402 static_assert(test::one == 1, "");
406 namespace test_lambdas
412 auto lambda1 = [](){};
413 auto lambda2 = lambda1;
421 auto a = [](int i, int j){ return i + j; }(1, 2);
422 auto b = []() -> int { return '0'; }();
423 auto c = [=](){ return a + b; }();
424 auto d = [&](){ return c; }();
425 auto e = [a, &b](int x) mutable {
426 const auto identity = [](int y){ return y; };
427 for (auto i = 0; i < a; ++i)
429 return x + identity(a + b);
431 return a + b + c + d + e;
437 const auto nullary = [](){ return 0; };
438 const auto unary = [](int x){ return x; };
439 using nullary_t = decltype(nullary);
440 using unary_t = decltype(unary);
441 const auto higher1st = [](nullary_t f){ return f(); };
442 const auto higher2nd = [unary](nullary_t f1){
443 return [unary, f1](unary_t f2){ return f2(unary(f1())); };
445 return higher1st(nullary) + higher2nd(nullary)(unary);
450 namespace test_variadic_templates
456 template <int N0, int... N1toN>
457 struct sum<N0, N1toN...>
459 static constexpr auto value = N0 + sum<N1toN...>::value;
465 static constexpr auto value = 0;
468 static_assert(sum<>::value == 0, "");
469 static_assert(sum<1>::value == 1, "");
470 static_assert(sum<23>::value == 23, "");
471 static_assert(sum<1, 2>::value == 3, "");
472 static_assert(sum<5, 5, 11>::value == 21, "");
473 static_assert(sum<2, 3, 5, 7, 11, 13>::value == 41, "");
477 // http://stackoverflow.com/questions/13728184/template-aliases-and-sfinae
478 // Clang 3.1 fails with headers of libstd++ 4.8.3 when using std::function
480 namespace test_template_alias_sfinae
486 using member = typename T::member_type;
492 void func(member<T>*) {}
496 void test() { func<foo>(0); }
502 #endif // __cplusplus >= 201103L
507 dnl Tests for new features in C++14
509 m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_14], [[
511 // If the compiler admits that it is not ready for C++14, why torture it?
512 // Hopefully, this will speed up the test.
516 #error "This is not a C++ compiler"
518 #elif __cplusplus < 201402L && !defined _MSC_VER
520 #error "This is not a C++14 compiler"
527 namespace test_polymorphic_lambdas
533 const auto lambda = [](auto&&... args){
534 const auto istiny = [](auto x){
535 return (sizeof(x) == 1UL) ? 1 : 0;
537 const int aretiny[] = { istiny(args)... };
540 return lambda(1, 1L, 1.0f, '1');
545 namespace test_binary_literals
548 constexpr auto ivii = 0b0000000000101010;
549 static_assert(ivii == 42, "wrong value");
553 namespace test_generalized_constexpr
556 template < typename CharT >
557 constexpr unsigned long
558 strlen_c(const CharT *const s) noexcept
561 for (auto p = s; *p; ++p)
566 static_assert(strlen_c("") == 0UL, "");
567 static_assert(strlen_c("x") == 1UL, "");
568 static_assert(strlen_c("test") == 4UL, "");
569 static_assert(strlen_c("another\0test") == 7UL, "");
573 namespace test_lambda_init_capture
580 const auto lambda1 = [a = x](int b){ return a + b; };
581 const auto lambda2 = [a = lambda1(x)](){ return a; };
587 namespace test_digit_separators
590 constexpr auto ten_million = 100'000'000;
591 static_assert(ten_million == 100000000, "");
595 namespace test_return_type_deduction
598 auto f(int& x) { return x; }
599 decltype(auto) g(int& x) { return x; }
601 template < typename T1, typename T2 >
604 static constexpr auto value = false;
607 template < typename T >
610 static constexpr auto value = true;
617 static_assert(is_same<int, decltype(f(x))>::value, "");
618 static_assert(is_same<int&, decltype(g(x))>::value, "");
626 #endif // __cplusplus >= 201402L
631 dnl Tests for new features in C++17
633 m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_17], [[
635 // If the compiler admits that it is not ready for C++17, why torture it?
636 // Hopefully, this will speed up the test.
640 #error "This is not a C++ compiler"
642 #elif (defined _MSVC_LANG ? _MSVC_LANG : __cplusplus) < 201703L
644 #error "This is not a C++17 compiler"
648 #include <initializer_list>
650 #include <type_traits>
655 namespace test_constexpr_lambdas
658 constexpr int foo = [](){return 42;}();
662 namespace test::nested_namespace::definitions
667 namespace test_fold_expression
670 template<typename... Args>
671 int multiply(Args... args)
673 return (args * ... * 1);
676 template<typename... Args>
677 bool all(Args... args)
679 return (args && ...);
684 namespace test_extended_static_assert
687 static_assert (true);
691 namespace test_auto_brace_init_list
697 static_assert(std::is_same<std::initializer_list<int>, decltype(foo)>::value);
698 static_assert(std::is_same<int, decltype(bar)>::value);
701 namespace test_typename_in_template_template_parameter
704 template<template<typename> typename X> struct D;
708 namespace test_fallthrough_nodiscard_maybe_unused_attributes
716 [[nodiscard]] int f2()
718 [[maybe_unused]] auto unused = f1();
733 namespace test_extended_aggregate_initialization
749 struct derived : base1, base2
754 derived d1 {{1, 2}, {}, 4}; // full initialization
755 derived d2 {{}, {}, 4}; // value-initialized bases
759 namespace test_general_range_based_for_loop
771 const int& operator* () const
788 bool operator== (const iter& i, const sentinel& s)
793 bool operator!= (const iter& i, const sentinel& s)
817 [[maybe_unused]] auto v = i;
823 namespace test_lambda_capture_asterisk_this_by_value
840 namespace test_enum_class_construction
843 enum class byte : unsigned char
850 namespace test_constexpr_if
868 namespace test_selection_statement_with_initializer
878 if (auto i = f(); i > 0)
883 switch (auto i = f(); i + 4)
895 namespace test_template_argument_deduction_for_class_templates
898 template <typename T1, typename T2>
912 [[maybe_unused]] auto p = pair{13, 42u};
917 namespace test_non_type_auto_template_parameters
929 namespace test_structured_bindings
932 int arr[2] = { 1, 2 };
933 std::pair<int, int> pr = { 1, 2 };
935 auto f1() -> int(&)[2]
940 auto f2() -> std::pair<int, int>&
956 auto [ x1, y1 ] = f1();
957 auto& [ xr1, yr1 ] = f1();
958 auto [ x2, y2 ] = f2();
959 auto& [ xr2, yr2 ] = f2();
960 const auto [ x3, y3 ] = f3();
964 namespace test_exception_spec_type_system
977 template<typename T1, typename T2>
981 static_assert (std::is_same_v<Good, decltype(f(g1, g2))>);
985 namespace test_inline_variables
988 template<class T> void f(T)
991 template<class T> inline T g(T)
996 template<> inline void f<>(int)
999 template<> int g<>(int)
1006 } // namespace cxx17
1008 #endif // (defined _MSVC_LANG ? _MSVC_LANG : __cplusplus) < 201703L
1013 dnl Tests for new features in C++20
1015 m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_20], [[
1019 #error "This is not a C++ compiler"
1021 #elif (defined _MSVC_LANG ? _MSVC_LANG : __cplusplus) < 202002L
1023 #error "This is not a C++20 compiler"
1032 // As C++20 supports feature test macros in the standard, there is no
1033 // immediate need to actually test for feature availability on the
1036 } // namespace cxx20
1038 #endif // (defined _MSVC_LANG ? _MSVC_LANG : __cplusplus) < 202002L
1043 dnl Tests for new features in C++23
1045 m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_23], [[
1049 #error "This is not a C++ compiler"
1051 #elif (defined _MSVC_LANG ? _MSVC_LANG : __cplusplus) < 202302L
1053 #error "This is not a C++23 compiler"
1062 // As C++23 supports feature test macros in the standard, there is no
1063 // immediate need to actually test for feature availability on the
1066 } // namespace cxx23
1068 #endif // (defined _MSVC_LANG ? _MSVC_LANG : __cplusplus) < 202302L