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