php_cxx_compile_stdcxx.m4 17 KB

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