public inbox for libstdc++-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc r14-5794] libstdc++: Define std::ranges::to for C++23 (P1206R7) [PR111055]
@ 2023-11-23 17:51 Jonathan Wakely
  0 siblings, 0 replies; only message in thread
From: Jonathan Wakely @ 2023-11-23 17:51 UTC (permalink / raw)
  To: gcc-cvs, libstdc++-cvs

https://gcc.gnu.org/g:7a6a29c455e7755b501c0006e39beb4e56ec2729

commit r14-5794-g7a6a29c455e7755b501c0006e39beb4e56ec2729
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Tue Sep 19 13:23:13 2023 +0100

    libstdc++: Define std::ranges::to for C++23 (P1206R7) [PR111055]
    
    This adds the std::ranges::to functions for C++23. The rest of P1206R7
    is not yet implemented, i.e. the new constructors taking the
    std::from_range tag, and the new insert_range, assign_range, etc. member
    functions. std::ranges::to works with the standard containers even
    without the new constructors, so this is useful immediately.
    
    The __cpp_lib_ranges_to_container feature test macro can be defined now,
    because that only indicates support for the changes in <ranges>, which
    are implemented by this patch. The __cpp_lib_containers_ranges macro
    will be defined once all containers support the new member functions.
    
    libstdc++-v3/ChangeLog:
    
            PR libstdc++/111055
            * include/bits/ranges_base.h (from_range_t): Define new tag
            type.
            (from_range): Define new tag object.
            * include/bits/version.def (ranges_to_container): Define.
            * include/bits/version.h: Regenerate.
            * include/std/ranges (ranges::to): Define.
            * testsuite/std/ranges/conv/1.cc: New test.
            * testsuite/std/ranges/conv/2_neg.cc: New test.
            * testsuite/std/ranges/conv/version.cc: New test.

Diff:
---
 libstdc++-v3/include/bits/ranges_base.h           |   8 +-
 libstdc++-v3/include/bits/version.def             |  34 +-
 libstdc++-v3/include/bits/version.h               | 111 ++++---
 libstdc++-v3/include/std/ranges                   | 361 ++++++++++++++++++++-
 libstdc++-v3/testsuite/std/ranges/conv/1.cc       | 369 ++++++++++++++++++++++
 libstdc++-v3/testsuite/std/ranges/conv/2_neg.cc   |  24 ++
 libstdc++-v3/testsuite/std/ranges/conv/version.cc |  19 ++
 7 files changed, 866 insertions(+), 60 deletions(-)

diff --git a/libstdc++-v3/include/bits/ranges_base.h b/libstdc++-v3/include/bits/ranges_base.h
index 7fa43d1965a..1ca2c5ce2bb 100644
--- a/libstdc++-v3/include/bits/ranges_base.h
+++ b/libstdc++-v3/include/bits/ranges_base.h
@@ -37,6 +37,7 @@
 #include <bits/stl_iterator.h>
 #include <ext/numeric_traits.h>
 #include <bits/max_size_type.h>
+#include <bits/version.h>
 
 #ifdef __cpp_lib_concepts
 namespace std _GLIBCXX_VISIBILITY(default)
@@ -1056,8 +1057,13 @@ namespace ranges
     using borrowed_iterator_t = __conditional_t<borrowed_range<_Range>,
 						iterator_t<_Range>,
 						dangling>;
-
 } // namespace ranges
+
+#if __glibcxx_ranges_to_container // C++ >= 23
+  struct from_range_t { explicit from_range_t() = default; };
+  inline constexpr from_range_t from_range{};
+#endif
+
 _GLIBCXX_END_NAMESPACE_VERSION
 } // namespace std
 #endif // library concepts
diff --git a/libstdc++-v3/include/bits/version.def b/libstdc++-v3/include/bits/version.def
index 605708dfee7..140777832ed 100644
--- a/libstdc++-v3/include/bits/version.def
+++ b/libstdc++-v3/include/bits/version.def
@@ -1439,19 +1439,21 @@ ftms = {
   };
 };
 
-ftms = {
-  name = to_underlying;
-  values = {
-    v = 202102;
-    cxxmin = 23;
-  };
-};
+//ftms = {
+//  name = container_ranges;
+//  values = {
+//    v = 202202;
+//    cxxmin = 23;
+//    hosted = yes;
+//  };
+//};
 
 ftms = {
-  name = unreachable;
+  name = ranges_to_container;
   values = {
     v = 202202;
     cxxmin = 23;
+    hosted = yes;
   };
 };
 
@@ -1683,6 +1685,22 @@ ftms = {
   };
 };
 
+ftms = {
+  name = to_underlying;
+  values = {
+    v = 202102;
+    cxxmin = 23;
+  };
+};
+
+ftms = {
+  name = unreachable;
+  values = {
+    v = 202202;
+    cxxmin = 23;
+  };
+};
+
 ftms = {
   name = fstream_native_handle;
   values = {
diff --git a/libstdc++-v3/include/bits/version.h b/libstdc++-v3/include/bits/version.h
index cacd9375cab..1fb1d148459 100644
--- a/libstdc++-v3/include/bits/version.h
+++ b/libstdc++-v3/include/bits/version.h
@@ -1740,29 +1740,18 @@
 #endif /* !defined(__cpp_lib_reference_from_temporary) && defined(__glibcxx_want_reference_from_temporary) */
 #undef __glibcxx_want_reference_from_temporary
 
-// from version.def line 1443
-#if !defined(__cpp_lib_to_underlying)
-# if (__cplusplus >= 202100L)
-#  define __glibcxx_to_underlying 202102L
-#  if defined(__glibcxx_want_all) || defined(__glibcxx_want_to_underlying)
-#   define __cpp_lib_to_underlying 202102L
-#  endif
-# endif
-#endif /* !defined(__cpp_lib_to_underlying) && defined(__glibcxx_want_to_underlying) */
-#undef __glibcxx_want_to_underlying
-
-// from version.def line 1451
-#if !defined(__cpp_lib_unreachable)
-# if (__cplusplus >= 202100L)
-#  define __glibcxx_unreachable 202202L
-#  if defined(__glibcxx_want_all) || defined(__glibcxx_want_unreachable)
-#   define __cpp_lib_unreachable 202202L
+// from version.def line 1452
+#if !defined(__cpp_lib_ranges_to_container)
+# if (__cplusplus >= 202100L) && _GLIBCXX_HOSTED
+#  define __glibcxx_ranges_to_container 202202L
+#  if defined(__glibcxx_want_all) || defined(__glibcxx_want_ranges_to_container)
+#   define __cpp_lib_ranges_to_container 202202L
 #  endif
 # endif
-#endif /* !defined(__cpp_lib_unreachable) && defined(__glibcxx_want_unreachable) */
-#undef __glibcxx_want_unreachable
+#endif /* !defined(__cpp_lib_ranges_to_container) && defined(__glibcxx_want_ranges_to_container) */
+#undef __glibcxx_want_ranges_to_container
 
-// from version.def line 1459
+// from version.def line 1461
 #if !defined(__cpp_lib_ranges_zip)
 # if (__cplusplus >= 202100L)
 #  define __glibcxx_ranges_zip 202110L
@@ -1773,7 +1762,7 @@
 #endif /* !defined(__cpp_lib_ranges_zip) && defined(__glibcxx_want_ranges_zip) */
 #undef __glibcxx_want_ranges_zip
 
-// from version.def line 1467
+// from version.def line 1469
 #if !defined(__cpp_lib_ranges_chunk)
 # if (__cplusplus >= 202100L)
 #  define __glibcxx_ranges_chunk 202202L
@@ -1784,7 +1773,7 @@
 #endif /* !defined(__cpp_lib_ranges_chunk) && defined(__glibcxx_want_ranges_chunk) */
 #undef __glibcxx_want_ranges_chunk
 
-// from version.def line 1475
+// from version.def line 1477
 #if !defined(__cpp_lib_ranges_slide)
 # if (__cplusplus >= 202100L)
 #  define __glibcxx_ranges_slide 202202L
@@ -1795,7 +1784,7 @@
 #endif /* !defined(__cpp_lib_ranges_slide) && defined(__glibcxx_want_ranges_slide) */
 #undef __glibcxx_want_ranges_slide
 
-// from version.def line 1483
+// from version.def line 1485
 #if !defined(__cpp_lib_ranges_chunk_by)
 # if (__cplusplus >= 202100L)
 #  define __glibcxx_ranges_chunk_by 202202L
@@ -1806,7 +1795,7 @@
 #endif /* !defined(__cpp_lib_ranges_chunk_by) && defined(__glibcxx_want_ranges_chunk_by) */
 #undef __glibcxx_want_ranges_chunk_by
 
-// from version.def line 1491
+// from version.def line 1493
 #if !defined(__cpp_lib_ranges_join_with)
 # if (__cplusplus >= 202100L)
 #  define __glibcxx_ranges_join_with 202202L
@@ -1817,7 +1806,7 @@
 #endif /* !defined(__cpp_lib_ranges_join_with) && defined(__glibcxx_want_ranges_join_with) */
 #undef __glibcxx_want_ranges_join_with
 
-// from version.def line 1499
+// from version.def line 1501
 #if !defined(__cpp_lib_ranges_repeat)
 # if (__cplusplus >= 202100L)
 #  define __glibcxx_ranges_repeat 202207L
@@ -1828,7 +1817,7 @@
 #endif /* !defined(__cpp_lib_ranges_repeat) && defined(__glibcxx_want_ranges_repeat) */
 #undef __glibcxx_want_ranges_repeat
 
-// from version.def line 1507
+// from version.def line 1509
 #if !defined(__cpp_lib_ranges_stride)
 # if (__cplusplus >= 202100L)
 #  define __glibcxx_ranges_stride 202207L
@@ -1839,7 +1828,7 @@
 #endif /* !defined(__cpp_lib_ranges_stride) && defined(__glibcxx_want_ranges_stride) */
 #undef __glibcxx_want_ranges_stride
 
-// from version.def line 1515
+// from version.def line 1517
 #if !defined(__cpp_lib_ranges_cartesian_product)
 # if (__cplusplus >= 202100L)
 #  define __glibcxx_ranges_cartesian_product 202207L
@@ -1850,7 +1839,7 @@
 #endif /* !defined(__cpp_lib_ranges_cartesian_product) && defined(__glibcxx_want_ranges_cartesian_product) */
 #undef __glibcxx_want_ranges_cartesian_product
 
-// from version.def line 1523
+// from version.def line 1525
 #if !defined(__cpp_lib_ranges_as_rvalue)
 # if (__cplusplus >= 202100L)
 #  define __glibcxx_ranges_as_rvalue 202207L
@@ -1861,7 +1850,7 @@
 #endif /* !defined(__cpp_lib_ranges_as_rvalue) && defined(__glibcxx_want_ranges_as_rvalue) */
 #undef __glibcxx_want_ranges_as_rvalue
 
-// from version.def line 1531
+// from version.def line 1533
 #if !defined(__cpp_lib_ranges_as_const)
 # if (__cplusplus >= 202100L)
 #  define __glibcxx_ranges_as_const 202207L
@@ -1872,7 +1861,7 @@
 #endif /* !defined(__cpp_lib_ranges_as_const) && defined(__glibcxx_want_ranges_as_const) */
 #undef __glibcxx_want_ranges_as_const
 
-// from version.def line 1539
+// from version.def line 1541
 #if !defined(__cpp_lib_ranges_enumerate)
 # if (__cplusplus >= 202100L)
 #  define __glibcxx_ranges_enumerate 202302L
@@ -1883,7 +1872,7 @@
 #endif /* !defined(__cpp_lib_ranges_enumerate) && defined(__glibcxx_want_ranges_enumerate) */
 #undef __glibcxx_want_ranges_enumerate
 
-// from version.def line 1547
+// from version.def line 1549
 #if !defined(__cpp_lib_ranges_fold)
 # if (__cplusplus >= 202100L)
 #  define __glibcxx_ranges_fold 202207L
@@ -1894,7 +1883,7 @@
 #endif /* !defined(__cpp_lib_ranges_fold) && defined(__glibcxx_want_ranges_fold) */
 #undef __glibcxx_want_ranges_fold
 
-// from version.def line 1555
+// from version.def line 1557
 #if !defined(__cpp_lib_ranges_contains)
 # if (__cplusplus >= 202100L)
 #  define __glibcxx_ranges_contains 202207L
@@ -1905,7 +1894,7 @@
 #endif /* !defined(__cpp_lib_ranges_contains) && defined(__glibcxx_want_ranges_contains) */
 #undef __glibcxx_want_ranges_contains
 
-// from version.def line 1563
+// from version.def line 1565
 #if !defined(__cpp_lib_ranges_iota)
 # if (__cplusplus >= 202100L)
 #  define __glibcxx_ranges_iota 202202L
@@ -1916,7 +1905,7 @@
 #endif /* !defined(__cpp_lib_ranges_iota) && defined(__glibcxx_want_ranges_iota) */
 #undef __glibcxx_want_ranges_iota
 
-// from version.def line 1571
+// from version.def line 1573
 #if !defined(__cpp_lib_ranges_find_last)
 # if (__cplusplus >= 202100L)
 #  define __glibcxx_ranges_find_last 202207L
@@ -1927,7 +1916,7 @@
 #endif /* !defined(__cpp_lib_ranges_find_last) && defined(__glibcxx_want_ranges_find_last) */
 #undef __glibcxx_want_ranges_find_last
 
-// from version.def line 1579
+// from version.def line 1581
 #if !defined(__cpp_lib_constexpr_bitset)
 # if (__cplusplus >= 202100L) && _GLIBCXX_HOSTED && (__cpp_constexpr_dynamic_alloc)
 #  define __glibcxx_constexpr_bitset 202202L
@@ -1938,7 +1927,7 @@
 #endif /* !defined(__cpp_lib_constexpr_bitset) && defined(__glibcxx_want_constexpr_bitset) */
 #undef __glibcxx_want_constexpr_bitset
 
-// from version.def line 1589
+// from version.def line 1591
 #if !defined(__cpp_lib_stdatomic_h)
 # if (__cplusplus >= 202100L)
 #  define __glibcxx_stdatomic_h 202011L
@@ -1949,7 +1938,7 @@
 #endif /* !defined(__cpp_lib_stdatomic_h) && defined(__glibcxx_want_stdatomic_h) */
 #undef __glibcxx_want_stdatomic_h
 
-// from version.def line 1597
+// from version.def line 1599
 #if !defined(__cpp_lib_adaptor_iterator_pair_constructor)
 # if (__cplusplus >= 202100L) && _GLIBCXX_HOSTED
 #  define __glibcxx_adaptor_iterator_pair_constructor 202106L
@@ -1960,7 +1949,7 @@
 #endif /* !defined(__cpp_lib_adaptor_iterator_pair_constructor) && defined(__glibcxx_want_adaptor_iterator_pair_constructor) */
 #undef __glibcxx_want_adaptor_iterator_pair_constructor
 
-// from version.def line 1606
+// from version.def line 1608
 #if !defined(__cpp_lib_formatters)
 # if (__cplusplus >= 202100L) && _GLIBCXX_HOSTED
 #  define __glibcxx_formatters 202302L
@@ -1971,7 +1960,7 @@
 #endif /* !defined(__cpp_lib_formatters) && defined(__glibcxx_want_formatters) */
 #undef __glibcxx_want_formatters
 
-// from version.def line 1615
+// from version.def line 1617
 #if !defined(__cpp_lib_forward_like)
 # if (__cplusplus >= 202100L)
 #  define __glibcxx_forward_like 202207L
@@ -1982,7 +1971,7 @@
 #endif /* !defined(__cpp_lib_forward_like) && defined(__glibcxx_want_forward_like) */
 #undef __glibcxx_want_forward_like
 
-// from version.def line 1623
+// from version.def line 1625
 #if !defined(__cpp_lib_ios_noreplace)
 # if (__cplusplus >= 202100L) && _GLIBCXX_HOSTED
 #  define __glibcxx_ios_noreplace 202207L
@@ -1993,7 +1982,7 @@
 #endif /* !defined(__cpp_lib_ios_noreplace) && defined(__glibcxx_want_ios_noreplace) */
 #undef __glibcxx_want_ios_noreplace
 
-// from version.def line 1632
+// from version.def line 1634
 #if !defined(__cpp_lib_move_only_function)
 # if (__cplusplus >= 202100L) && _GLIBCXX_HOSTED
 #  define __glibcxx_move_only_function 202110L
@@ -2004,7 +1993,7 @@
 #endif /* !defined(__cpp_lib_move_only_function) && defined(__glibcxx_want_move_only_function) */
 #undef __glibcxx_want_move_only_function
 
-// from version.def line 1641
+// from version.def line 1643
 #if !defined(__cpp_lib_out_ptr)
 # if (__cplusplus >= 202100L)
 #  define __glibcxx_out_ptr 202311L
@@ -2015,7 +2004,7 @@
 #endif /* !defined(__cpp_lib_out_ptr) && defined(__glibcxx_want_out_ptr) */
 #undef __glibcxx_want_out_ptr
 
-// from version.def line 1649
+// from version.def line 1651
 #if !defined(__cpp_lib_spanstream)
 # if (__cplusplus >= 202100L) && _GLIBCXX_HOSTED && (__glibcxx_span)
 #  define __glibcxx_spanstream 202106L
@@ -2026,7 +2015,7 @@
 #endif /* !defined(__cpp_lib_spanstream) && defined(__glibcxx_want_spanstream) */
 #undef __glibcxx_want_spanstream
 
-// from version.def line 1659
+// from version.def line 1661
 #if !defined(__cpp_lib_stacktrace)
 # if (__cplusplus >= 202100L) && _GLIBCXX_HOSTED && (_GLIBCXX_HAVE_STACKTRACE)
 #  define __glibcxx_stacktrace 202011L
@@ -2037,7 +2026,7 @@
 #endif /* !defined(__cpp_lib_stacktrace) && defined(__glibcxx_want_stacktrace) */
 #undef __glibcxx_want_stacktrace
 
-// from version.def line 1669
+// from version.def line 1671
 #if !defined(__cpp_lib_string_contains)
 # if (__cplusplus >= 202100L) && _GLIBCXX_HOSTED
 #  define __glibcxx_string_contains 202011L
@@ -2048,7 +2037,7 @@
 #endif /* !defined(__cpp_lib_string_contains) && defined(__glibcxx_want_string_contains) */
 #undef __glibcxx_want_string_contains
 
-// from version.def line 1678
+// from version.def line 1680
 #if !defined(__cpp_lib_string_resize_and_overwrite)
 # if (__cplusplus >= 202100L) && _GLIBCXX_HOSTED
 #  define __glibcxx_string_resize_and_overwrite 202110L
@@ -2059,7 +2048,29 @@
 #endif /* !defined(__cpp_lib_string_resize_and_overwrite) && defined(__glibcxx_want_string_resize_and_overwrite) */
 #undef __glibcxx_want_string_resize_and_overwrite
 
-// from version.def line 1687
+// from version.def line 1689
+#if !defined(__cpp_lib_to_underlying)
+# if (__cplusplus >= 202100L)
+#  define __glibcxx_to_underlying 202102L
+#  if defined(__glibcxx_want_all) || defined(__glibcxx_want_to_underlying)
+#   define __cpp_lib_to_underlying 202102L
+#  endif
+# endif
+#endif /* !defined(__cpp_lib_to_underlying) && defined(__glibcxx_want_to_underlying) */
+#undef __glibcxx_want_to_underlying
+
+// from version.def line 1697
+#if !defined(__cpp_lib_unreachable)
+# if (__cplusplus >= 202100L)
+#  define __glibcxx_unreachable 202202L
+#  if defined(__glibcxx_want_all) || defined(__glibcxx_want_unreachable)
+#   define __cpp_lib_unreachable 202202L
+#  endif
+# endif
+#endif /* !defined(__cpp_lib_unreachable) && defined(__glibcxx_want_unreachable) */
+#undef __glibcxx_want_unreachable
+
+// from version.def line 1705
 #if !defined(__cpp_lib_fstream_native_handle)
 # if (__cplusplus >  202302L) && _GLIBCXX_HOSTED
 #  define __glibcxx_fstream_native_handle 202306L
@@ -2070,7 +2081,7 @@
 #endif /* !defined(__cpp_lib_fstream_native_handle) && defined(__glibcxx_want_fstream_native_handle) */
 #undef __glibcxx_want_fstream_native_handle
 
-// from version.def line 1696
+// from version.def line 1714
 #if !defined(__cpp_lib_ratio)
 # if (__cplusplus >  202302L)
 #  define __glibcxx_ratio 202306L
@@ -2081,7 +2092,7 @@
 #endif /* !defined(__cpp_lib_ratio) && defined(__glibcxx_want_ratio) */
 #undef __glibcxx_want_ratio
 
-// from version.def line 1704
+// from version.def line 1722
 #if !defined(__cpp_lib_saturation_arithmetic)
 # if (__cplusplus >  202302L)
 #  define __glibcxx_saturation_arithmetic 202311L
@@ -2092,7 +2103,7 @@
 #endif /* !defined(__cpp_lib_saturation_arithmetic) && defined(__glibcxx_want_saturation_arithmetic) */
 #undef __glibcxx_want_saturation_arithmetic
 
-// from version.def line 1712
+// from version.def line 1730
 #if !defined(__cpp_lib_to_string)
 # if (__cplusplus >  202302L) && _GLIBCXX_HOSTED && (__glibcxx_to_chars)
 #  define __glibcxx_to_string 202306L
diff --git a/libstdc++-v3/include/std/ranges b/libstdc++-v3/include/std/ranges
index 26d6c013ad0..63bea862c05 100644
--- a/libstdc++-v3/include/std/ranges
+++ b/libstdc++-v3/include/std/ranges
@@ -64,6 +64,7 @@
 #define __glibcxx_want_ranges_repeat
 #define __glibcxx_want_ranges_slide
 #define __glibcxx_want_ranges_stride
+#define __glibcxx_want_ranges_to_container
 #define __glibcxx_want_ranges_zip
 #include <bits/version.h>
 
@@ -9213,8 +9214,366 @@ namespace views::__adaptor
 
   namespace views = ranges::views;
 
+#if __cpp_lib_ranges_to_container // C++ >= 23
+namespace ranges
+{
+/// @cond undocumented
+namespace __detail
+{
+  template<typename _Container>
+    constexpr bool __reservable_container
+      = sized_range<_Container>
+      && requires(_Container& __c, range_size_t<_Container> __n) {
+	__c.reserve(__n);
+	{ __c.capacity() } -> same_as<decltype(__n)>;
+	{ __c.max_size() } -> same_as<decltype(__n)>;
+      };
+
+  template<typename _Container, typename _Ref>
+    constexpr bool __container_insertable
+      = requires(_Container& __c, _Ref&& __ref) {
+	typename _Container::value_type;
+	requires (
+	  requires { __c.push_back(std::forward<_Ref>(__ref)); }
+	  || requires { __c.insert(__c.end(), std::forward<_Ref>(__ref)); }
+	);
+      };
+
+  template<typename _Ref, typename _Container>
+    constexpr auto
+    __container_inserter(_Container& __c)
+    {
+      if constexpr (requires { __c.push_back(std::declval<_Ref>()); })
+	return std::back_inserter(__c);
+      else
+	return std::inserter(__c, __c.end());
+    }
+
+  template<typename _Cont, typename _Range>
+    constexpr bool __toable = requires {
+      requires (!input_range<_Range>
+		  || convertible_to<range_reference_t<_Range>,
+				    range_value_t<_Cont>>);
+    };
+} // namespace __detail
+/// @endcond
+
+  /// Convert a range to a container.
+  /**
+   * @tparam _Cont A container type.
+   * @param __r A range that models the `input_range` concept.
+   * @param __args... Arguments to pass to the container constructor.
+   * @since C++23
+   *
+   * This function converts a range to the `_Cont` type.
+   *
+   * For example, `std::ranges::to<std::vector<int>>(some_view)`
+   * will convert the view to `std::vector<int>`.
+   *
+   * Additional constructor arguments for the container can be supplied after
+   * the input range argument, e.g.
+   * `std::ranges::to<std::vector<int, Alloc<int>>>(a_range, an_allocator)`.
+   */
+  template<typename _Cont, input_range _Rg, typename... _Args>
+    requires (!view<_Cont>)
+    constexpr _Cont
+    to [[nodiscard]] (_Rg&& __r, _Args&&... __args)
+    {
+      static_assert(!is_const_v<_Cont> && !is_volatile_v<_Cont>);
+      static_assert(is_class_v<_Cont>);
+
+      if constexpr (__detail::__toable<_Cont, _Rg>)
+	{
+	  if constexpr (constructible_from<_Cont, _Rg, _Args...>)
+	    return _Cont(std::forward<_Rg>(__r),
+			 std::forward<_Args>(__args)...);
+	  else if constexpr (constructible_from<_Cont, from_range_t, _Rg, _Args...>)
+	    return _Cont(from_range, std::forward<_Rg>(__r),
+			 std::forward<_Args>(__args)...);
+	  else if constexpr (requires { common_range<_Rg>;
+		typename __iter_category_t<iterator_t<_Rg>>;
+		requires derived_from<__iter_category_t<iterator_t<_Rg>>,
+				      input_iterator_tag>;
+		requires constructible_from<_Cont, iterator_t<_Rg>,
+					    sentinel_t<_Rg>, _Args...>;
+	      })
+	    return _Cont(ranges::begin(__r), ranges::end(__r),
+			 std::forward<_Args>(__args)...);
+	  else
+	    {
+	      using __detail::__container_insertable;
+	      using __detail::__reservable_container;
+	      using _RefT = range_reference_t<_Rg>;
+	      static_assert(constructible_from<_Cont, _Args...>);
+	      static_assert(__container_insertable<_Cont, _RefT>);
+	      _Cont __c(std::forward<_Args>(__args)...);
+	      if constexpr (sized_range<_Rg> && __reservable_container<_Cont>)
+		__c.reserve(static_cast<range_size_t<_Cont>>(ranges::size(__r)));
+	      auto __ins = __detail::__container_inserter<_RefT>(__c);
+	      for (auto&& __e : __r)
+		*__ins++ = std::forward<decltype(__e)>(__e);
+	      return __c;
+	    }
+	}
+      else
+	{
+	  static_assert(input_range<range_reference_t<_Rg>>);
+	  // _GLIBCXX_RESOLVE_LIB_DEFECTS
+	  // 3984. ranges::to's recursion branch may be ill-formed
+	  return ranges::to<_Cont>(ref_view(__r) | views::transform(
+		[]<typename _Elt>(_Elt&& __elem) {
+		  using _ValT = range_value_t<_Cont>;
+		  return ranges::to<_ValT>(std::forward<_Elt>(__elem));
+		}), std::forward<_Args>(__args)...);
+	}
+    }
+
+/// @cond undocumented
+namespace __detail
+{
+  template<typename _Rg>
+    struct _InputIter
+    {
+      using iterator_category = input_iterator_tag;
+      using value_type = range_value_t<_Rg>;
+      using difference_type = ptrdiff_t;
+      using pointer = add_pointer_t<range_reference_t<_Rg>>;
+      using reference = range_reference_t<_Rg>;
+      reference operator*() const;
+      pointer operator->() const;
+      _InputIter& operator++();
+      _InputIter operator++(int);
+      bool operator==(const _InputIter&) const;
+    };
+
+#if 0
+  template<template<typename...> typename _Cont, typename _Rg,
+	   typename... _Args>
+    concept __deduce_expr_1 = requires {
+      _Cont(std::declval<_Rg>(), std::declval<_Args>()...);
+    };
+
+  template<template<typename...> typename _Cont, typename _Rg,
+	   typename... _Args>
+    concept __deduce_expr_2 = requires {
+      _Cont(from_range, std::declval<_Rg>(), std::declval<_Args>()...);
+    };
+
+  template<template<typename...> typename _Cont, typename _Rg,
+	   typename... _Args>
+    concept __deduce_expr_3 = requires(_InputIter<_Rg> __i) {
+      _Cont(std::move(__i), std::move(__i), std::declval<_Args>()...);
+    };
+#endif
+
+  template<template<typename...> typename _Cont, input_range _Rg,
+	   typename... _Args>
+    using _DeduceExpr1
+      = decltype(_Cont(std::declval<_Rg>(), std::declval<_Args>()...));
+
+  template<template<typename...> typename _Cont, input_range _Rg,
+	   typename... _Args>
+    using _DeduceExpr2
+      = decltype(_Cont(from_range, std::declval<_Rg>(),
+		       std::declval<_Args>()...));
+
+  template<template<typename...> typename _Cont, input_range _Rg,
+	   typename... _Args>
+    using _DeduceExpr3
+      = decltype(_Cont(std::declval<_InputIter<_Rg>>(),
+		       std::declval<_InputIter<_Rg>>(),
+		       std::declval<_Args>()...));
+
+} // namespace __detail
+/// @endcond
+
+  template<template<typename...> typename _Cont, input_range _Rg,
+	   typename... _Args>
+    constexpr auto
+    to [[nodiscard]] (_Rg&& __r, _Args&&... __args)
+    {
+      using __detail::_DeduceExpr1;
+      using __detail::_DeduceExpr2;
+      using __detail::_DeduceExpr3;
+      if constexpr (requires { typename _DeduceExpr1<_Cont, _Rg, _Args...>; })
+	return ranges::to<_DeduceExpr1<_Cont, _Rg, _Args...>>(
+	    std::forward<_Rg>(__r), std::forward<_Args>(__args)...);
+      else if constexpr (requires { typename _DeduceExpr2<_Cont, _Rg, _Args...>; })
+	return ranges::to<_DeduceExpr2<_Cont, _Rg, _Args...>>(
+	    std::forward<_Rg>(__r), std::forward<_Args>(__args)...);
+      else if constexpr (requires { typename _DeduceExpr3<_Cont, _Rg, _Args...>; })
+	return ranges::to<_DeduceExpr3<_Cont, _Rg, _Args...>>(
+	    std::forward<_Rg>(__r), std::forward<_Args>(__args)...);
+      else
+	static_assert(false); // Cannot deduce container specialization.
+    }
+
+/// @cond undocumented
+namespace __detail
+{
+  template<typename _Cont, typename... _Args>
+    class _ToClosure
+    : public views::__adaptor::_RangeAdaptorClosure<_ToClosure<_Cont, _Args...>>
+    {
+      tuple<decay_t<_Args>...> _M_bound_args;
+
+    public:
+      _ToClosure(_Args&&... __args)
+      : _M_bound_args(std::forward<_Args>(__args)...)
+      { }
+
+      // TODO: use explicit object functions ("deducing this").
+
+      template<typename _Rg>
+	constexpr auto
+	operator()(_Rg&& __r) &
+	{
+	  return std::apply([&__r]<typename... _Tp>(_Tp&&... __args) {
+	    return ranges::to<_Cont>(std::forward<_Rg>(__r),
+				     std::forward<_Tp>(__args)...);
+	  }, _M_bound_args);
+	}
+
+      template<typename _Rg>
+	constexpr auto
+	operator()(_Rg&& __r) const &
+	{
+	  return std::apply([&__r]<typename... _Tp>(_Tp&&... __args) {
+	    return ranges::to<_Cont>(std::forward<_Rg>(__r),
+				     std::forward<_Tp>(__args)...);
+	  }, _M_bound_args);
+	}
+
+      template<typename _Rg>
+	constexpr auto
+	operator()(_Rg&& __r) &&
+	{
+	  return std::apply([&__r]<typename... _Tp>(_Tp&&... __args) {
+	    return ranges::to<_Cont>(std::forward<_Rg>(__r),
+				     std::forward<_Tp>(__args)...);
+	  }, std::move(_M_bound_args));
+	}
+
+      template<typename _Rg>
+	constexpr auto
+	operator()(_Rg&& __r) const &&
+	{
+	  return std::apply([&__r]<typename... _Tp>(_Tp&&... __args) {
+	    return ranges::to<_Cont>(std::forward<_Rg>(__r),
+				     std::forward<_Tp>(__args)...);
+	  }, std::move(_M_bound_args));
+	}
+    };
+} // namespace __detail
+/// @endcond
+
+  /// ranges::to adaptor for converting a range to a container type
+  /**
+   * @tparam _Cont A container type.
+   * @param __args... Arguments to pass to the container constructor.
+   * @since C++23
+   *
+   * This range adaptor returns a range adaptor closure object that converts
+   * a range to the `_Cont` type.
+   *
+   * For example, `some_view | std::ranges::to<std::vector<int>>()`
+   * will convert the view to `std::vector<int>`.
+   *
+   * Additional constructor arguments for the container can be supplied, e.g.
+   * `r | std::ranges::to<std::vector<int, Alloc<int>>>(an_allocator)`.
+   */
+  template<typename _Cont, typename... _Args>
+    requires (!view<_Cont>)
+    constexpr __detail::_ToClosure<_Cont, _Args...>
+    to [[nodiscard]] (_Args&&... __args)
+    { return {std::forward<_Args>(__args)...}; }
+
+/// @cond undocumented
+namespace __detail
+{
+  template<template<typename...> typename _Cont, typename... _Args>
+    class _ToClosure2
+    : public views::__adaptor::_RangeAdaptorClosure<_ToClosure2<_Cont, _Args...>>
+    {
+      tuple<decay_t<_Args>...> _M_bound_args;
+
+    public:
+      _ToClosure2(_Args&&... __args)
+      : _M_bound_args(std::forward<_Args>(__args)...)
+      { }
+
+      // TODO: use explicit object functions ("deducing this").
+
+      template<typename _Rg>
+	constexpr auto
+	operator()(_Rg&& __r) &
+	{
+	  return std::apply([&__r]<typename... _Tp>(_Tp&&... __args) {
+	    return ranges::to<_Cont>(std::forward<_Rg>(__r),
+				     std::forward<_Tp>(__args)...);
+	  }, _M_bound_args);
+	}
+
+      template<typename _Rg>
+	constexpr auto
+	operator()(_Rg&& __r) const &
+	{
+	  return std::apply([&__r]<typename... _Tp>(_Tp&&... __args) {
+	    return ranges::to<_Cont>(std::forward<_Rg>(__r),
+				     std::forward<_Tp>(__args)...);
+	  }, _M_bound_args);
+	}
+
+      template<typename _Rg>
+	constexpr auto
+	operator()(_Rg&& __r) &&
+	{
+	  return std::apply([&__r]<typename... _Tp>(_Tp&&... __args) {
+	    return ranges::to<_Cont>(std::forward<_Rg>(__r),
+				     std::forward<_Tp>(__args)...);
+	  }, std::move(_M_bound_args));
+	}
+
+      template<typename _Rg>
+	constexpr auto
+	operator()(_Rg&& __r) const &&
+	{
+	  return std::apply([&__r]<typename... _Tp>(_Tp&&... __args) {
+	    return ranges::to<_Cont>(std::forward<_Rg>(__r),
+				     std::forward<_Tp>(__args)...);
+	  }, std::move(_M_bound_args));
+	}
+    };
+} // namespace __detail
+/// @endcond
+
+  /// ranges::to adaptor for converting a range to a deduced container type.
+  /**
+   * @tparam _Cont A container template.
+   * @param __args... Arguments to pass to the container constructor.
+   * @since C++23
+   *
+   * This range adaptor returns a range adaptor closure object that converts
+   * a range to a specialization of the `_Cont` class template. The specific
+   * specialization of `_Cont` to be used is deduced automatically.
+   *
+   * For example, `some_view | std::ranges::to<std::vector>(Alloc<int>{})`
+   * will convert the view to `std::vector<T, Alloc<T>>`, where `T` is the
+   * view's value type, i.e. `std::ranges::range_value_t<decltype(some_view)>`.
+   *
+   * Additional constructor arguments for the container can be supplied, e.g.
+   * `r | std::ranges::to<std::vector>(an_allocator)`.
+   */
+  template<template<typename...> typename _Cont, typename... _Args>
+    constexpr __detail::_ToClosure2<_Cont, _Args...>
+    to [[nodiscard]] (_Args&&... __args)
+    { return {std::forward<_Args>(__args)...}; }
+
+} // namespace ranges
+#endif // __cpp_lib_ranges_to_container
+
 _GLIBCXX_END_NAMESPACE_VERSION
-} // namespace
+} // namespace std
 #endif // library concepts
 #endif // C++2a
 #endif /* _GLIBCXX_RANGES */
diff --git a/libstdc++-v3/testsuite/std/ranges/conv/1.cc b/libstdc++-v3/testsuite/std/ranges/conv/1.cc
new file mode 100644
index 00000000000..0032cf32688
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/ranges/conv/1.cc
@@ -0,0 +1,369 @@
+// { dg-do run { target c++23 } }
+
+// C++23 26.5.7 Range conversions [range.utility.conv]
+
+#include <ranges>
+#include <vector>
+#include <string>
+#include <deque>
+#include <list>
+#include <forward_list>
+#include <map>
+#include <testsuite_hooks.h>
+#include <testsuite_allocator.h>
+#include <testsuite_iterators.h>
+
+void
+test_p1206r7_examples()
+{
+  using Alloc = __gnu_test::uneq_allocator<int>;
+  const Alloc alloc(303);
+  const std::map<int, const char*> m{{1, "one"}, {2, "two"}, {3, "three"}};
+  namespace ranges = std::ranges;
+
+  auto l = std::views::iota(1, 10);
+  // create a vector with the elements of l
+  auto vec = ranges::to<std::vector<int>>(l); // or vector{std::from_range, l};
+  //Specify an allocator
+  auto b = ranges::to<std::vector<int, Alloc>>(l, alloc); // or vector{std::from_range, l, alloc};
+  //deducing value_type
+  auto c = ranges::to<std::vector>(l);
+  // explicit conversion int -> long
+  auto d = ranges::to<std::vector<long>>(l);
+  //Supports converting associative container to sequence containers
+  auto f = ranges::to<std::vector>(m);
+  //Supports converting sequence containers to associative ones
+  auto g = ranges::to<std::map>(f);
+  //Pipe syntax
+  auto g2 = l | ranges::views::take(42) | ranges::to<std::vector>();
+  //Pipe syntax with allocator
+  auto h = l | ranges::views::take(42) | ranges::to<std::vector>(alloc);
+  //The pipe syntax also support specifying the type and conversions
+  auto i = l | ranges::views::take(42) | ranges::to<std::vector<long>>();
+  // Nested ranges
+  std::list<std::forward_list<int>> lst = {{0, 1, 2, 3}, {4, 5, 6, 7}};
+  auto vec1 = ranges::to<std::vector<std::vector<int>>>(lst);
+  auto vec2 = ranges::to<std::vector<std::deque<double>>>(lst);
+
+  VERIFY( vec == std::vector<int>(std::ranges::begin(l), std::ranges::end(l)) );
+  static_assert(std::is_same_v<decltype(b), std::vector<int, Alloc>>);
+  VERIFY( b == (std::vector<int, Alloc>(vec.begin(), vec.end())) );
+  VERIFY( b.get_allocator() == alloc );
+  static_assert(std::is_same_v<decltype(c), std::vector<int>>);
+  VERIFY( c == vec );
+  static_assert(std::is_same_v<decltype(d), std::vector<long>>);
+  VERIFY( d == std::vector<long>(vec.begin(), vec.end()) );
+  VERIFY( g == m );
+  static_assert(std::is_same_v<decltype(g2), std::vector<int>>);
+  VERIFY( g2 == vec );
+  static_assert(std::is_same_v<decltype(h), std::vector<int, Alloc>>);
+  VERIFY( h == b );
+  VERIFY( h.get_allocator() == alloc );
+  VERIFY( i == d );
+  static_assert(std::is_same_v<decltype(vec1), std::vector<std::vector<int>>>);
+  VERIFY( vec1[1][1] == 5 );
+  static_assert(std::is_same_v<decltype(vec2), std::vector<std::deque<double>>>);
+  VERIFY( vec2[1][2] == 6.0 );
+}
+
+void
+test_example_1()
+{
+  using namespace std;
+  using ranges::to;
+
+  // Example 1 from C++23 [range.utility.conv.general]
+  string_view str = "the quick brown fox";
+  auto words = views::split(str, ' ') | to<vector<string>>();
+
+  VERIFY( (is_same_v<decltype(words), vector<string>>) );
+  VERIFY( words == vector<string>({"the", "quick", "brown", "fox"}) );
+}
+
+template<typename C>
+struct Cont1
+{
+  template<typename R, typename... Args>
+    requires std::constructible_from<C, R&, Args&...>
+    Cont1(R&& r, Args&&... args)
+    : c(r, args...)
+    { }
+
+  typename C::iterator begin();
+  typename C::iterator end();
+
+  C c;
+};
+
+void
+test_2_1_1()
+{
+  // (2.1.1) constructible_from<C, R, Args...>
+
+  std::vector<int> v{1, 2, 3, 4};
+  auto v2 = std::ranges::to<std::vector<int>>(v);
+  static_assert(std::is_same_v<decltype(v2), decltype(v)>);
+  VERIFY( v2 == v );
+
+  std::initializer_list<int> il{5, 6, 7, 8};
+  v2 = std::ranges::to<std::vector<int>>(il);
+  VERIFY( v2 == std::vector<int>(il) );
+
+  v2 = std::ranges::to<std::vector<int>>(il, std::allocator<int>{});
+  VERIFY( v2 == std::vector<int>(il) );
+
+  using Alloc = __gnu_test::uneq_allocator<int>;
+  using V = std::vector<int, Alloc>;
+
+  V v3({10, 11, 12, 13}, Alloc(14));
+  auto v4 = std::ranges::to<V>(v3);
+  static_assert(std::is_same_v<decltype(v4), V>);
+  VERIFY( v4 == v3 );
+  VERIFY( v4.get_allocator() == v3.get_allocator() );
+
+  auto v5 = std::ranges::to<V>(v3, Alloc(33));
+  VERIFY( v5 == v3 );
+  VERIFY( v5.get_allocator() == Alloc(33) );
+
+  auto v6 = std::ranges::to<V>(il, Alloc(44));
+  VERIFY( v6 == V(il) );
+  VERIFY( v6.get_allocator() == Alloc(44) );
+
+  auto c = std::ranges::to<Cont1<V>>(V{1, 2, 3});
+  static_assert(std::is_same_v<decltype(c), Cont1<V>>);
+  VERIFY( c.c == V({1, 2, 3}) );
+
+  auto c2 = std::ranges::to<Cont1<V>>(V{4, 5, 6}, Alloc(55));
+  static_assert(std::is_same_v<decltype(c2), Cont1<V>>);
+  VERIFY( c2.c == V({4, 5, 6}) );
+  VERIFY( c2.c.get_allocator() == Alloc(55) );
+
+  auto c3 = std::ranges::to<Cont1<V>>(il, Alloc(66));
+  static_assert(std::is_same_v<decltype(c2), Cont1<V>>);
+  VERIFY( c3.c == V(v2.begin(), v2.end()) );
+  VERIFY( c3.c.get_allocator() == Alloc(66) );
+}
+
+template<typename C>
+struct Cont2
+{
+  template<typename R, typename... Args>
+    requires std::constructible_from<C, R&, Args&...>
+    Cont2(std::from_range_t, R&& r, Args&&... args)
+    : c(r, args...)
+    { }
+
+  typename C::iterator begin();
+  typename C::iterator end();
+
+  C c;
+};
+
+void
+test_2_1_2()
+{
+  // (2.1.2) constructible_from<C, from_range_t, R, Args...>
+
+  using Alloc = __gnu_test::uneq_allocator<int>;
+  using V = std::vector<int, Alloc>;
+  auto c = std::ranges::to<Cont2<V>>(V{1, 2, 3});
+  static_assert(std::is_same_v<decltype(c), Cont2<V>>);
+  VERIFY( c.c == V({1, 2, 3}) );
+
+  auto c2 = std::ranges::to<Cont2<V>>(V{4, 5, 6}, Alloc(7));
+  static_assert(std::is_same_v<decltype(c2), Cont2<V>>);
+  VERIFY( c2.c == V({4, 5, 6}) );
+  VERIFY( c2.c.get_allocator() == Alloc(7) );
+}
+
+template<typename C>
+struct Cont3
+{
+  template<typename It, typename Sent, typename... Args>
+    requires std::same_as<It, Sent>
+    && std::constructible_from<C, It&, Sent&, Args&...>
+    Cont3(It first, Sent last, Args&&... args)
+    : c(first, last, args...)
+    { }
+
+  typename C::iterator begin();
+  typename C::iterator end();
+
+  C c;
+};
+
+void
+test_2_1_3()
+{
+  // (2.1.3) constructible_from<C, iterator_t<R>, sentinel_t<R<, Args...>
+
+  using Alloc = __gnu_test::uneq_allocator<int>;
+  using V = std::vector<int, Alloc>;
+
+  std::list<unsigned> l{1u, 2u, 3u};
+  auto c = std::ranges::to<Cont3<V>>(l);
+  static_assert(std::is_same_v<decltype(c), Cont3<V>>);
+  VERIFY( c.c == V(l.begin(), l.end()) );
+
+  std::list<long> l2{4l, 5l, 6l};
+  auto c2 = std::ranges::to<Cont3<V>>(l2, Alloc(78));
+  static_assert(std::is_same_v<decltype(c2), Cont3<V>>);
+  VERIFY( c2.c == V(l2.begin(), l2.end()) );
+  VERIFY( c2.c.get_allocator() == Alloc(78) );
+}
+
+template<typename C, bool UsePushBack = true>
+struct Cont4
+{
+  using value_type = typename C::value_type;
+
+  // Only support construction with no args or an allocator.
+  // This forces the use of either push_back or insert to fill the container.
+  Cont4() { }
+  Cont4(typename C::allocator_type a) : c(a) { }
+
+  // Required to satisfy range
+  typename C::iterator begin() { return c.begin(); }
+  typename C::iterator end() { return c.end(); }
+
+  // Satisfying container-insertable requires either this ...
+  template<typename T>
+    requires UsePushBack
+    && requires(C& c, T&& t) { c.push_back(std::forward<T>(t)); }
+    void
+    push_back(T&& t)
+    {
+      c.push_back(std::forward<T>(t));
+      used_push_back = true;
+    }
+
+  // ... or this:
+  template<typename T>
+    typename C::iterator
+    insert(typename C::iterator, T&& t)
+    {
+      used_push_back = false;
+      return c.insert(c.end(), std::forward<T>(t));
+    }
+
+  // Required to satisfy reservable-container
+  void
+  reserve(typename C::size_type n) requires requires(C& c) { c.reserve(n); }
+  {
+    c.reserve(n);
+    used_reserve = true;
+  }
+
+  // Required to satisfy reservable-container
+  auto size() const { return c.size(); }
+
+  // Required to satisfy reservable-container
+  auto capacity() const requires requires(C& c) { c.capacity(); }
+  { return c.capacity(); }
+
+  // Required to satisfy reservable-container
+  auto max_size() const { return c.max_size(); }
+
+  C c;
+  bool used_push_back = false;
+  bool used_reserve = false;
+};
+
+void
+test_2_1_4()
+{
+  // (2.1.4) constructible_from<C, Args...> and
+  // container-insertable<C, range_reference_t<R>>
+
+  using Alloc = __gnu_test::uneq_allocator<int>;
+  using V = std::vector<int, Alloc>;
+
+  std::list<unsigned> l{1u, 2u, 3u};
+  auto c = std::ranges::to<Cont4<V>>(l);
+  static_assert(std::is_same_v<decltype(c), Cont4<V>>);
+  VERIFY( c.c == V(l.begin(), l.end()) );
+  VERIFY( c.used_push_back );
+  VERIFY( c.used_reserve );
+
+  std::list<long> l2{4l, 5l, 6l};
+  auto c2 = std::ranges::to<Cont4<V>>(l2, Alloc(78));
+  static_assert(std::is_same_v<decltype(c2), Cont4<V>>);
+  VERIFY( c2.c == V(l2.begin(), l2.end()) );
+  VERIFY( c2.c.get_allocator() == Alloc(78) );
+  VERIFY( c2.used_push_back );
+  VERIFY( c2.used_reserve );
+
+  using Alloc2 = __gnu_test::uneq_allocator<short>;
+  using List = std::list<short, Alloc2>;
+  auto c3 = std::ranges::to<Cont4<List>>(c.c, Alloc2(99));
+  static_assert(std::is_same_v<decltype(c3), Cont4<List>>);
+  VERIFY( c3.c == List(l.begin(), l.end()) );
+  VERIFY( c3.c.get_allocator() == Alloc(99) );
+  VERIFY( c3.used_push_back );
+  VERIFY( ! c3.used_reserve );
+
+  auto c4 = std::ranges::to<Cont4<List, false>>(c.c, Alloc2(111));
+  static_assert(std::is_same_v<decltype(c4), Cont4<List, false>>);
+  VERIFY( c4.c == List(l.begin(), l.end()) );
+  VERIFY( c4.c.get_allocator() == Alloc(111) );
+  VERIFY( ! c4.used_push_back );
+  VERIFY( ! c4.used_reserve );
+}
+
+void
+test_2_2()
+{
+  // (2.2) input_range<range_reference_t<R>>
+
+  std::string s1[]{ "one", "two", "three", "four" };
+  std::string s2[]{ "V", "VI", "VII", "VIII" };
+  std::string s3[]{ "0x09", "0x0a", "0x0b", "0x0c" };
+  using R = __gnu_test::test_input_range<std::string>;
+  R input_ranges[]{R(s1), R(s2), R(s3)};
+  __gnu_test::test_input_range<R> rr(input_ranges);
+  namespace pmr = std::pmr;
+  __gnu_test::memory_resource res;
+#if _GLIBCXX_USE_CXX11_ABI
+  auto vvs = std::ranges::to<pmr::vector<pmr::vector<pmr::string>>>(rr, &res);
+  auto str_alloc = pmr::polymorphic_allocator<char>(&res);
+#else
+  auto vvs = std::ranges::to<pmr::vector<pmr::vector<std::string>>>(rr, &res);
+  auto str_alloc = std::allocator<char>();
+#endif
+  VERIFY( vvs[1][1] == "VI" );
+  VERIFY( vvs[2][2] == "0x0b" );
+  VERIFY( vvs[0].get_allocator().resource() == &res );
+  VERIFY( vvs[2][2].get_allocator() == str_alloc );
+}
+
+void
+test_lwg3984()
+{
+  std::vector<std::vector<int>> v;
+  auto r = std::views::all(std::move(v));
+  auto l = std::ranges::to<std::list<std::list<int>>>(r);
+  VERIFY(l.empty());
+}
+
+void
+test_nodiscard()
+{
+  std::vector<int> v;
+  std::ranges::to<std::vector<long>>(v); // { dg-warning "ignoring return" }
+  std::ranges::to<std::vector>(v);       // { dg-warning "ignoring return" }
+  std::ranges::to<std::vector<long>>();  // { dg-warning "ignoring return" }
+  std::ranges::to<std::vector>();        // { dg-warning "ignoring return" }
+}
+
+int main()
+{
+  test_p1206r7_examples();
+  test_example_1();
+  test_2_1_1();
+  test_2_1_2();
+  test_2_1_3();
+  test_2_1_4();
+  test_2_2();
+  test_lwg3984();
+  test_nodiscard();
+}
diff --git a/libstdc++-v3/testsuite/std/ranges/conv/2_neg.cc b/libstdc++-v3/testsuite/std/ranges/conv/2_neg.cc
new file mode 100644
index 00000000000..1e5f6f18408
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/ranges/conv/2_neg.cc
@@ -0,0 +1,24 @@
+// { dg-do compile { target c++23 } }
+
+// C++23 26.5.7 Range conversions [range.utility.conv]
+
+#include <ranges>
+#include <vector>
+#include <testsuite_allocator.h>
+
+void
+test_2_1_5()
+{
+  // (2.1.5) Otherwise, the program is ill-formed.
+
+  using Alloc = __gnu_test::uneq_allocator<int>;
+  using Vec = std::vector<int, Alloc>;
+
+  std::vector<int> v;
+  (void) std::ranges::to<Vec>(v, v.get_allocator()); // { dg-error "here" }
+
+  (void) std::ranges::to<Vec>(Vec{}, 1, 2, 3, 4, 5, 6); // { dg-error "here" }
+}
+
+// { dg-error "static assertion failed" "" { target *-*-* } 0 }
+// { dg-prune-output "no matching function" }
diff --git a/libstdc++-v3/testsuite/std/ranges/conv/version.cc b/libstdc++-v3/testsuite/std/ranges/conv/version.cc
new file mode 100644
index 00000000000..33736807eb4
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/ranges/conv/version.cc
@@ -0,0 +1,19 @@
+// { dg-do preprocess { target c++23 } }
+// { dg-add-options no_pch }
+
+#include <ranges>
+
+#ifndef __cpp_lib_ranges_to_container
+# error "Feature test macro for ranges_to_container is missing in <ranges>"
+#elif __cpp_lib_ranges_to_container < 202202L
+# error "Feature test macro for ranges_to_container has wrong value in <ranges>"
+#endif
+
+#undef __cpp_lib_ranges_to_container
+#include <version>
+
+#ifndef __cpp_lib_ranges_to_container
+# error "Feature test macro for ranges_to_container is missing in <version>"
+#elif __cpp_lib_ranges_to_container < 202202L
+# error "Feature test macro for ranges_to_container has wrong value in <version>"
+#endif

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2023-11-23 17:51 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-11-23 17:51 [gcc r14-5794] libstdc++: Define std::ranges::to for C++23 (P1206R7) [PR111055] 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).