diff mbox series

[committed,1/2] libstdc++: Reduce header dependencies on <array> and <utility>

Message ID YP/44pvIPoBzwix+@redhat.com
State New
Headers show
Series [committed,1/2] libstdc++: Reduce header dependencies on <array> and <utility> | expand

Commit Message

Jonathan Wakely July 27, 2021, 12:15 p.m. UTC
This refactoring reduces the memory usage and compilation time to parse
a number of headers that depend on std::pair, std::tuple or std::array.
Previously the headers for these class templates were all intertwined,
due to the common dependency on std::tuple_size, std::tuple_element and
their std::get overloads. This decouples the headers by moving some
parts of <utility> into a new <bits/utility.h> header. This means that
<array> and <tuple> no longer need to include the whole of <utility>,
and <tuple> no longer needs to include <array>.

This decoupling benefits headers such as <thread> and <scoped_allocator>
which only need std::tuple, and so no longer have to parse std::array.

Some other headers such as <any>, <optional> and <variant> no longer
need to include <utility> just for the std::in_place tag types, so
do not have to parse the std::pair definitions.

Removing direct uses of <utility> also means that the std::rel_ops
namespace is not transitively declared by other headers.

Signed-off-by: Jonathan Wakely <jwakely@redhat.com>

libstdc++-v3/ChangeLog:

	* include/Makefile.am: Add bits/utility.h header.
	* include/Makefile.in: Regenerate.
	* include/bits/utility.h: New file.
	* include/std/utility (tuple_size, tuple_element): Move
	to new header.
	* include/std/type_traits (__is_tuple_like_impl<tuple<T...>>):
	Move to <tuple>.
	(_Index_tuple, _Build_index_tuple, integer_sequence): Likewise.
	(in_place_t, in_place_index_t, in_place_type_t): Likewise.
	* include/bits/ranges_util.h: Include new header instead of
	<utility>.
	* include/bits/stl_pair.h (tuple_size, tuple_element): Move
	partial specializations for std::pair here.
	(get): Move overloads for std::pair here.
	* include/std/any: Include new header instead of <utility>.
	* include/std/array: Likewise.
	* include/std/memory_resource: Likewise.
	* include/std/optional: Likewise.
	* include/std/variant: Likewise.
	* include/std/tuple: Likewise.
	(__is_tuple_like_impl<tuple<T...>>): Move here.
	(get) Declare overloads for std::array.
	* include/std/version (__cpp_lib_tuples_by_type): Change type
	to long.
	* testsuite/20_util/optional/84601.cc: Include <utility>.
	* testsuite/20_util/specialized_algorithms/uninitialized_fill/constrained.cc:
	Likewise.
	* testsuite/23_containers/array/tuple_interface/get_neg.cc:
	Adjust dg-error line numbers.
	* testsuite/std/ranges/access/cbegin.cc: Include <utility>.
	* testsuite/std/ranges/access/cend.cc: Likewise.
	* testsuite/std/ranges/access/end.cc: Likewise.
	* testsuite/std/ranges/single_view.cc: Likewise.

Tested powerpc64le-linux. Committed to trunk.
commit 261d5a4a459bd49942e53bc83334ccc7154a09d5
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Thu Jul 22 14:48:27 2021

    libstdc++: Reduce header dependencies on <array> and <utility>
    
    This refactoring reduces the memory usage and compilation time to parse
    a number of headers that depend on std::pair, std::tuple or std::array.
    Previously the headers for these class templates were all intertwined,
    due to the common dependency on std::tuple_size, std::tuple_element and
    their std::get overloads. This decouples the headers by moving some
    parts of <utility> into a new <bits/utility.h> header. This means that
    <array> and <tuple> no longer need to include the whole of <utility>,
    and <tuple> no longer needs to include <array>.
    
    This decoupling benefits headers such as <thread> and <scoped_allocator>
    which only need std::tuple, and so no longer have to parse std::array.
    
    Some other headers such as <any>, <optional> and <variant> no longer
    need to include <utility> just for the std::in_place tag types, so
    do not have to parse the std::pair definitions.
    
    Removing direct uses of <utility> also means that the std::rel_ops
    namespace is not transitively declared by other headers.
    
    Signed-off-by: Jonathan Wakely <jwakely@redhat.com>
    
    libstdc++-v3/ChangeLog:
    
            * include/Makefile.am: Add bits/utility.h header.
            * include/Makefile.in: Regenerate.
            * include/bits/utility.h: New file.
            * include/std/utility (tuple_size, tuple_element): Move
            to new header.
            * include/std/type_traits (__is_tuple_like_impl<tuple<T...>>):
            Move to <tuple>.
            (_Index_tuple, _Build_index_tuple, integer_sequence): Likewise.
            (in_place_t, in_place_index_t, in_place_type_t): Likewise.
            * include/bits/ranges_util.h: Include new header instead of
            <utility>.
            * include/bits/stl_pair.h (tuple_size, tuple_element): Move
            partial specializations for std::pair here.
            (get): Move overloads for std::pair here.
            * include/std/any: Include new header instead of <utility>.
            * include/std/array: Likewise.
            * include/std/memory_resource: Likewise.
            * include/std/optional: Likewise.
            * include/std/variant: Likewise.
            * include/std/tuple: Likewise.
            (__is_tuple_like_impl<tuple<T...>>): Move here.
            (get) Declare overloads for std::array.
            * include/std/version (__cpp_lib_tuples_by_type): Change type
            to long.
            * testsuite/20_util/optional/84601.cc: Include <utility>.
            * testsuite/20_util/specialized_algorithms/uninitialized_fill/constrained.cc:
            Likewise.
            * testsuite/23_containers/array/tuple_interface/get_neg.cc:
            Adjust dg-error line numbers.
            * testsuite/std/ranges/access/cbegin.cc: Include <utility>.
            * testsuite/std/ranges/access/cend.cc: Likewise.
            * testsuite/std/ranges/access/end.cc: Likewise.
            * testsuite/std/ranges/single_view.cc: Likewise.
diff mbox series

Patch

diff --git a/libstdc++-v3/include/Makefile.am b/libstdc++-v3/include/Makefile.am
index 40a41ef2a1c..99eec558116 100644
--- a/libstdc++-v3/include/Makefile.am
+++ b/libstdc++-v3/include/Makefile.am
@@ -233,6 +233,7 @@  bits_headers = \
 	${bits_srcdir}/unordered_set.h \
 	${bits_srcdir}/uses_allocator.h \
 	${bits_srcdir}/uses_allocator_args.h \
+	${bits_srcdir}/utility.h \
 	${bits_srcdir}/valarray_array.h \
 	${bits_srcdir}/valarray_array.tcc \
 	${bits_srcdir}/valarray_before.h \
diff --git a/libstdc++-v3/include/bits/ranges_util.h b/libstdc++-v3/include/bits/ranges_util.h
index 9a07079ac13..0ca203dd4b0 100644
--- a/libstdc++-v3/include/bits/ranges_util.h
+++ b/libstdc++-v3/include/bits/ranges_util.h
@@ -32,6 +32,7 @@ 
 
 #if __cplusplus > 201703L
 # include <bits/ranges_base.h>
+# include <bits/utility.h>
 
 #ifdef __cpp_lib_ranges
 namespace std _GLIBCXX_VISIBILITY(default)
diff --git a/libstdc++-v3/include/bits/stl_pair.h b/libstdc++-v3/include/bits/stl_pair.h
index c89f377fddc..329485ce3b2 100644
--- a/libstdc++-v3/include/bits/stl_pair.h
+++ b/libstdc++-v3/include/bits/stl_pair.h
@@ -56,12 +56,12 @@ 
 #ifndef _STL_PAIR_H
 #define _STL_PAIR_H 1
 
-#include <bits/move.h> // for std::move / std::forward, and std::swap
-
 #if __cplusplus >= 201103L
-# include <type_traits> // for std::__decay_and_strip, std::is_reference_v
+# include <type_traits>    // for std::__decay_and_strip
+# include <bits/move.h>    // for std::move / std::forward, and std::swap
+# include <bits/utility.h> // for std::tuple_element, std::tuple_size
 #endif
-#if __cplusplus > 201703L
+#if __cplusplus >= 202002L
 # include <compare>
 # define __cpp_lib_constexpr_utility 201811L
 #endif
@@ -752,6 +752,153 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
   /// @}
 
+#if __cplusplus >= 201103L
+  // Various functions which give std::pair a tuple-like interface.
+
+  template<typename _T1, typename _T2>
+    struct __is_tuple_like_impl<pair<_T1, _T2>> : true_type
+    { };
+
+  /// Partial specialization for std::pair
+  template<class _Tp1, class _Tp2>
+    struct tuple_size<pair<_Tp1, _Tp2>>
+    : public integral_constant<size_t, 2> { };
+
+  /// Partial specialization for std::pair
+  template<class _Tp1, class _Tp2>
+    struct tuple_element<0, pair<_Tp1, _Tp2>>
+    { typedef _Tp1 type; };
+
+  /// Partial specialization for std::pair
+  template<class _Tp1, class _Tp2>
+    struct tuple_element<1, pair<_Tp1, _Tp2>>
+    { typedef _Tp2 type; };
+
+  /// @cond undocumented
+  template<size_t _Int>
+    struct __pair_get;
+
+  template<>
+    struct __pair_get<0>
+    {
+      template<typename _Tp1, typename _Tp2>
+	static constexpr _Tp1&
+	__get(pair<_Tp1, _Tp2>& __pair) noexcept
+	{ return __pair.first; }
+
+      template<typename _Tp1, typename _Tp2>
+	static constexpr _Tp1&&
+	__move_get(pair<_Tp1, _Tp2>&& __pair) noexcept
+	{ return std::forward<_Tp1>(__pair.first); }
+
+      template<typename _Tp1, typename _Tp2>
+	static constexpr const _Tp1&
+	__const_get(const pair<_Tp1, _Tp2>& __pair) noexcept
+	{ return __pair.first; }
+
+      template<typename _Tp1, typename _Tp2>
+	static constexpr const _Tp1&&
+	__const_move_get(const pair<_Tp1, _Tp2>&& __pair) noexcept
+	{ return std::forward<const _Tp1>(__pair.first); }
+    };
+
+  template<>
+    struct __pair_get<1>
+    {
+      template<typename _Tp1, typename _Tp2>
+	static constexpr _Tp2&
+	__get(pair<_Tp1, _Tp2>& __pair) noexcept
+	{ return __pair.second; }
+
+      template<typename _Tp1, typename _Tp2>
+	static constexpr _Tp2&&
+	__move_get(pair<_Tp1, _Tp2>&& __pair) noexcept
+	{ return std::forward<_Tp2>(__pair.second); }
+
+      template<typename _Tp1, typename _Tp2>
+	static constexpr const _Tp2&
+	__const_get(const pair<_Tp1, _Tp2>& __pair) noexcept
+	{ return __pair.second; }
+
+      template<typename _Tp1, typename _Tp2>
+	static constexpr const _Tp2&&
+	__const_move_get(const pair<_Tp1, _Tp2>&& __pair) noexcept
+	{ return std::forward<const _Tp2>(__pair.second); }
+    };
+  /// @endcond
+
+  /** @{
+   * std::get overloads for accessing members of std::pair
+   */
+
+  template<size_t _Int, class _Tp1, class _Tp2>
+    constexpr typename tuple_element<_Int, pair<_Tp1, _Tp2>>::type&
+    get(pair<_Tp1, _Tp2>& __in) noexcept
+    { return __pair_get<_Int>::__get(__in); }
+
+  template<size_t _Int, class _Tp1, class _Tp2>
+    constexpr typename tuple_element<_Int, pair<_Tp1, _Tp2>>::type&&
+    get(pair<_Tp1, _Tp2>&& __in) noexcept
+    { return __pair_get<_Int>::__move_get(std::move(__in)); }
+
+  template<size_t _Int, class _Tp1, class _Tp2>
+    constexpr const typename tuple_element<_Int, pair<_Tp1, _Tp2>>::type&
+    get(const pair<_Tp1, _Tp2>& __in) noexcept
+    { return __pair_get<_Int>::__const_get(__in); }
+
+  template<size_t _Int, class _Tp1, class _Tp2>
+    constexpr const typename tuple_element<_Int, pair<_Tp1, _Tp2>>::type&&
+    get(const pair<_Tp1, _Tp2>&& __in) noexcept
+    { return __pair_get<_Int>::__const_move_get(std::move(__in)); }
+
+#if __cplusplus >= 201402L
+
+#define __cpp_lib_tuples_by_type 201304L
+
+  template <typename _Tp, typename _Up>
+    constexpr _Tp&
+    get(pair<_Tp, _Up>& __p) noexcept
+    { return __p.first; }
+
+  template <typename _Tp, typename _Up>
+    constexpr const _Tp&
+    get(const pair<_Tp, _Up>& __p) noexcept
+    { return __p.first; }
+
+  template <typename _Tp, typename _Up>
+    constexpr _Tp&&
+    get(pair<_Tp, _Up>&& __p) noexcept
+    { return std::move(__p.first); }
+
+  template <typename _Tp, typename _Up>
+    constexpr const _Tp&&
+    get(const pair<_Tp, _Up>&& __p) noexcept
+    { return std::move(__p.first); }
+
+  template <typename _Tp, typename _Up>
+    constexpr _Tp&
+    get(pair<_Up, _Tp>& __p) noexcept
+    { return __p.second; }
+
+  template <typename _Tp, typename _Up>
+    constexpr const _Tp&
+    get(const pair<_Up, _Tp>& __p) noexcept
+    { return __p.second; }
+
+  template <typename _Tp, typename _Up>
+    constexpr _Tp&&
+    get(pair<_Up, _Tp>&& __p) noexcept
+    { return std::move(__p.second); }
+
+  template <typename _Tp, typename _Up>
+    constexpr const _Tp&&
+    get(const pair<_Up, _Tp>&& __p) noexcept
+    { return std::move(__p.second); }
+
+#endif // C++14
+  /// @}
+#endif // C++11
+
 _GLIBCXX_END_NAMESPACE_VERSION
 } // namespace std
 
diff --git a/libstdc++-v3/include/bits/utility.h b/libstdc++-v3/include/bits/utility.h
new file mode 100644
index 00000000000..96d350874d9
--- /dev/null
+++ b/libstdc++-v3/include/bits/utility.h
@@ -0,0 +1,205 @@ 
+// Utilities used throughout the library -*- C++ -*-
+
+// Copyright (C) 2004-2021 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+// <http://www.gnu.org/licenses/>.
+
+/** @file include/bits/utility.h
+ *  This is an internal header file, included by other library headers.
+ *  Do not attempt to use it directly. @headername{utility}
+ *
+ *  This file contains the parts of `<utility>` needed by other headers,
+ *  so they don't need to include the whole of `<utility>`.
+ */
+
+#ifndef _GLIBCXX_UTILITY_H
+#define _GLIBCXX_UTILITY_H 1
+
+#pragma GCC system_header
+
+#if __cplusplus >= 201103L
+
+#include <type_traits>
+#include <bits/move.h>
+
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+
+  /// Finds the size of a given tuple type.
+  template<typename _Tp>
+    struct tuple_size;
+
+  // _GLIBCXX_RESOLVE_LIB_DEFECTS
+  // 2313. tuple_size should always derive from integral_constant<size_t, N>
+  // 2770. tuple_size<const T> specialization is not SFINAE compatible
+
+  template<typename _Tp,
+	   typename _Up = typename remove_cv<_Tp>::type,
+	   typename = typename enable_if<is_same<_Tp, _Up>::value>::type,
+	   size_t = tuple_size<_Tp>::value>
+    using __enable_if_has_tuple_size = _Tp;
+
+  template<typename _Tp>
+    struct tuple_size<const __enable_if_has_tuple_size<_Tp>>
+    : public tuple_size<_Tp> { };
+
+  template<typename _Tp>
+    struct tuple_size<volatile __enable_if_has_tuple_size<_Tp>>
+    : public tuple_size<_Tp> { };
+
+  template<typename _Tp>
+    struct tuple_size<const volatile __enable_if_has_tuple_size<_Tp>>
+    : public tuple_size<_Tp> { };
+
+  /// Gives the type of the ith element of a given tuple type.
+  template<size_t __i, typename _Tp>
+    struct tuple_element;
+
+  // Duplicate of C++14's tuple_element_t for internal use in C++11 mode
+  template<size_t __i, typename _Tp>
+    using __tuple_element_t = typename tuple_element<__i, _Tp>::type;
+
+  template<size_t __i, typename _Tp>
+    struct tuple_element<__i, const _Tp>
+    {
+      typedef typename add_const<__tuple_element_t<__i, _Tp>>::type type;
+    };
+
+  template<size_t __i, typename _Tp>
+    struct tuple_element<__i, volatile _Tp>
+    {
+      typedef typename add_volatile<__tuple_element_t<__i, _Tp>>::type type;
+    };
+
+  template<size_t __i, typename _Tp>
+    struct tuple_element<__i, const volatile _Tp>
+    {
+      typedef typename add_cv<__tuple_element_t<__i, _Tp>>::type type;
+    };
+
+#if __cplusplus >= 201402L
+// The standard says this macro and alias template should be in <tuple>
+// but we define them here, to be available in <utility> and <array> too.
+#define __cpp_lib_tuple_element_t 201402L
+
+  template<size_t __i, typename _Tp>
+    using tuple_element_t = typename tuple_element<__i, _Tp>::type;
+#endif // C++14
+
+  // Stores a tuple of indices.  Used by tuple and pair, and by bind() to
+  // extract the elements in a tuple.
+  template<size_t... _Indexes> struct _Index_tuple { };
+
+  // Builds an _Index_tuple<0, 1, 2, ..., _Num-1>.
+  template<size_t _Num>
+    struct _Build_index_tuple
+    {
+#if __has_builtin(__make_integer_seq)
+      template<typename, size_t... _Indices>
+	using _IdxTuple = _Index_tuple<_Indices...>;
+
+      // Clang defines __make_integer_seq for this purpose.
+      using __type = __make_integer_seq<_IdxTuple, size_t, _Num>;
+#else
+      // For GCC and other compilers, use __integer_pack instead.
+      using __type = _Index_tuple<__integer_pack(_Num)...>;
+#endif
+    };
+
+#if __cplusplus >= 201402L
+
+#define __cpp_lib_integer_sequence 201304L
+
+  /// Class template integer_sequence
+  template<typename _Tp, _Tp... _Idx>
+    struct integer_sequence
+    {
+      typedef _Tp value_type;
+      static constexpr size_t size() noexcept { return sizeof...(_Idx); }
+    };
+
+  /// Alias template make_integer_sequence
+  template<typename _Tp, _Tp _Num>
+    using make_integer_sequence
+#if __has_builtin(__make_integer_seq)
+      = __make_integer_seq<integer_sequence, _Tp, _Num>;
+#else
+      = integer_sequence<_Tp, __integer_pack(_Num)...>;
+#endif
+
+  /// Alias template index_sequence
+  template<size_t... _Idx>
+    using index_sequence = integer_sequence<size_t, _Idx...>;
+
+  /// Alias template make_index_sequence
+  template<size_t _Num>
+    using make_index_sequence = make_integer_sequence<size_t, _Num>;
+
+  /// Alias template index_sequence_for
+  template<typename... _Types>
+    using index_sequence_for = make_index_sequence<sizeof...(_Types)>;
+
+#if __cplusplus >= 201703L
+
+  //
+  struct in_place_t {
+    explicit in_place_t() = default;
+  };
+
+  inline constexpr in_place_t in_place{};
+
+  template<typename _Tp> struct in_place_type_t
+  {
+    explicit in_place_type_t() = default;
+  };
+
+  template<typename _Tp>
+    inline constexpr in_place_type_t<_Tp> in_place_type{};
+
+  template<size_t _Idx> struct in_place_index_t
+  {
+    explicit in_place_index_t() = default;
+  };
+
+  template<size_t _Idx>
+    inline constexpr in_place_index_t<_Idx> in_place_index{};
+
+  template<typename>
+    struct __is_in_place_type_impl : false_type
+    { };
+
+  template<typename _Tp>
+    struct __is_in_place_type_impl<in_place_type_t<_Tp>> : true_type
+    { };
+
+  template<typename _Tp>
+    struct __is_in_place_type
+      : public __is_in_place_type_impl<_Tp>
+    { };
+#endif // C++17
+#endif // C++14
+
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace
+
+#endif // C++11
+#endif /* _GLIBCXX_UTILITY_H */
diff --git a/libstdc++-v3/include/std/any b/libstdc++-v3/include/std/any
index a6995b79c43..1fce95730ea 100644
--- a/libstdc++-v3/include/std/any
+++ b/libstdc++-v3/include/std/any
@@ -33,10 +33,11 @@ 
 
 #if __cplusplus >= 201703L
 
+#include <initializer_list>
 #include <typeinfo>
 #include <new>
-#include <utility>
 #include <type_traits>
+#include <bits/utility.h> // in_place_type_t
 
 namespace std _GLIBCXX_VISIBILITY(default)
 {
diff --git a/libstdc++-v3/include/std/array b/libstdc++-v3/include/std/array
index 0c6f33e3276..ea8d3cb5f2e 100644
--- a/libstdc++-v3/include/std/array
+++ b/libstdc++-v3/include/std/array
@@ -35,10 +35,14 @@ 
 # include <bits/c++0x_warning.h>
 #else
 
-#include <utility>
+#include <compare>
+#include <initializer_list>
+
+#include <type_traits>
 #include <bits/functexcept.h>
 #include <bits/stl_algobase.h>
-#include <bits/range_access.h>
+#include <bits/range_access.h> // std::begin, std::end etc.
+#include <bits/utility.h>      // std::index_sequence, std::tuple_size
 #include <debug/assertions.h>
 
 namespace std _GLIBCXX_VISIBILITY(default)
@@ -428,28 +432,20 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
   // Tuple interface to class template array.
 
-  /// tuple_size
-  template<typename _Tp>
-    struct tuple_size;
-
   /// Partial specialization for std::array
-  template<typename _Tp, std::size_t _Nm>
+  template<typename _Tp, size_t _Nm>
     struct tuple_size<array<_Tp, _Nm>>
-    : public integral_constant<std::size_t, _Nm> { };
-
-  /// tuple_element
-  template<std::size_t _Int, typename _Tp>
-    struct tuple_element;
+    : public integral_constant<size_t, _Nm> { };
 
   /// Partial specialization for std::array
-  template<std::size_t _Int, typename _Tp, std::size_t _Nm>
-    struct tuple_element<_Int, array<_Tp, _Nm>>
+  template<size_t _Ind, typename _Tp, size_t _Nm>
+    struct tuple_element<_Ind, array<_Tp, _Nm>>
     {
-      static_assert(_Int < _Nm, "index is out of bounds");
-      typedef _Tp type;
+      static_assert(_Ind < _Nm, "array index is in range");
+      using type = _Tp;
     };
 
-  template<typename _Tp, std::size_t _Nm>
+  template<typename _Tp, size_t _Nm>
     struct __is_tuple_like_impl<array<_Tp, _Nm>> : true_type
     { };
 
diff --git a/libstdc++-v3/include/std/memory_resource b/libstdc++-v3/include/std/memory_resource
index df4e806f814..cdc5e5d98b1 100644
--- a/libstdc++-v3/include/std/memory_resource
+++ b/libstdc++-v3/include/std/memory_resource
@@ -38,13 +38,13 @@ 
 #include <shared_mutex>			// shared_mutex
 #include <bits/align.h>			// align
 #include <bits/functexcept.h>		// __throw_bad_array_new_length
-#include <bits/uses_allocator.h>	// __use_alloc
+#include <bits/uses_allocator.h>	// allocator_arg_t, __use_alloc
 #include <bits/uses_allocator_args.h>	// uninitialized_construct_using_alloc
 #include <ext/numeric_traits.h>
 #include <debug/assertions.h>
 
 #if ! __cpp_lib_make_obj_using_allocator
-# include <utility>			// pair, index_sequence
+# include <bits/utility.h>		// index_sequence
 # include <tuple>			// tuple, forward_as_tuple
 #endif
 
@@ -338,10 +338,10 @@  namespace pmr
       { return _M_resource; }
 
     private:
+#if ! __cpp_lib_make_obj_using_allocator
       using __uses_alloc1_ = __uses_alloc1<polymorphic_allocator>;
       using __uses_alloc2_ = __uses_alloc2<polymorphic_allocator>;
 
-#if ! __cpp_lib_make_obj_using_allocator
       template<typename _Ind, typename... _Args>
 	static tuple<_Args&&...>
 	_S_construct_p(__uses_alloc0, _Ind, tuple<_Args...>& __t)
diff --git a/libstdc++-v3/include/std/optional b/libstdc++-v3/include/std/optional
index 0a67ce24bbd..df9ed0736b3 100644
--- a/libstdc++-v3/include/std/optional
+++ b/libstdc++-v3/include/std/optional
@@ -33,14 +33,14 @@ 
 
 #if __cplusplus >= 201703L
 
-#include <utility>
 #include <type_traits>
 #include <exception>
 #include <new>
 #include <initializer_list>
+#include <bits/enable_special_members.h>
 #include <bits/exception_defines.h>
 #include <bits/functional_hash.h>
-#include <bits/enable_special_members.h>
+#include <bits/utility.h> // in_place_t
 #if __cplusplus > 201703L
 # include <compare>
 #endif
diff --git a/libstdc++-v3/include/std/tuple b/libstdc++-v3/include/std/tuple
index 8ee0d2f1ef5..1292aee45c0 100644
--- a/libstdc++-v3/include/std/tuple
+++ b/libstdc++-v3/include/std/tuple
@@ -35,10 +35,10 @@ 
 # include <bits/c++0x_warning.h>
 #else
 
-#include <utility>
-#include <array>
-#include <bits/uses_allocator.h>
-#include <bits/invoke.h>
+#include <bits/stl_pair.h>		// for std::pair
+#include <bits/uses_allocator.h>	// for std::allocator_arg_t
+#include <bits/utility.h>		// for std::get, std::tuple_size etc.
+#include <bits/invoke.h>		// for std::__invoke
 #if __cplusplus > 201703L
 # include <compare>
 # define __cpp_lib_constexpr_tuple 201811L
@@ -1415,7 +1415,7 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
 #if __cplusplus >= 201402L
 
-#define __cpp_lib_tuples_by_type 201304
+#define __cpp_lib_tuples_by_type 201304L
 
   // Return the index of _Tp in _Types, if it occurs exactly once.
   // Otherwise, return sizeof...(_Types).
@@ -1613,6 +1613,28 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
     forward_as_tuple(_Elements&&... __args) noexcept
     { return tuple<_Elements&&...>(std::forward<_Elements>(__args)...); }
 
+  // Declarations of std::array and its std::get overloads, so that
+  // std::tuple_cat can use them if <tuple> is included before <array>.
+
+  template<typename _Tp, size_t _Nm> struct array;
+
+  template<size_t _Int, typename _Tp, size_t _Nm>
+    constexpr _Tp&
+    get(array<_Tp, _Nm>&) noexcept;
+
+  template<size_t _Int, typename _Tp, size_t _Nm>
+    constexpr _Tp&&
+    get(array<_Tp, _Nm>&&) noexcept;
+
+  template<size_t _Int, typename _Tp, size_t _Nm>
+    constexpr const _Tp&
+    get(const array<_Tp, _Nm>&) noexcept;
+
+  template<size_t _Int, typename _Tp, size_t _Nm>
+    constexpr const _Tp&&
+    get(const array<_Tp, _Nm>&&) noexcept;
+
+
   template<size_t, typename, typename, size_t>
     struct __make_tuple_impl;
 
@@ -1721,6 +1743,10 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	}
     };
 
+  template<typename... _Tps>
+    struct __is_tuple_like_impl<tuple<_Tps...>> : true_type
+    { };
+
   /// tuple_cat
   template<typename... _Tpls, typename = typename
            enable_if<__and_<__is_tuple_like<_Tpls>...>::value>::type>
diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 15ec83a06b8..0d821f9c074 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -41,9 +41,6 @@  namespace std _GLIBCXX_VISIBILITY(default)
 {
 _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
-  template<typename... _Elements>
-    class tuple;
-
   template<typename _Tp>
     class reference_wrapper;
 
@@ -2680,10 +2677,6 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
     struct __is_tuple_like_impl : false_type
     { };
 
-  template<typename... _Tps>
-    struct __is_tuple_like_impl<tuple<_Tps...>> : true_type
-    { };
-
   // Internal type trait that allows us to sfinae-protect tuple_cat.
   template<typename _Tp>
     struct __is_tuple_like
diff --git a/libstdc++-v3/include/std/utility b/libstdc++-v3/include/std/utility
index 3e68f682e00..c2697f87dc5 100644
--- a/libstdc++-v3/include/std/utility
+++ b/libstdc++-v3/include/std/utility
@@ -60,9 +60,8 @@ 
 /**
  * @defgroup utilities Utilities
  *
- * Components deemed generally useful. Includes pair, tuple,
- * forward/move helpers, ratio, function object, metaprogramming and
- * type traits, time, date, and memory functions.
+ * Basic function and class templates used with the rest of the library.
+ * Includes pair, swap, forward/move helpers, declval, integer_sequence.
  */
 
 #include <bits/c++config.h>
@@ -71,218 +70,21 @@ 
 
 #if __cplusplus >= 201103L
 
+#include <initializer_list>
 #include <type_traits>
 #include <bits/move.h>
-#include <initializer_list>
+#include <bits/utility.h>
 
-#if __cplusplus > 201703L
-#include <ext/numeric_traits.h>
+#if __cplusplus >= 202002L
+#include <ext/numeric_traits.h> // __is_standard_integer, __int_traits
 #endif
 
 namespace std _GLIBCXX_VISIBILITY(default)
 {
 _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
-  /// Finds the size of a given tuple type.
-  template<typename _Tp>
-    struct tuple_size;
-
-  // _GLIBCXX_RESOLVE_LIB_DEFECTS
-  // 2313. tuple_size should always derive from integral_constant<size_t, N>
-  // 2770. tuple_size<const T> specialization is not SFINAE compatible
-
-  template<typename _Tp,
-	   typename _Up = typename remove_cv<_Tp>::type,
-	   typename = typename enable_if<is_same<_Tp, _Up>::value>::type,
-	   size_t = tuple_size<_Tp>::value>
-    using __enable_if_has_tuple_size = _Tp;
-
-  template<typename _Tp>
-    struct tuple_size<const __enable_if_has_tuple_size<_Tp>>
-    : public tuple_size<_Tp> { };
-
-  template<typename _Tp>
-    struct tuple_size<volatile __enable_if_has_tuple_size<_Tp>>
-    : public tuple_size<_Tp> { };
-
-  template<typename _Tp>
-    struct tuple_size<const volatile __enable_if_has_tuple_size<_Tp>>
-    : public tuple_size<_Tp> { };
-
-  /// Gives the type of the ith element of a given tuple type.
-  template<size_t __i, typename _Tp>
-    struct tuple_element;
-
-  // Duplicate of C++14's tuple_element_t for internal use in C++11 mode
-  template<size_t __i, typename _Tp>
-    using __tuple_element_t = typename tuple_element<__i, _Tp>::type;
-
-  template<size_t __i, typename _Tp>
-    struct tuple_element<__i, const _Tp>
-    {
-      typedef typename add_const<__tuple_element_t<__i, _Tp>>::type type;
-    };
-
-  template<size_t __i, typename _Tp>
-    struct tuple_element<__i, volatile _Tp>
-    {
-      typedef typename add_volatile<__tuple_element_t<__i, _Tp>>::type type;
-    };
-
-  template<size_t __i, typename _Tp>
-    struct tuple_element<__i, const volatile _Tp>
-    {
-      typedef typename add_cv<__tuple_element_t<__i, _Tp>>::type type;
-    };
-
 #if __cplusplus >= 201402L
-// The standard says this macro and alias template should be in <tuple>
-// but we define them here, to be available when the partial specializations
-// of tuple_element<pair<T,U>> and tuple_element<array<T,N>> are defined.
-#define __cpp_lib_tuple_element_t 201402L
-
-  template<size_t __i, typename _Tp>
-    using tuple_element_t = typename tuple_element<__i, _Tp>::type;
-#endif
-
-  // Various functions which give std::pair a tuple-like interface.
-
-  /// Partial specialization for std::pair
-  template<typename _T1, typename _T2>
-    struct __is_tuple_like_impl<pair<_T1, _T2>> : true_type
-    { };
-
-  /// Partial specialization for std::pair
-  template<class _Tp1, class _Tp2>
-    struct tuple_size<pair<_Tp1, _Tp2>>
-    : public integral_constant<size_t, 2> { };
-
-  /// Partial specialization for std::pair
-  template<class _Tp1, class _Tp2>
-    struct tuple_element<0, pair<_Tp1, _Tp2>>
-    { typedef _Tp1 type; };
-
-  /// Partial specialization for std::pair
-  template<class _Tp1, class _Tp2>
-    struct tuple_element<1, pair<_Tp1, _Tp2>>
-    { typedef _Tp2 type; };
-
-  template<size_t _Int>
-    struct __pair_get;
-
-  template<>
-    struct __pair_get<0>
-    {
-      template<typename _Tp1, typename _Tp2>
-	static constexpr _Tp1&
-	__get(pair<_Tp1, _Tp2>& __pair) noexcept
-	{ return __pair.first; }
-
-      template<typename _Tp1, typename _Tp2>
-	static constexpr _Tp1&&
-	__move_get(pair<_Tp1, _Tp2>&& __pair) noexcept
-	{ return std::forward<_Tp1>(__pair.first); }
-
-      template<typename _Tp1, typename _Tp2>
-	static constexpr const _Tp1&
-	__const_get(const pair<_Tp1, _Tp2>& __pair) noexcept
-	{ return __pair.first; }
-
-      template<typename _Tp1, typename _Tp2>
-	static constexpr const _Tp1&&
-	__const_move_get(const pair<_Tp1, _Tp2>&& __pair) noexcept
-	{ return std::forward<const _Tp1>(__pair.first); }
-    };
-
-  template<>
-    struct __pair_get<1>
-    {
-      template<typename _Tp1, typename _Tp2>
-	static constexpr _Tp2&
-	__get(pair<_Tp1, _Tp2>& __pair) noexcept
-	{ return __pair.second; }
-
-      template<typename _Tp1, typename _Tp2>
-	static constexpr _Tp2&&
-	__move_get(pair<_Tp1, _Tp2>&& __pair) noexcept
-	{ return std::forward<_Tp2>(__pair.second); }
-
-      template<typename _Tp1, typename _Tp2>
-	static constexpr const _Tp2&
-	__const_get(const pair<_Tp1, _Tp2>& __pair) noexcept
-	{ return __pair.second; }
-
-      template<typename _Tp1, typename _Tp2>
-	static constexpr const _Tp2&&
-	__const_move_get(const pair<_Tp1, _Tp2>&& __pair) noexcept
-	{ return std::forward<const _Tp2>(__pair.second); }
-    };
-
-  template<size_t _Int, class _Tp1, class _Tp2>
-    constexpr typename tuple_element<_Int, pair<_Tp1, _Tp2>>::type&
-    get(pair<_Tp1, _Tp2>& __in) noexcept
-    { return __pair_get<_Int>::__get(__in); }
-
-  template<size_t _Int, class _Tp1, class _Tp2>
-    constexpr typename tuple_element<_Int, pair<_Tp1, _Tp2>>::type&&
-    get(pair<_Tp1, _Tp2>&& __in) noexcept
-    { return __pair_get<_Int>::__move_get(std::move(__in)); }
-
-  template<size_t _Int, class _Tp1, class _Tp2>
-    constexpr const typename tuple_element<_Int, pair<_Tp1, _Tp2>>::type&
-    get(const pair<_Tp1, _Tp2>& __in) noexcept
-    { return __pair_get<_Int>::__const_get(__in); }
-
-  template<size_t _Int, class _Tp1, class _Tp2>
-    constexpr const typename tuple_element<_Int, pair<_Tp1, _Tp2>>::type&&
-    get(const pair<_Tp1, _Tp2>&& __in) noexcept
-    { return __pair_get<_Int>::__const_move_get(std::move(__in)); }
-
-#if __cplusplus >= 201402L
-
-#define __cpp_lib_tuples_by_type 201304
-
-  template <typename _Tp, typename _Up>
-    constexpr _Tp&
-    get(pair<_Tp, _Up>& __p) noexcept
-    { return __p.first; }
-
-  template <typename _Tp, typename _Up>
-    constexpr const _Tp&
-    get(const pair<_Tp, _Up>& __p) noexcept
-    { return __p.first; }
-
-  template <typename _Tp, typename _Up>
-    constexpr _Tp&&
-    get(pair<_Tp, _Up>&& __p) noexcept
-    { return std::move(__p.first); }
-
-  template <typename _Tp, typename _Up>
-    constexpr const _Tp&&
-    get(const pair<_Tp, _Up>&& __p) noexcept
-    { return std::move(__p.first); }
-
-  template <typename _Tp, typename _Up>
-    constexpr _Tp&
-    get(pair<_Up, _Tp>& __p) noexcept
-    { return __p.second; }
-
-  template <typename _Tp, typename _Up>
-    constexpr const _Tp&
-    get(const pair<_Up, _Tp>& __p) noexcept
-    { return __p.second; }
-
-  template <typename _Tp, typename _Up>
-    constexpr _Tp&&
-    get(pair<_Up, _Tp>&& __p) noexcept
-    { return std::move(__p.second); }
-
-  template <typename _Tp, typename _Up>
-    constexpr const _Tp&&
-    get(const pair<_Up, _Tp>&& __p) noexcept
-    { return std::move(__p.second); }
-
-#define __cpp_lib_exchange_function 201304
+#define __cpp_lib_exchange_function 201304L
 
   /// Assign @p __new_val to @p __obj and return its previous value.
   template <typename _Tp, typename _Up = _Tp>
@@ -291,100 +93,9 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
     exchange(_Tp& __obj, _Up&& __new_val)
     { return std::__exchange(__obj, std::forward<_Up>(__new_val)); }
 
-#endif // C++14
+#if __cplusplus >= 201703L
 
-  // Stores a tuple of indices.  Used by tuple and pair, and by bind() to
-  // extract the elements in a tuple.
-  template<size_t... _Indexes> struct _Index_tuple { };
-
-  // Builds an _Index_tuple<0, 1, 2, ..., _Num-1>.
-  template<size_t _Num>
-    struct _Build_index_tuple
-    {
-#if __has_builtin(__make_integer_seq)
-      template<typename, size_t... _Indices>
-        using _IdxTuple = _Index_tuple<_Indices...>;
-
-      // Clang defines __make_integer_seq for this purpose.
-      using __type = __make_integer_seq<_IdxTuple, size_t, _Num>;
-#else
-      // For GCC and other compilers, use __integer_pack instead.
-      using __type = _Index_tuple<__integer_pack(_Num)...>;
-#endif
-    };
-
-#if __cplusplus >= 201402L
-
-#define __cpp_lib_integer_sequence 201304
-
-  /// Class template integer_sequence
-  template<typename _Tp, _Tp... _Idx>
-    struct integer_sequence
-    {
-      typedef _Tp value_type;
-      static constexpr size_t size() noexcept { return sizeof...(_Idx); }
-    };
-
-  /// Alias template make_integer_sequence
-  template<typename _Tp, _Tp _Num>
-    using make_integer_sequence
-#if __has_builtin(__make_integer_seq)
-      = __make_integer_seq<integer_sequence, _Tp, _Num>;
-#else
-      = integer_sequence<_Tp, __integer_pack(_Num)...>;
-#endif
-
-  /// Alias template index_sequence
-  template<size_t... _Idx>
-    using index_sequence = integer_sequence<size_t, _Idx...>;
-
-  /// Alias template make_index_sequence
-  template<size_t _Num>
-    using make_index_sequence = make_integer_sequence<size_t, _Num>;
-
-  /// Alias template index_sequence_for
-  template<typename... _Types>
-    using index_sequence_for = make_index_sequence<sizeof...(_Types)>;
-#endif
-
-#if __cplusplus > 201402L
-
-  struct in_place_t {
-    explicit in_place_t() = default;
-  };
-
-  inline constexpr in_place_t in_place{};
-
-  template<typename _Tp> struct in_place_type_t
-  {
-    explicit in_place_type_t() = default;
-  };
-
-  template<typename _Tp>
-    inline constexpr in_place_type_t<_Tp> in_place_type{};
-
-  template<size_t _Idx> struct in_place_index_t
-  {
-    explicit in_place_index_t() = default;
-  };
-
-  template<size_t _Idx>
-    inline constexpr in_place_index_t<_Idx> in_place_index{};
-
-  template<typename>
-    struct __is_in_place_type_impl : false_type
-    { };
-
-  template<typename _Tp>
-    struct __is_in_place_type_impl<in_place_type_t<_Tp>> : true_type
-    { };
-
-  template<typename _Tp>
-    struct __is_in_place_type
-      : public __is_in_place_type_impl<_Tp>
-    { };
-
-#define  __cpp_lib_as_const 201510
+#define  __cpp_lib_as_const 201510L
   template<typename _Tp>
     [[nodiscard]]
     constexpr add_const_t<_Tp>&
@@ -476,6 +187,7 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #endif // C++23
 #endif // C++20
 #endif // C++17
+#endif // C++14
 
 _GLIBCXX_END_NAMESPACE_VERSION
 } // namespace
diff --git a/libstdc++-v3/include/std/variant b/libstdc++-v3/include/std/variant
index a4e038e0ec8..6383cf4e502 100644
--- a/libstdc++-v3/include/std/variant
+++ b/libstdc++-v3/include/std/variant
@@ -33,11 +33,10 @@ 
 
 #if __cplusplus >= 201703L
 
+#include <initializer_list>
 #include <type_traits>
-#include <utility>
 #include <bits/enable_special_members.h>
-#include <bits/functexcept.h>
-#include <bits/move.h>
+#include <bits/exception_defines.h>
 #include <bits/functional_hash.h>
 #include <bits/invoke.h>
 #include <ext/aligned_buffer.h>
@@ -45,6 +44,7 @@ 
 #include <bits/stl_iterator_base_types.h>
 #include <bits/stl_iterator_base_funcs.h>
 #include <bits/stl_construct.h>
+#include <bits/utility.h> // in_place_index_t
 #if __cplusplus > 201703L
 # include <compare>
 #endif
diff --git a/libstdc++-v3/include/std/version b/libstdc++-v3/include/std/version
index 27bcd32cb60..d5fa38d7786 100644
--- a/libstdc++-v3/include/std/version
+++ b/libstdc++-v3/include/std/version
@@ -94,7 +94,7 @@ 
 # define __cpp_lib_string_udls 201304
 # define __cpp_lib_transparent_operators 201510
 # define __cpp_lib_tuple_element_t 201402L
-# define __cpp_lib_tuples_by_type 201304
+# define __cpp_lib_tuples_by_type 201304L
 #endif
 
 #if __cplusplus >= 201703L
diff --git a/libstdc++-v3/testsuite/20_util/optional/84601.cc b/libstdc++-v3/testsuite/20_util/optional/84601.cc
index ddac999d49e..fbfa8fdeebf 100644
--- a/libstdc++-v3/testsuite/20_util/optional/84601.cc
+++ b/libstdc++-v3/testsuite/20_util/optional/84601.cc
@@ -1,6 +1,7 @@ 
 // { dg-do compile { target c++17 }  }
 
 #include <optional>
+#include <utility>
 
 using pair_t = std::pair<int, int>;
 using opt_t = std::optional<pair_t>;
diff --git a/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_fill/constrained.cc b/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_fill/constrained.cc
index bb980a91b0e..bce65cf0807 100644
--- a/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_fill/constrained.cc
+++ b/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_fill/constrained.cc
@@ -25,6 +25,7 @@ 
 #include <span>
 #include <string>
 #include <vector>
+#include <utility>
 
 #include <testsuite_hooks.h>
 #include <testsuite_iterators.h>
diff --git a/libstdc++-v3/testsuite/23_containers/array/tuple_interface/get_neg.cc b/libstdc++-v3/testsuite/23_containers/array/tuple_interface/get_neg.cc
index 2875f30011b..423594dd2b3 100644
--- a/libstdc++-v3/testsuite/23_containers/array/tuple_interface/get_neg.cc
+++ b/libstdc++-v3/testsuite/23_containers/array/tuple_interface/get_neg.cc
@@ -26,6 +26,6 @@  int n1 = std::get<1>(a);
 int n2 = std::get<1>(std::move(a));
 int n3 = std::get<1>(ca);
 
-// { dg-error "static assertion failed" "" { target *-*-* } 363 }
-// { dg-error "static assertion failed" "" { target *-*-* } 371 }
-// { dg-error "static assertion failed" "" { target *-*-* } 379 }
+// { dg-error "static assertion failed" "" { target *-*-* } 367 }
+// { dg-error "static assertion failed" "" { target *-*-* } 375 }
+// { dg-error "static assertion failed" "" { target *-*-* } 383 }
diff --git a/libstdc++-v3/testsuite/std/ranges/access/cbegin.cc b/libstdc++-v3/testsuite/std/ranges/access/cbegin.cc
index ed80af589cf..7941563b124 100644
--- a/libstdc++-v3/testsuite/std/ranges/access/cbegin.cc
+++ b/libstdc++-v3/testsuite/std/ranges/access/cbegin.cc
@@ -19,6 +19,7 @@ 
 // { dg-do run { target c++2a } }
 
 #include <ranges>
+#include <utility> // as_const
 #include <testsuite_hooks.h>
 #include <testsuite_iterators.h>
 
diff --git a/libstdc++-v3/testsuite/std/ranges/access/cend.cc b/libstdc++-v3/testsuite/std/ranges/access/cend.cc
index 3e685ae9ce2..135bda80a6a 100644
--- a/libstdc++-v3/testsuite/std/ranges/access/cend.cc
+++ b/libstdc++-v3/testsuite/std/ranges/access/cend.cc
@@ -19,6 +19,7 @@ 
 // { dg-do run { target c++2a } }
 
 #include <ranges>
+#include <utility> // as_const
 #include <testsuite_hooks.h>
 #include <testsuite_iterators.h>
 
diff --git a/libstdc++-v3/testsuite/std/ranges/access/end.cc b/libstdc++-v3/testsuite/std/ranges/access/end.cc
index 25f21c75afc..7321a3088a4 100644
--- a/libstdc++-v3/testsuite/std/ranges/access/end.cc
+++ b/libstdc++-v3/testsuite/std/ranges/access/end.cc
@@ -19,6 +19,7 @@ 
 // { dg-do run { target c++2a } }
 
 #include <ranges>
+#include <utility> // as_const
 #include <testsuite_hooks.h>
 #include <testsuite_iterators.h>
 
diff --git a/libstdc++-v3/testsuite/std/ranges/single_view.cc b/libstdc++-v3/testsuite/std/ranges/single_view.cc
index f1d8e103715..fe03cccf9cc 100644
--- a/libstdc++-v3/testsuite/std/ranges/single_view.cc
+++ b/libstdc++-v3/testsuite/std/ranges/single_view.cc
@@ -19,6 +19,7 @@ 
 // { dg-do run { target c++2a } }
 
 #include <ranges>
+#include <utility> // as_const
 #include <testsuite_hooks.h>
 
 void