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