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