aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJonathan Wakely <jwakely@redhat.com>2023-09-19 13:23:13 +0100
committerJonathan Wakely <jwakely@redhat.com>2023-11-23 17:48:41 +0000
commit7a6a29c455e7755b501c0006e39beb4e56ec2729 (patch)
tree4ff795bbc89cfb12f0c5b2de2fec7030289aaa36
parent0585daf7de0673ade9feca1be66a68178786b48d (diff)
downloadgcc-7a6a29c455e7755b501c0006e39beb4e56ec2729.zip
gcc-7a6a29c455e7755b501c0006e39beb4e56ec2729.tar.gz
gcc-7a6a29c455e7755b501c0006e39beb4e56ec2729.tar.bz2
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.
-rw-r--r--libstdc++-v3/include/bits/ranges_base.h8
-rw-r--r--libstdc++-v3/include/bits/version.def34
-rw-r--r--libstdc++-v3/include/bits/version.h111
-rw-r--r--libstdc++-v3/include/std/ranges361
-rw-r--r--libstdc++-v3/testsuite/std/ranges/conv/1.cc369
-rw-r--r--libstdc++-v3/testsuite/std/ranges/conv/2_neg.cc24
-rw-r--r--libstdc++-v3/testsuite/std/ranges/conv/version.cc19
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 7fa43d1..1ca2c5c 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 605708d..1407778 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;
};
};
@@ -1684,6 +1686,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 = {
v = 202306;
diff --git a/libstdc++-v3/include/bits/version.h b/libstdc++-v3/include/bits/version.h
index cacd9375..1fb1d14 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 26d6c01..63bea86 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 0000000..0032cf32
--- /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 0000000..1e5f6f1
--- /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 0000000..3373680
--- /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