public inbox for libstdc++@gcc.gnu.org
 help / color / mirror / Atom feed
* [committed] [1/2] libstdc++: Reduce header dependencies on <array> and <utility>
@ 2021-07-27 12:15 Jonathan Wakely
  2021-07-27 12:16 ` [committed] [2/2] libstdc++: Remove unnecessary uses of <utility> Jonathan Wakely
  0 siblings, 1 reply; 3+ messages in thread
From: Jonathan Wakely @ 2021-07-27 12:15 UTC (permalink / raw)
  To: libstdc++, gcc-patches

[-- Attachment #1: Type: text/plain, Size: 2602 bytes --]

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.


[-- Attachment #2: patch.txt --]
[-- Type: text/plain, Size: 38980 bytes --]

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 --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

^ permalink raw reply	[flat|nested] 3+ messages in thread

* [committed] [2/2] libstdc++: Remove unnecessary uses of <utility>
  2021-07-27 12:15 [committed] [1/2] libstdc++: Reduce header dependencies on <array> and <utility> Jonathan Wakely
@ 2021-07-27 12:16 ` Jonathan Wakely
  2021-07-27 20:38   ` [committed] [3/2] testsuite: Add missing C++ includes to tests [PR101646] Jonathan Wakely
  0 siblings, 1 reply; 3+ messages in thread
From: Jonathan Wakely @ 2021-07-27 12:16 UTC (permalink / raw)
  To: libstdc++, gcc-patches

[-- Attachment #1: Type: text/plain, Size: 2536 bytes --]

The <algorithm> header includes <utility>, with a comment referring to
UK-300, a National Body comment on the C++11 draft. That comment
proposed to move std::swap to <utility> and then require <algorithm> to
include <utility>. The comment was rejected, so we do not need to
implement the suggestion. For backwards compatibility with C++03 we do
want <algorithm> to define std::swap, but it does so anyway via
<bits/move.h>. We don't need the whole of <utility> to do that.

A few other headers that need std::swap can include <bits/move.h> to
get it, instead of <utility>.

There are several headers that include <utility> to get std::pair, but
they can use <bits/stl_pair.h> to get it without also including the
rel_ops namespace and other contents of <utility>.

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

libstdc++-v3/ChangeLog:

         * include/std/algorithm: Do not include <utility>.
         * include/std/functional: Likewise.
         * include/std/regex: Include <bits/stl_pair.h> instead of
         <utility>.
         * include/debug/map.h: Likewise.
         * include/debug/multimap.h: Likewise.
         * include/debug/multiset.h: Likewise.
         * include/debug/set.h: Likewise.
         * include/debug/vector: Likewise.
         * include/bits/fs_path.h: Likewise.
         * include/bits/unique_ptr.h: Do not include <utility>.
         * include/experimental/any: Likewise.
         * include/experimental/executor: Likewise.
         * include/experimental/memory: Likewise.
         * include/experimental/optional: Likewise.
         * include/experimental/socket: Use __exchange instead
         of std::exchange.
         * src/filesystem/ops-common.h: Likewise.
         * testsuite/20_util/default_delete/48631_neg.cc: Adjust expected
         errors to not use a hardcoded line number.
         * testsuite/20_util/default_delete/void_neg.cc: Likewise.
         * testsuite/20_util/specialized_algorithms/uninitialized_copy/constrained.cc:
         Include <utility> for std::as_const.
         * testsuite/20_util/specialized_algorithms/uninitialized_default_construct/constrained.cc:
         Likewise.
         * testsuite/20_util/specialized_algorithms/uninitialized_move/constrained.cc:
         Likewise.
         * testsuite/20_util/specialized_algorithms/uninitialized_value_construct/constrained.cc:
         Likewise.
         * testsuite/23_containers/vector/cons/destructible_debug_neg.cc:
         Adjust dg-error line number.


Tested powerpc64le-linux. Committed to trunk.



[-- Attachment #2: patch.txt --]
[-- Type: text/x-patch, Size: 15274 bytes --]

commit 16158c96496b537194111526d25e19f268d613b6
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Thu Jul 22 14:48:27 2021

    libstdc++: Remove unnecessary uses of <utility>
    
    The <algorithm> header includes <utility>, with a comment referring to
    UK-300, a National Body comment on the C++11 draft. That comment
    proposed to move std::swap to <utility> and then require <algorithm> to
    include <utility>. The comment was rejected, so we do not need to
    implement the suggestion. For backwards compatibility with C++03 we do
    want <algorithm> to define std::swap, but it does so anyway via
    <bits/move.h>. We don't need the whole of <utility> to do that.
    
    A few other headers that need std::swap can include <bits/move.h> to
    get it, instead of <utility>.
    
    There are several headers that include <utility> to get std::pair, but
    they can use <bits/stl_pair.h> to get it without also including the
    rel_ops namespace and other contents of <utility>.
    
    Signed-off-by: Jonathan Wakely <jwakely@redhat.com>
    
    libstdc++-v3/ChangeLog:
    
            * include/std/algorithm: Do not include <utility>.
            * include/std/functional: Likewise.
            * include/std/regex: Include <bits/stl_pair.h> instead of
            <utility>.
            * include/debug/map.h: Likewise.
            * include/debug/multimap.h: Likewise.
            * include/debug/multiset.h: Likewise.
            * include/debug/set.h: Likewise.
            * include/debug/vector: Likewise.
            * include/bits/fs_path.h: Likewise.
            * include/bits/unique_ptr.h: Do not include <utility>.
            * include/experimental/any: Likewise.
            * include/experimental/executor: Likewise.
            * include/experimental/memory: Likewise.
            * include/experimental/optional: Likewise.
            * include/experimental/socket: Use __exchange instead
            of std::exchange.
            * src/filesystem/ops-common.h: Likewise.
            * testsuite/20_util/default_delete/48631_neg.cc: Adjust expected
            errors to not use a hardcoded line number.
            * testsuite/20_util/default_delete/void_neg.cc: Likewise.
            * testsuite/20_util/specialized_algorithms/uninitialized_copy/constrained.cc:
            Include <utility> for std::as_const.
            * testsuite/20_util/specialized_algorithms/uninitialized_default_construct/constrained.cc:
            Likewise.
            * testsuite/20_util/specialized_algorithms/uninitialized_move/constrained.cc:
            Likewise.
            * testsuite/20_util/specialized_algorithms/uninitialized_value_construct/constrained.cc:
            Likewise.
            * testsuite/23_containers/vector/cons/destructible_debug_neg.cc:
            Adjust dg-error line number.

diff --git a/libstdc++-v3/include/bits/fs_path.h b/libstdc++-v3/include/bits/fs_path.h
index 4fcd1def92f..3151af1e901 100644
--- a/libstdc++-v3/include/bits/fs_path.h
+++ b/libstdc++-v3/include/bits/fs_path.h
@@ -32,7 +32,6 @@
 
 #if __cplusplus >= 201703L
 
-#include <utility>
 #include <type_traits>
 #include <locale>
 #include <iosfwd>
@@ -41,6 +40,7 @@
 #include <string_view>
 #include <system_error>
 #include <bits/stl_algobase.h>
+#include <bits/stl_pair.h>
 #include <bits/locale_conv.h>
 #include <ext/concurrence.h>
 #include <bits/shared_ptr.h>
diff --git a/libstdc++-v3/include/bits/unique_ptr.h b/libstdc++-v3/include/bits/unique_ptr.h
index 0a0667a7608..2d8b9ed3fae 100644
--- a/libstdc++-v3/include/bits/unique_ptr.h
+++ b/libstdc++-v3/include/bits/unique_ptr.h
@@ -33,7 +33,6 @@
 #include <bits/c++config.h>
 #include <debug/assertions.h>
 #include <type_traits>
-#include <utility>
 #include <tuple>
 #include <bits/stl_function.h>
 #include <bits/functional_hash.h>
diff --git a/libstdc++-v3/include/debug/map.h b/libstdc++-v3/include/debug/map.h
index ab34b2affd9..c0153d09abe 100644
--- a/libstdc++-v3/include/debug/map.h
+++ b/libstdc++-v3/include/debug/map.h
@@ -32,7 +32,7 @@
 #include <debug/safe_sequence.h>
 #include <debug/safe_container.h>
 #include <debug/safe_iterator.h>
-#include <utility>
+#include <bits/stl_pair.h>
 
 namespace std _GLIBCXX_VISIBILITY(default)
 {
diff --git a/libstdc++-v3/include/debug/multimap.h b/libstdc++-v3/include/debug/multimap.h
index 96a44f4725f..94929344a9d 100644
--- a/libstdc++-v3/include/debug/multimap.h
+++ b/libstdc++-v3/include/debug/multimap.h
@@ -32,7 +32,7 @@
 #include <debug/safe_sequence.h>
 #include <debug/safe_container.h>
 #include <debug/safe_iterator.h>
-#include <utility>
+#include <bits/stl_pair.h>
 
 namespace std _GLIBCXX_VISIBILITY(default)
 {
diff --git a/libstdc++-v3/include/debug/multiset.h b/libstdc++-v3/include/debug/multiset.h
index 0e76c5ff332..bb68d8c8f18 100644
--- a/libstdc++-v3/include/debug/multiset.h
+++ b/libstdc++-v3/include/debug/multiset.h
@@ -32,7 +32,7 @@
 #include <debug/safe_sequence.h>
 #include <debug/safe_container.h>
 #include <debug/safe_iterator.h>
-#include <utility>
+#include <bits/stl_pair.h>
 
 namespace std _GLIBCXX_VISIBILITY(default)
 {
diff --git a/libstdc++-v3/include/debug/set.h b/libstdc++-v3/include/debug/set.h
index c579de7426d..cdf35ea5396 100644
--- a/libstdc++-v3/include/debug/set.h
+++ b/libstdc++-v3/include/debug/set.h
@@ -32,7 +32,7 @@
 #include <debug/safe_sequence.h>
 #include <debug/safe_container.h>
 #include <debug/safe_iterator.h>
-#include <utility>
+#include <bits/stl_pair.h>
 
 namespace std _GLIBCXX_VISIBILITY(default)
 {
diff --git a/libstdc++-v3/include/debug/vector b/libstdc++-v3/include/debug/vector
index 987bba17c2b..79ccf527dd6 100644
--- a/libstdc++-v3/include/debug/vector
+++ b/libstdc++-v3/include/debug/vector
@@ -37,7 +37,6 @@ namespace std _GLIBCXX_VISIBILITY(default) { namespace __debug {
 } } // namespace std::__debug
 
 #include <vector>
-#include <utility>
 #include <debug/safe_sequence.h>
 #include <debug/safe_container.h>
 #include <debug/safe_iterator.h>
diff --git a/libstdc++-v3/include/experimental/any b/libstdc++-v3/include/experimental/any
index 3bb3e8c4a0a..7d18f267e8b 100644
--- a/libstdc++-v3/include/experimental/any
+++ b/libstdc++-v3/include/experimental/any
@@ -36,8 +36,8 @@
 
 #include <typeinfo>
 #include <new>
-#include <utility>
 #include <type_traits>
+#include <bits/move.h>
 #include <experimental/bits/lfts_config.h>
 
 namespace std _GLIBCXX_VISIBILITY(default)
diff --git a/libstdc++-v3/include/experimental/executor b/libstdc++-v3/include/experimental/executor
index c670f2739b6..4322a7f5caf 100644
--- a/libstdc++-v3/include/experimental/executor
+++ b/libstdc++-v3/include/experimental/executor
@@ -43,7 +43,6 @@
 #include <thread>
 #include <tuple>
 #include <unordered_map>
-#include <utility>
 #include <experimental/netfwd>
 #include <bits/unique_ptr.h>
 #include <experimental/bits/net.h>
diff --git a/libstdc++-v3/include/experimental/memory b/libstdc++-v3/include/experimental/memory
index a74b2402f7a..a89a5ecfa84 100644
--- a/libstdc++-v3/include/experimental/memory
+++ b/libstdc++-v3/include/experimental/memory
@@ -40,7 +40,6 @@
 
 #include <memory>
 #include <type_traits>
-#include <utility>
 #include <experimental/bits/shared_ptr.h>
 #include <bits/functional_hash.h>
 
diff --git a/libstdc++-v3/include/experimental/optional b/libstdc++-v3/include/experimental/optional
index ae2418f0500..431d23631cf 100644
--- a/libstdc++-v3/include/experimental/optional
+++ b/libstdc++-v3/include/experimental/optional
@@ -32,7 +32,6 @@
 
 #if __cplusplus >= 201402L
 
-#include <utility>
 #include <type_traits>
 #include <stdexcept>
 #include <new>
@@ -40,6 +39,7 @@
 #include <bits/functexcept.h>
 #include <bits/functional_hash.h>
 #include <bits/enable_special_members.h>
+#include <bits/move.h>
 #include <experimental/bits/lfts_config.h>
 
 namespace std _GLIBCXX_VISIBILITY(default)
diff --git a/libstdc++-v3/include/experimental/socket b/libstdc++-v3/include/experimental/socket
index 9db4a245ccf..6d1c114254a 100644
--- a/libstdc++-v3/include/experimental/socket
+++ b/libstdc++-v3/include/experimental/socket
@@ -429,16 +429,16 @@ inline namespace v1
 
     __socket_impl(__socket_impl&& __rhs)
     : _M_ctx(__rhs._M_ctx),
-      _M_sockfd(std::exchange(__rhs._M_sockfd, -1)),
-      _M_bits(std::exchange(__rhs._M_bits, {}))
+      _M_sockfd(std::__exchange(__rhs._M_sockfd, -1)),
+      _M_bits(std::__exchange(__rhs._M_bits, {}))
     { }
 
     __socket_impl&
     operator=(__socket_impl&& __rhs)
     {
       _M_ctx = __rhs._M_ctx;
-      _M_sockfd = std::exchange(__rhs._M_sockfd, -1);
-      _M_bits = std::exchange(__rhs._M_bits, {});
+      _M_sockfd = std::__exchange(__rhs._M_sockfd, -1);
+      _M_bits = std::__exchange(__rhs._M_bits, {});
       return *this;
     }
 
@@ -615,7 +615,7 @@ inline namespace v1
       {
 	__glibcxx_assert(is_open());
 	cancel(__ec);
-	return std::exchange(_M_sockfd, -1);
+	return std::__exchange(_M_sockfd, -1);
       }
 
       template<typename _SettableSocketOption>
diff --git a/libstdc++-v3/include/std/algorithm b/libstdc++-v3/include/std/algorithm
index 9ce4aa8423d..c9df7eae1ff 100644
--- a/libstdc++-v3/include/std/algorithm
+++ b/libstdc++-v3/include/std/algorithm
@@ -57,7 +57,6 @@
 
 #pragma GCC system_header
 
-#include <utility> // UK-300.
 #include <bits/stl_algobase.h>
 #include <bits/stl_algo.h>
 #if __cplusplus > 201703L
diff --git a/libstdc++-v3/include/std/functional b/libstdc++-v3/include/std/functional
index f61f2ac8cfd..131e6629341 100644
--- a/libstdc++-v3/include/std/functional
+++ b/libstdc++-v3/include/std/functional
@@ -61,7 +61,6 @@
 # include <unordered_map>
 # include <vector>
 # include <array>
-# include <utility>
 # include <bits/stl_algo.h>
 #endif
 #if __cplusplus > 201703L
diff --git a/libstdc++-v3/include/std/regex b/libstdc++-v3/include/std/regex
index cd33f26af0d..e623a6ed498 100644
--- a/libstdc++-v3/include/std/regex
+++ b/libstdc++-v3/include/std/regex
@@ -47,7 +47,6 @@
 #include <stack>
 #include <stdexcept>
 #include <string>
-#include <utility>
 #include <vector>
 #include <map>
 #include <cstring>
@@ -55,6 +54,7 @@
 #include <ext/aligned_buffer.h>
 #include <ext/numeric_traits.h>
 #include <bits/std_function.h>
+#include <bits/stl_pair.h>
 #include <bits/regex_constants.h>
 #include <bits/regex_error.h>
 #include <bits/regex_automaton.h>
diff --git a/libstdc++-v3/src/filesystem/ops-common.h b/libstdc++-v3/src/filesystem/ops-common.h
index 529d4e09016..43311e6c38f 100644
--- a/libstdc++-v3/src/filesystem/ops-common.h
+++ b/libstdc++-v3/src/filesystem/ops-common.h
@@ -26,6 +26,7 @@
 #define _GLIBCXX_OPS_COMMON_H 1
 
 #include <chrono>
+#include <bits/move.h> // std::__exchange
 
 #ifdef _GLIBCXX_HAVE_UNISTD_H
 # include <unistd.h>
@@ -407,7 +408,7 @@ _GLIBCXX_BEGIN_NAMESPACE_FILESYSTEM
 
     struct CloseFD {
       ~CloseFD() { if (fd != -1) posix::close(fd); }
-      bool close() { return posix::close(std::exchange(fd, -1)) == 0; }
+      bool close() { return posix::close(std::__exchange(fd, -1)) == 0; }
       int fd;
     };
 
diff --git a/libstdc++-v3/testsuite/20_util/default_delete/48631_neg.cc b/libstdc++-v3/testsuite/20_util/default_delete/48631_neg.cc
index 5de981665d9..3e80b73603e 100644
--- a/libstdc++-v3/testsuite/20_util/default_delete/48631_neg.cc
+++ b/libstdc++-v3/testsuite/20_util/default_delete/48631_neg.cc
@@ -26,4 +26,4 @@ struct D : B { };
 D d;
 std::default_delete<B[]> db;
 typedef decltype(db(&d)) type; // { dg-error "no match" }
-// { dg-error "no type" "" { target *-*-* } 116 }
+// { dg-prune-output "no type named 'type' in 'struct std::enable_if" }
diff --git a/libstdc++-v3/testsuite/20_util/default_delete/void_neg.cc b/libstdc++-v3/testsuite/20_util/default_delete/void_neg.cc
index 217c39b5eb4..ac4eabc5341 100644
--- a/libstdc++-v3/testsuite/20_util/default_delete/void_neg.cc
+++ b/libstdc++-v3/testsuite/20_util/default_delete/void_neg.cc
@@ -25,5 +25,5 @@ void test01()
 {
   std::default_delete<void> d;
   d(nullptr);   // { dg-error "here" }
-  // { dg-error "incomplete" "" { target *-*-* } 81 }
+  // { dg-error "delete pointer to incomplete type" "" { target *-*-* } 0 }
 }
diff --git a/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_copy/constrained.cc b/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_copy/constrained.cc
index ac9128e6a00..7946effcf3a 100644
--- a/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_copy/constrained.cc
+++ b/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_copy/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/20_util/specialized_algorithms/uninitialized_default_construct/constrained.cc b/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_default_construct/constrained.cc
index 05824c021a8..7267738a4af 100644
--- a/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_default_construct/constrained.cc
+++ b/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_default_construct/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/20_util/specialized_algorithms/uninitialized_move/constrained.cc b/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_move/constrained.cc
index cc8cf0beef8..8759d042bb6 100644
--- a/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_move/constrained.cc
+++ b/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_move/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/20_util/specialized_algorithms/uninitialized_value_construct/constrained.cc b/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_value_construct/constrained.cc
index efcf138dd5f..164d9ca667b 100644
--- a/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_value_construct/constrained.cc
+++ b/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_value_construct/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/vector/cons/destructible_debug_neg.cc b/libstdc++-v3/testsuite/23_containers/vector/cons/destructible_debug_neg.cc
index 2283d99b260..b85199e693f 100644
--- a/libstdc++-v3/testsuite/23_containers/vector/cons/destructible_debug_neg.cc
+++ b/libstdc++-v3/testsuite/23_containers/vector/cons/destructible_debug_neg.cc
@@ -46,7 +46,7 @@ test02()
 // { dg-error "value type is destructible" "" { target *-*-* } 0 }
 
 // In Debug Mode the "required from here" errors come from <debug/vector>
-// { dg-error "required from here" "" { target *-*-* } 173 }
+// { dg-error "required from here" "" { target *-*-* } 172 }
 
 // Needed because of PR c++/92193
 // { dg-prune-output "deleted function" }

^ permalink raw reply	[flat|nested] 3+ messages in thread

* [committed] [3/2] testsuite: Add missing C++ includes to tests [PR101646]
  2021-07-27 12:16 ` [committed] [2/2] libstdc++: Remove unnecessary uses of <utility> Jonathan Wakely
@ 2021-07-27 20:38   ` Jonathan Wakely
  0 siblings, 0 replies; 3+ messages in thread
From: Jonathan Wakely @ 2021-07-27 20:38 UTC (permalink / raw)
  To: libstdc++, gcc-patches

[-- Attachment #1: Type: text/plain, Size: 280 bytes --]

These tests stopped working after some libstdc++ refactoring, because
they aren't including what they use.

I committed a blank ChangeLog (I did 'git push' when I meant to push
to the compile farm, oops) so I'll fix that tomorrow.

Tested powerpc64le-linux. Committed to trunk.



[-- Attachment #2: patch.txt --]
[-- Type: text/x-patch, Size: 1206 bytes --]

commit b7195fb01fe62a313ae5f7faede698101bdb3025
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Tue Jul 27 21:29:10 2021

    testsuite: Add missing C++ includes to tests [PR101646]
    
    These tests stopped working after some libstdc++ refactoring, because
    they aren't including what they use.
    
    gcc/testsuite/ChangeLog:
    
            PR testsuite/101646
            * g++.dg/coroutines/pr99047.C:
            * g++.dg/pr71655.C:

diff --git a/gcc/testsuite/g++.dg/coroutines/pr99047.C b/gcc/testsuite/g++.dg/coroutines/pr99047.C
index 124633a08e6..05ce08567b2 100644
--- a/gcc/testsuite/g++.dg/coroutines/pr99047.C
+++ b/gcc/testsuite/g++.dg/coroutines/pr99047.C
@@ -1,4 +1,5 @@
 #include <optional>
+#include <utility>
 #include <coroutine>
 
 template <typename T>
diff --git a/gcc/testsuite/g++.dg/pr71655.C b/gcc/testsuite/g++.dg/pr71655.C
index 8ed33711c36..45943060bc5 100644
--- a/gcc/testsuite/g++.dg/pr71655.C
+++ b/gcc/testsuite/g++.dg/pr71655.C
@@ -5,6 +5,7 @@
 
 #include <functional>
 #include <valarray>
+#include <array>
 extern int var_16, le_s5, le_s6, le_s9;
 std::array<std::array<std::array<long, 8>, 4>, 24> v4;
 extern std::array<std::array<int, 48>, 18> v15;

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2021-07-27 20:38 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-07-27 12:15 [committed] [1/2] libstdc++: Reduce header dependencies on <array> and <utility> Jonathan Wakely
2021-07-27 12:16 ` [committed] [2/2] libstdc++: Remove unnecessary uses of <utility> Jonathan Wakely
2021-07-27 20:38   ` [committed] [3/2] testsuite: Add missing C++ includes to tests [PR101646] Jonathan Wakely

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).