Home | History | Annotate | Line # | Download | only in conftools
      1 # ===========================================================================
      2 #  https://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx.html
      3 # ===========================================================================
      4 #
      5 # SYNOPSIS
      6 #
      7 #   AX_CXX_COMPILE_STDCXX(VERSION, [ext|noext], [mandatory|optional])
      8 #
      9 # DESCRIPTION
     10 #
     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', or '20' for
     14 #   the respective C++ standard version.
     15 #
     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.
     20 #
     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.
     27 #
     28 # LICENSE
     29 #
     30 #   Copyright (c) 2008 Benjamin Kosnik <bkoz (a] redhat.com>
     31 #   Copyright (c) 2012 Zack Weinberg <zackw (a] panix.com>
     32 #   Copyright (c) 2013 Roy Stogner <roystgnr (a] ices.utexas.edu>
     33 #   Copyright (c) 2014, 2015 Google Inc.; contributed by Alexey Sokolov <sokolov (a] google.com>
     34 #   Copyright (c) 2015 Paul Norman <penorman (a] mac.com>
     35 #   Copyright (c) 2015 Moritz Klammler <moritz (a] klammler.eu>
     36 #   Copyright (c) 2016, 2018 Krzesimir Nowak <qdlacz (a] gmail.com>
     37 #   Copyright (c) 2019 Enji Cooper <yaneurabeya (a] gmail.com>
     38 #   Copyright (c) 2020 Jason Merrill <jason (a] redhat.com>
     39 #   Copyright (c) 2021 Jrn Heusipp <osmanx (a] problemloesungsmaschine.de>
     40 #
     41 #   Copying and distribution of this file, with or without modification, are
     42 #   permitted in any medium without royalty provided the copyright notice
     43 #   and this notice are preserved.  This file is offered as-is, without any
     44 #   warranty.
     45 
     46 #serial 18
     47 
     48 dnl  This macro is based on the code from the AX_CXX_COMPILE_STDCXX_11 macro
     49 dnl  (serial version number 13).
     50 
     51 AC_DEFUN([AX_CXX_COMPILE_STDCXX], [dnl
     52   m4_if([$1], [11], [ax_cxx_compile_alternatives="11 0x"],
     53         [$1], [14], [ax_cxx_compile_alternatives="14 1y"],
     54         [$1], [17], [ax_cxx_compile_alternatives="17 1z"],
     55         [$1], [20], [ax_cxx_compile_alternatives="20"],
     56         [m4_fatal([invalid first argument `$1' to AX_CXX_COMPILE_STDCXX])])dnl
     57   m4_if([$2], [], [],
     58         [$2], [ext], [],
     59         [$2], [noext], [],
     60         [m4_fatal([invalid second argument `$2' to AX_CXX_COMPILE_STDCXX])])dnl
     61   m4_if([$3], [], [ax_cxx_compile_cxx$1_required=true],
     62         [$3], [mandatory], [ax_cxx_compile_cxx$1_required=true],
     63         [$3], [optional], [ax_cxx_compile_cxx$1_required=false],
     64         [m4_fatal([invalid third argument `$3' to AX_CXX_COMPILE_STDCXX])])
     65   AC_LANG_PUSH([C++])dnl
     66   ac_success=no
     67 
     68   m4_if([$2], [], [dnl
     69     AC_CACHE_CHECK(whether $CXX supports C++$1 features by default,
     70 		   ax_cv_cxx_compile_cxx$1,
     71       [AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])],
     72         [ax_cv_cxx_compile_cxx$1=yes],
     73         [ax_cv_cxx_compile_cxx$1=no])])
     74     if test x$ax_cv_cxx_compile_cxx$1 = xyes; then
     75       ac_success=yes
     76     fi])
     77 
     78   m4_if([$2], [noext], [], [dnl
     79   if test x$ac_success = xno; then
     80     for alternative in ${ax_cxx_compile_alternatives}; do
     81       switch="-std=gnu++${alternative}"
     82       cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch])
     83       AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch,
     84                      $cachevar,
     85         [ac_save_CXX="$CXX"
     86          CXX="$CXX $switch"
     87          AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])],
     88           [eval $cachevar=yes],
     89           [eval $cachevar=no])
     90          CXX="$ac_save_CXX"])
     91       if eval test x\$$cachevar = xyes; then
     92         CXX="$CXX $switch"
     93         if test -n "$CXXCPP" ; then
     94           CXXCPP="$CXXCPP $switch"
     95         fi
     96         ac_success=yes
     97         break
     98       fi
     99     done
    100   fi])
    101 
    102   m4_if([$2], [ext], [], [dnl
    103   if test x$ac_success = xno; then
    104     dnl HP's aCC needs +std=c++11 according to:
    105     dnl http://h21007.www2.hp.com/portal/download/files/unprot/aCxx/PDF_Release_Notes/769149-001.pdf
    106     dnl Cray's crayCC needs "-h std=c++11"
    107     dnl MSVC needs -std:c++NN for C++17 and later (default is C++14)
    108     for alternative in ${ax_cxx_compile_alternatives}; do
    109       for switch in -std=c++${alternative} +std=c++${alternative} "-h std=c++${alternative}" MSVC; do
    110         if test x"$switch" = xMSVC; then
    111           dnl AS_TR_SH maps both `:` and `=` to `_` so -std:c++17 would collide
    112           dnl with -std=c++17.  We suffix the cache variable name with _MSVC to
    113           dnl avoid this.
    114           switch=-std:c++${alternative}
    115           cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_${switch}_MSVC])
    116         else
    117           cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch])
    118         fi
    119         AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch,
    120                        $cachevar,
    121           [ac_save_CXX="$CXX"
    122            CXX="$CXX $switch"
    123            AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])],
    124             [eval $cachevar=yes],
    125             [eval $cachevar=no])
    126            CXX="$ac_save_CXX"])
    127         if eval test x\$$cachevar = xyes; then
    128           CXX="$CXX $switch"
    129           if test -n "$CXXCPP" ; then
    130             CXXCPP="$CXXCPP $switch"
    131           fi
    132           ac_success=yes
    133           break
    134         fi
    135       done
    136       if test x$ac_success = xyes; then
    137         break
    138       fi
    139     done
    140   fi])
    141   AC_LANG_POP([C++])
    142   if test x$ax_cxx_compile_cxx$1_required = xtrue; then
    143     if test x$ac_success = xno; then
    144       AC_MSG_ERROR([*** A compiler with support for C++$1 language features is required.])
    145     fi
    146   fi
    147   if test x$ac_success = xno; then
    148     HAVE_CXX$1=0
    149     AC_MSG_NOTICE([No compiler with C++$1 support was found])
    150   else
    151     HAVE_CXX$1=1
    152     AC_DEFINE(HAVE_CXX$1,1,
    153               [define if the compiler supports basic C++$1 syntax])
    154   fi
    155   AC_SUBST(HAVE_CXX$1)
    156 ])
    157 
    158 
    159 dnl  Test body for checking C++11 support
    160 
    161 m4_define([_AX_CXX_COMPILE_STDCXX_testbody_11],
    162   _AX_CXX_COMPILE_STDCXX_testbody_new_in_11
    163 )
    164 
    165 dnl  Test body for checking C++14 support
    166 
    167 m4_define([_AX_CXX_COMPILE_STDCXX_testbody_14],
    168   _AX_CXX_COMPILE_STDCXX_testbody_new_in_11
    169   _AX_CXX_COMPILE_STDCXX_testbody_new_in_14
    170 )
    171 
    172 dnl  Test body for checking C++17 support
    173 
    174 m4_define([_AX_CXX_COMPILE_STDCXX_testbody_17],
    175   _AX_CXX_COMPILE_STDCXX_testbody_new_in_11
    176   _AX_CXX_COMPILE_STDCXX_testbody_new_in_14
    177   _AX_CXX_COMPILE_STDCXX_testbody_new_in_17
    178 )
    179 
    180 dnl  Test body for checking C++20 support
    181 
    182 m4_define([_AX_CXX_COMPILE_STDCXX_testbody_20],
    183   _AX_CXX_COMPILE_STDCXX_testbody_new_in_11
    184   _AX_CXX_COMPILE_STDCXX_testbody_new_in_14
    185   _AX_CXX_COMPILE_STDCXX_testbody_new_in_17
    186   _AX_CXX_COMPILE_STDCXX_testbody_new_in_20
    187 )
    188 
    189 
    190 dnl  Tests for new features in C++11
    191 
    192 m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_11], [[
    193 
    194 // If the compiler admits that it is not ready for C++11, why torture it?
    195 // Hopefully, this will speed up the test.
    196 
    197 #ifndef __cplusplus
    198 
    199 #error "This is not a C++ compiler"
    200 
    201 // MSVC always sets __cplusplus to 199711L in older versions; newer versions
    202 // only set it correctly if /Zc:__cplusplus is specified as well as a
    203 // /std:c++NN switch:
    204 // https://devblogs.microsoft.com/cppblog/msvc-now-correctly-reports-__cplusplus/
    205 #elif __cplusplus < 201103L && !defined _MSC_VER
    206 
    207 #error "This is not a C++11 compiler"
    208 
    209 #else
    210 
    211 namespace cxx11
    212 {
    213 
    214   namespace test_static_assert
    215   {
    216 
    217     template <typename T>
    218     struct check
    219     {
    220       static_assert(sizeof(int) <= sizeof(T), "not big enough");
    221     };
    222 
    223   }
    224 
    225   namespace test_final_override
    226   {
    227 
    228     struct Base
    229     {
    230       virtual ~Base() {}
    231       virtual void f() {}
    232     };
    233 
    234     struct Derived : public Base
    235     {
    236       virtual ~Derived() override {}
    237       virtual void f() override {}
    238     };
    239 
    240   }
    241 
    242   namespace test_double_right_angle_brackets
    243   {
    244 
    245     template < typename T >
    246     struct check {};
    247 
    248     typedef check<void> single_type;
    249     typedef check<check<void>> double_type;
    250     typedef check<check<check<void>>> triple_type;
    251     typedef check<check<check<check<void>>>> quadruple_type;
    252 
    253   }
    254 
    255   namespace test_decltype
    256   {
    257 
    258     int
    259     f()
    260     {
    261       int a = 1;
    262       decltype(a) b = 2;
    263       return a + b;
    264     }
    265 
    266   }
    267 
    268   namespace test_type_deduction
    269   {
    270 
    271     template < typename T1, typename T2 >
    272     struct is_same
    273     {
    274       static const bool value = false;
    275     };
    276 
    277     template < typename T >
    278     struct is_same<T, T>
    279     {
    280       static const bool value = true;
    281     };
    282 
    283     template < typename T1, typename T2 >
    284     auto
    285     add(T1 a1, T2 a2) -> decltype(a1 + a2)
    286     {
    287       return a1 + a2;
    288     }
    289 
    290     int
    291     test(const int c, volatile int v)
    292     {
    293       static_assert(is_same<int, decltype(0)>::value == true, "");
    294       static_assert(is_same<int, decltype(c)>::value == false, "");
    295       static_assert(is_same<int, decltype(v)>::value == false, "");
    296       auto ac = c;
    297       auto av = v;
    298       auto sumi = ac + av + 'x';
    299       auto sumf = ac + av + 1.0;
    300       static_assert(is_same<int, decltype(ac)>::value == true, "");
    301       static_assert(is_same<int, decltype(av)>::value == true, "");
    302       static_assert(is_same<int, decltype(sumi)>::value == true, "");
    303       static_assert(is_same<int, decltype(sumf)>::value == false, "");
    304       static_assert(is_same<int, decltype(add(c, v))>::value == true, "");
    305       return (sumf > 0.0) ? sumi : add(c, v);
    306     }
    307 
    308   }
    309 
    310   namespace test_noexcept
    311   {
    312 
    313     int f() { return 0; }
    314     int g() noexcept { return 0; }
    315 
    316     static_assert(noexcept(f()) == false, "");
    317     static_assert(noexcept(g()) == true, "");
    318 
    319   }
    320 
    321   namespace test_constexpr
    322   {
    323 
    324     template < typename CharT >
    325     unsigned long constexpr
    326     strlen_c_r(const CharT *const s, const unsigned long acc) noexcept
    327     {
    328       return *s ? strlen_c_r(s + 1, acc + 1) : acc;
    329     }
    330 
    331     template < typename CharT >
    332     unsigned long constexpr
    333     strlen_c(const CharT *const s) noexcept
    334     {
    335       return strlen_c_r(s, 0UL);
    336     }
    337 
    338     static_assert(strlen_c("") == 0UL, "");
    339     static_assert(strlen_c("1") == 1UL, "");
    340     static_assert(strlen_c("example") == 7UL, "");
    341     static_assert(strlen_c("another\0example") == 7UL, "");
    342 
    343   }
    344 
    345   namespace test_rvalue_references
    346   {
    347 
    348     template < int N >
    349     struct answer
    350     {
    351       static constexpr int value = N;
    352     };
    353 
    354     answer<1> f(int&)       { return answer<1>(); }
    355     answer<2> f(const int&) { return answer<2>(); }
    356     answer<3> f(int&&)      { return answer<3>(); }
    357 
    358     void
    359     test()
    360     {
    361       int i = 0;
    362       const int c = 0;
    363       static_assert(decltype(f(i))::value == 1, "");
    364       static_assert(decltype(f(c))::value == 2, "");
    365       static_assert(decltype(f(0))::value == 3, "");
    366     }
    367 
    368   }
    369 
    370   namespace test_uniform_initialization
    371   {
    372 
    373     struct test
    374     {
    375       static const int zero {};
    376       static const int one {1};
    377     };
    378 
    379     static_assert(test::zero == 0, "");
    380     static_assert(test::one == 1, "");
    381 
    382   }
    383 
    384   namespace test_lambdas
    385   {
    386 
    387     void
    388     test1()
    389     {
    390       auto lambda1 = [](){};
    391       auto lambda2 = lambda1;
    392       lambda1();
    393       lambda2();
    394     }
    395 
    396     int
    397     test2()
    398     {
    399       auto a = [](int i, int j){ return i + j; }(1, 2);
    400       auto b = []() -> int { return '0'; }();
    401       auto c = [=](){ return a + b; }();
    402       auto d = [&](){ return c; }();
    403       auto e = [a, &b](int x) mutable {
    404         const auto identity = [](int y){ return y; };
    405         for (auto i = 0; i < a; ++i)
    406           a += b--;
    407         return x + identity(a + b);
    408       }(0);
    409       return a + b + c + d + e;
    410     }
    411 
    412     int
    413     test3()
    414     {
    415       const auto nullary = [](){ return 0; };
    416       const auto unary = [](int x){ return x; };
    417       using nullary_t = decltype(nullary);
    418       using unary_t = decltype(unary);
    419       const auto higher1st = [](nullary_t f){ return f(); };
    420       const auto higher2nd = [unary](nullary_t f1){
    421         return [unary, f1](unary_t f2){ return f2(unary(f1())); };
    422       };
    423       return higher1st(nullary) + higher2nd(nullary)(unary);
    424     }
    425 
    426   }
    427 
    428   namespace test_variadic_templates
    429   {
    430 
    431     template <int...>
    432     struct sum;
    433 
    434     template <int N0, int... N1toN>
    435     struct sum<N0, N1toN...>
    436     {
    437       static constexpr auto value = N0 + sum<N1toN...>::value;
    438     };
    439 
    440     template <>
    441     struct sum<>
    442     {
    443       static constexpr auto value = 0;
    444     };
    445 
    446     static_assert(sum<>::value == 0, "");
    447     static_assert(sum<1>::value == 1, "");
    448     static_assert(sum<23>::value == 23, "");
    449     static_assert(sum<1, 2>::value == 3, "");
    450     static_assert(sum<5, 5, 11>::value == 21, "");
    451     static_assert(sum<2, 3, 5, 7, 11, 13>::value == 41, "");
    452 
    453   }
    454 
    455   // http://stackoverflow.com/questions/13728184/template-aliases-and-sfinae
    456   // Clang 3.1 fails with headers of libstd++ 4.8.3 when using std::function
    457   // because of this.
    458   namespace test_template_alias_sfinae
    459   {
    460 
    461     struct foo {};
    462 
    463     template<typename T>
    464     using member = typename T::member_type;
    465 
    466     template<typename T>
    467     void func(...) {}
    468 
    469     template<typename T>
    470     void func(member<T>*) {}
    471 
    472     void test();
    473 
    474     void test() { func<foo>(0); }
    475 
    476   }
    477 
    478 }  // namespace cxx11
    479 
    480 #endif  // __cplusplus >= 201103L
    481 
    482 ]])
    483 
    484 
    485 dnl  Tests for new features in C++14
    486 
    487 m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_14], [[
    488 
    489 // If the compiler admits that it is not ready for C++14, why torture it?
    490 // Hopefully, this will speed up the test.
    491 
    492 #ifndef __cplusplus
    493 
    494 #error "This is not a C++ compiler"
    495 
    496 #elif __cplusplus < 201402L && !defined _MSC_VER
    497 
    498 #error "This is not a C++14 compiler"
    499 
    500 #else
    501 
    502 namespace cxx14
    503 {
    504 
    505   namespace test_polymorphic_lambdas
    506   {
    507 
    508     int
    509     test()
    510     {
    511       const auto lambda = [](auto&&... args){
    512         const auto istiny = [](auto x){
    513           return (sizeof(x) == 1UL) ? 1 : 0;
    514         };
    515         const int aretiny[] = { istiny(args)... };
    516         return aretiny[0];
    517       };
    518       return lambda(1, 1L, 1.0f, '1');
    519     }
    520 
    521   }
    522 
    523   namespace test_binary_literals
    524   {
    525 
    526     constexpr auto ivii = 0b0000000000101010;
    527     static_assert(ivii == 42, "wrong value");
    528 
    529   }
    530 
    531   namespace test_generalized_constexpr
    532   {
    533 
    534     template < typename CharT >
    535     constexpr unsigned long
    536     strlen_c(const CharT *const s) noexcept
    537     {
    538       auto length = 0UL;
    539       for (auto p = s; *p; ++p)
    540         ++length;
    541       return length;
    542     }
    543 
    544     static_assert(strlen_c("") == 0UL, "");
    545     static_assert(strlen_c("x") == 1UL, "");
    546     static_assert(strlen_c("test") == 4UL, "");
    547     static_assert(strlen_c("another\0test") == 7UL, "");
    548 
    549   }
    550 
    551   namespace test_lambda_init_capture
    552   {
    553 
    554     int
    555     test()
    556     {
    557       auto x = 0;
    558       const auto lambda1 = [a = x](int b){ return a + b; };
    559       const auto lambda2 = [a = lambda1(x)](){ return a; };
    560       return lambda2();
    561     }
    562 
    563   }
    564 
    565   namespace test_digit_separators
    566   {
    567 
    568     constexpr auto ten_million = 100'000'000;
    569     static_assert(ten_million == 100000000, "");
    570 
    571   }
    572 
    573   namespace test_return_type_deduction
    574   {
    575 
    576     auto f(int& x) { return x; }
    577     decltype(auto) g(int& x) { return x; }
    578 
    579     template < typename T1, typename T2 >
    580     struct is_same
    581     {
    582       static constexpr auto value = false;
    583     };
    584 
    585     template < typename T >
    586     struct is_same<T, T>
    587     {
    588       static constexpr auto value = true;
    589     };
    590 
    591     int
    592     test()
    593     {
    594       auto x = 0;
    595       static_assert(is_same<int, decltype(f(x))>::value, "");
    596       static_assert(is_same<int&, decltype(g(x))>::value, "");
    597       return x;
    598     }
    599 
    600   }
    601 
    602 }  // namespace cxx14
    603 
    604 #endif  // __cplusplus >= 201402L
    605 
    606 ]])
    607 
    608 
    609 dnl  Tests for new features in C++17
    610 
    611 m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_17], [[
    612 
    613 // If the compiler admits that it is not ready for C++17, why torture it?
    614 // Hopefully, this will speed up the test.
    615 
    616 #ifndef __cplusplus
    617 
    618 #error "This is not a C++ compiler"
    619 
    620 #elif __cplusplus < 201703L && !defined _MSC_VER
    621 
    622 #error "This is not a C++17 compiler"
    623 
    624 #else
    625 
    626 #include <initializer_list>
    627 #include <utility>
    628 #include <type_traits>
    629 
    630 namespace cxx17
    631 {
    632 
    633   namespace test_constexpr_lambdas
    634   {
    635 
    636     constexpr int foo = [](){return 42;}();
    637 
    638   }
    639 
    640   namespace test::nested_namespace::definitions
    641   {
    642 
    643   }
    644 
    645   namespace test_fold_expression
    646   {
    647 
    648     template<typename... Args>
    649     int multiply(Args... args)
    650     {
    651       return (args * ... * 1);
    652     }
    653 
    654     template<typename... Args>
    655     bool all(Args... args)
    656     {
    657       return (args && ...);
    658     }
    659 
    660   }
    661 
    662   namespace test_extended_static_assert
    663   {
    664 
    665     static_assert (true);
    666 
    667   }
    668 
    669   namespace test_auto_brace_init_list
    670   {
    671 
    672     auto foo = {5};
    673     auto bar {5};
    674 
    675     static_assert(std::is_same<std::initializer_list<int>, decltype(foo)>::value);
    676     static_assert(std::is_same<int, decltype(bar)>::value);
    677   }
    678 
    679   namespace test_typename_in_template_template_parameter
    680   {
    681 
    682     template<template<typename> typename X> struct D;
    683 
    684   }
    685 
    686   namespace test_fallthrough_nodiscard_maybe_unused_attributes
    687   {
    688 
    689     int f1()
    690     {
    691       return 42;
    692     }
    693 
    694     [[nodiscard]] int f2()
    695     {
    696       [[maybe_unused]] auto unused = f1();
    697 
    698       switch (f1())
    699       {
    700       case 17:
    701         f1();
    702         [[fallthrough]];
    703       case 42:
    704         f1();
    705       }
    706       return f1();
    707     }
    708 
    709   }
    710 
    711   namespace test_extended_aggregate_initialization
    712   {
    713 
    714     struct base1
    715     {
    716       int b1, b2 = 42;
    717     };
    718 
    719     struct base2
    720     {
    721       base2() {
    722         b3 = 42;
    723       }
    724       int b3;
    725     };
    726 
    727     struct derived : base1, base2
    728     {
    729         int d;
    730     };
    731 
    732     derived d1 {{1, 2}, {}, 4};  // full initialization
    733     derived d2 {{}, {}, 4};      // value-initialized bases
    734 
    735   }
    736 
    737   namespace test_general_range_based_for_loop
    738   {
    739 
    740     struct iter
    741     {
    742       int i;
    743 
    744       int& operator* ()
    745       {
    746         return i;
    747       }
    748 
    749       const int& operator* () const
    750       {
    751         return i;
    752       }
    753 
    754       iter& operator++()
    755       {
    756         ++i;
    757         return *this;
    758       }
    759     };
    760 
    761     struct sentinel
    762     {
    763       int i;
    764     };
    765 
    766     bool operator== (const iter& i, const sentinel& s)
    767     {
    768       return i.i == s.i;
    769     }
    770 
    771     bool operator!= (const iter& i, const sentinel& s)
    772     {
    773       return !(i == s);
    774     }
    775 
    776     struct range
    777     {
    778       iter begin() const
    779       {
    780         return {0};
    781       }
    782 
    783       sentinel end() const
    784       {
    785         return {5};
    786       }
    787     };
    788 
    789     void f()
    790     {
    791       range r {};
    792 
    793       for (auto i : r)
    794       {
    795         [[maybe_unused]] auto v = i;
    796       }
    797     }
    798 
    799   }
    800 
    801   namespace test_lambda_capture_asterisk_this_by_value
    802   {
    803 
    804     struct t
    805     {
    806       int i;
    807       int foo()
    808       {
    809         return [*this]()
    810         {
    811           return i;
    812         }();
    813       }
    814     };
    815 
    816   }
    817 
    818   namespace test_enum_class_construction
    819   {
    820 
    821     enum class byte : unsigned char
    822     {};
    823 
    824     byte foo {42};
    825 
    826   }
    827 
    828   namespace test_constexpr_if
    829   {
    830 
    831     template <bool cond>
    832     int f ()
    833     {
    834       if constexpr(cond)
    835       {
    836         return 13;
    837       }
    838       else
    839       {
    840         return 42;
    841       }
    842     }
    843 
    844   }
    845 
    846   namespace test_selection_statement_with_initializer
    847   {
    848 
    849     int f()
    850     {
    851       return 13;
    852     }
    853 
    854     int f2()
    855     {
    856       if (auto i = f(); i > 0)
    857       {
    858         return 3;
    859       }
    860 
    861       switch (auto i = f(); i + 4)
    862       {
    863       case 17:
    864         return 2;
    865 
    866       default:
    867         return 1;
    868       }
    869     }
    870 
    871   }
    872 
    873   namespace test_template_argument_deduction_for_class_templates
    874   {
    875 
    876     template <typename T1, typename T2>
    877     struct pair
    878     {
    879       pair (T1 p1, T2 p2)
    880         : m1 {p1},
    881           m2 {p2}
    882       {}
    883 
    884       T1 m1;
    885       T2 m2;
    886     };
    887 
    888     void f()
    889     {
    890       [[maybe_unused]] auto p = pair{13, 42u};
    891     }
    892 
    893   }
    894 
    895   namespace test_non_type_auto_template_parameters
    896   {
    897 
    898     template <auto n>
    899     struct B
    900     {};
    901 
    902     B<5> b1;
    903     B<'a'> b2;
    904 
    905   }
    906 
    907   namespace test_structured_bindings
    908   {
    909 
    910     int arr[2] = { 1, 2 };
    911     std::pair<int, int> pr = { 1, 2 };
    912 
    913     auto f1() -> int(&)[2]
    914     {
    915       return arr;
    916     }
    917 
    918     auto f2() -> std::pair<int, int>&
    919     {
    920       return pr;
    921     }
    922 
    923     struct S
    924     {
    925       int x1 : 2;
    926       volatile double y1;
    927     };
    928 
    929     S f3()
    930     {
    931       return {};
    932     }
    933 
    934     auto [ x1, y1 ] = f1();
    935     auto& [ xr1, yr1 ] = f1();
    936     auto [ x2, y2 ] = f2();
    937     auto& [ xr2, yr2 ] = f2();
    938     const auto [ x3, y3 ] = f3();
    939 
    940   }
    941 
    942   namespace test_exception_spec_type_system
    943   {
    944 
    945     struct Good {};
    946     struct Bad {};
    947 
    948     void g1() noexcept;
    949     void g2();
    950 
    951     template<typename T>
    952     Bad
    953     f(T*, T*);
    954 
    955     template<typename T1, typename T2>
    956     Good
    957     f(T1*, T2*);
    958 
    959     static_assert (std::is_same_v<Good, decltype(f(g1, g2))>);
    960 
    961   }
    962 
    963   namespace test_inline_variables
    964   {
    965 
    966     template<class T> void f(T)
    967     {}
    968 
    969     template<class T> inline T g(T)
    970     {
    971       return T{};
    972     }
    973 
    974     template<> inline void f<>(int)
    975     {}
    976 
    977     template<> int g<>(int)
    978     {
    979       return 5;
    980     }
    981 
    982   }
    983 
    984 }  // namespace cxx17
    985 
    986 #endif  // __cplusplus < 201703L && !defined _MSC_VER
    987 
    988 ]])
    989 
    990 
    991 dnl  Tests for new features in C++20
    992 
    993 m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_20], [[
    994 
    995 #ifndef __cplusplus
    996 
    997 #error "This is not a C++ compiler"
    998 
    999 #elif __cplusplus < 202002L && !defined _MSC_VER
   1000 
   1001 #error "This is not a C++20 compiler"
   1002 
   1003 #else
   1004 
   1005 #include <version>
   1006 
   1007 namespace cxx20
   1008 {
   1009 
   1010 // As C++20 supports feature test macros in the standard, there is no
   1011 // immediate need to actually test for feature availability on the
   1012 // Autoconf side.
   1013 
   1014 }  // namespace cxx20
   1015 
   1016 #endif  // __cplusplus < 202002L && !defined _MSC_VER
   1017 
   1018 ]])
   1019