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