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