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