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