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