Linux: enforce a c++17 compiler usage
[scilab.git] / scilab / m4 / ax_cxx_compile_stdcxx.m4
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
46 dnl  This macro is based on the code from the AX_CXX_COMPILE_STDCXX_11 macro
47 dnl  (serial version number 13).
48
49 AC_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
137 dnl  Test body for checking C++11 support
138
139 m4_define([_AX_CXX_COMPILE_STDCXX_testbody_11],
140   _AX_CXX_COMPILE_STDCXX_testbody_new_in_11
141 )
142
143
144 dnl  Test body for checking C++14 support
145
146 m4_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
151 m4_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
157 dnl  Tests for new features in C++11
158
159 m4_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
174 namespace 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
448 dnl  Tests for new features in C++14
449
450 m4_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
465 namespace 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
572 dnl  Tests for new features in C++17
573
574 m4_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
593 namespace 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 ]])