aboutsummaryrefslogtreecommitdiff
path: root/libstdc++-v3/testsuite
diff options
context:
space:
mode:
authorPatrick Palka <ppalka@redhat.com>2024-02-01 14:59:46 -0500
committerPatrick Palka <ppalka@redhat.com>2024-02-01 14:59:46 -0500
commit65b4cba9d6a9ffe9b4d4bdff90727a7064cc0e3b (patch)
tree294dd6fdadc946c51eafcf6b30b989034a637edf /libstdc++-v3/testsuite
parent87d162383ed68c55311a55784f6b40e979945c00 (diff)
downloadgcc-65b4cba9d6a9ffe9b4d4bdff90727a7064cc0e3b.zip
gcc-65b4cba9d6a9ffe9b4d4bdff90727a7064cc0e3b.tar.gz
gcc-65b4cba9d6a9ffe9b4d4bdff90727a7064cc0e3b.tar.bz2
libstdc++: Implement P2165R4 changes to std::pair/tuple/etc [PR113309]
This implements the C++23 paper P2165R4 Compatibility between tuple, pair and tuple-like objects, which builds upon many changes from the earlier C++23 paper P2321R2 zip. Some declarations had to be moved around so that they're visible from <bits/stl_pair.h> without introducing new includes and bloating the header. In the end, the only new include is for <bits/utility.h> from <bits/stl_iterator.h>, for tuple_element_t. PR libstdc++/113309 PR libstdc++/109203 libstdc++-v3/ChangeLog: * include/bits/ranges_util.h (__detail::__pair_like): Don't define in C++23 mode. (__detail::__pair_like_convertible_from): Adjust as per P2165R4. (__detail::__is_subrange<subrange>): Moved from <ranges>. (__detail::__is_tuple_like_v<subrange>): Likewise. * include/bits/stl_iterator.h: Include <bits/utility.h> for C++23. (__different_from): Move to <concepts>. (__iter_key_t): Adjust for C++23 as per P2165R4. (__iter_val_t): Likewise. * include/bits/stl_pair.h (pair, array): Forward declare. (get): Forward declare all overloads relevant to P2165R4 tuple-like constructors. (__is_tuple_v): Define for C++23. (__is_tuple_like_v): Define for C++23. (__tuple_like): Define for C++23 as per P2165R4. (__pair_like): Define for C++23 as per P2165R4. (__eligibile_tuple_like): Define for C++23. (__eligibile_pair_like): Define for C++23. (pair::_S_constructible_from_pair_like): Define for C++23. (pair::_S_convertible_from_pair_like): Define for C++23. (pair::_S_dangles_from_pair_like): Define for C++23. (pair::pair): Define overloads taking a tuple-like type for C++23 as per P2165R4. (pair::_S_assignable_from_tuple_like): Define for C++23. (pair::_S_const_assignable_from_tuple_like): Define for C++23. (pair::operator=): Define overloads taking a tuple-like type for C++23 as per P2165R4. * include/bits/utility.h (ranges::__detail::__is_subrange): Moved from <ranges>. * include/bits/version.def (tuple_like): Define for C++23. * include/bits/version.h: Regenerate. * include/std/concepts (__different_from): Moved from <bits/stl_iterator.h>. (ranges::__swap::__adl_swap): Clarify which __detail namespace. * include/std/map (__cpp_lib_tuple_like): Define C++23. * include/std/ranges (__detail::__is_subrange): Moved to <bits/utility.h>. (__detail::__is_subrange<subrange>): Moved to <bits/ranges_util.h> (__detail::__has_tuple_element): Adjust for C++23 as per P2165R4. (__detail::__tuple_or_pair): Remove as per P2165R4. Replace all uses with plain tuple as per P2165R4. * include/std/tuple (__cpp_lib_tuple_like): Define for C++23. (__tuple_like_tag_t): Define for C++23. (__tuple_cmp): Forward declare for C++23. (_Tuple_impl::_Tuple_impl): Define overloads taking __tuple_like_tag_t and a tuple-like type for C++23. (_Tuple_impl::_M_assign): Likewise. (tuple::__constructible_from_tuple_like): Define for C++23. (tuple::__convertible_from_tuple_like): Define for C++23. (tuple::__dangles_from_tuple_like): Define for C++23. (tuple::tuple): Define overloads taking a tuple-like type for C++23 as per P2165R4. (tuple::__assignable_from_tuple_like): Define for C++23. (tuple::__const_assignable_from_tuple_like): Define for C++23. (tuple::operator=): Define overloads taking a tuple-like type for C++23 as per P2165R4. (tuple::__tuple_like_common_comparison_category): Define for C++23. (tuple::operator<=>): Define overload taking a tuple-like type for C++23 as per P2165R4. (array, get): Forward declarations moved to <bits/stl_pair.h>. (tuple_cat): Constrain with __tuple_like for C++23 as per P2165R4. (apply): Likewise. (make_from_tuple): Likewise. (__tuple_like_common_reference): Define for C++23. (basic_common_reference): Adjust as per P2165R4. (__tuple_like_common_type): Define for C++23. (common_type): Adjust as per P2165R4. * include/std/unordered_map (__cpp_lib_tuple_like): Define for C++23. * include/std/utility (__cpp_lib_tuple_like): Define for C++23. * testsuite/std/ranges/zip/1.cc (test01): Adjust to handle pair and 2-tuple interchangeably. (test05): New test. * testsuite/20_util/pair/p2165r4.cc: New test. * testsuite/20_util/tuple/p2165r4.cc: New test. Reviewed-by: Jonathan Wakely <jwakely@redhat.com>
Diffstat (limited to 'libstdc++-v3/testsuite')
-rw-r--r--libstdc++-v3/testsuite/20_util/pair/p2165r4.cc173
-rw-r--r--libstdc++-v3/testsuite/20_util/tuple/p2165r4.cc335
-rw-r--r--libstdc++-v3/testsuite/std/ranges/zip/1.cc17
3 files changed, 523 insertions, 2 deletions
diff --git a/libstdc++-v3/testsuite/20_util/pair/p2165r4.cc b/libstdc++-v3/testsuite/20_util/pair/p2165r4.cc
new file mode 100644
index 0000000..ef06df1
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/pair/p2165r4.cc
@@ -0,0 +1,173 @@
+// Verify P2165R4 enhancements to std::pair.
+// { dg-do run { target c++23 } }
+
+#include <array>
+#include <tuple>
+#include <utility>
+#include <testsuite_hooks.h>
+
+using std::array;
+using std::pair;
+using std::tuple;
+
+struct A { };
+
+template<template<typename> class pair_like_t>
+constexpr bool
+test01()
+{
+ struct B {
+ int m;
+ constexpr B(A&) : m(0) { }
+ constexpr B(A&&) : m(1) { }
+ constexpr B(const A&) : m(2) { }
+ constexpr B(const A&&) : m(3) { }
+ };
+
+ // template<pair-like UPair>
+ // constexpr explicit(false) pair(UPair&&);
+
+ pair_like_t<A> pair_like;
+
+ [&] {
+ pair<B, B> p2b = pair_like;
+ VERIFY( p2b.first.m == 0 && p2b.second.m == 0 );
+ }();
+ [&] {
+ pair<B, B> p2b = std::move(pair_like);
+ VERIFY( p2b.first.m == 1 && p2b.second.m == 1 );
+ }();
+ [&] {
+ pair<B, B> p2b = std::as_const(pair_like);
+ VERIFY( p2b.first.m == 2 && p2b.second.m == 2 );
+ }();
+ [&] {
+ pair<B, B> p2b = std::move(std::as_const(pair_like));
+ VERIFY( p2b.first.m == 3 && p2b.second.m == 3 );
+ }();
+
+ // Verify dangling checks.
+ static_assert( !std::is_constructible_v<pair<const int&, int>, pair_like_t<long>> );
+ static_assert( !std::is_constructible_v<pair<int, const int&>, pair_like_t<long>> );
+
+ return true;
+}
+
+template<template<typename> class pair_like_t>
+constexpr bool
+test02()
+{
+ struct B {
+ int m;
+ constexpr explicit B(A&) : m(0) { }
+ constexpr explicit B(A&&) : m(1) { }
+ constexpr explicit B(const A&) : m(2) { }
+ constexpr explicit B(const A&&) : m(3) { }
+ };
+
+ // template<pair-like UPair>
+ // constexpr explicit(true) pair(UPair&&);
+
+ static_assert( !std::is_convertible_v<pair_like_t<A>, pair<B, B>> );
+
+ pair_like_t<A> pair_like;
+
+ [&] {
+ pair<B, B> p2b{pair_like};
+ VERIFY( p2b.first.m == 0 && p2b.second.m == 0 );
+ }();
+ [&] {
+ pair<B, B> p2b{std::move(pair_like)};
+ VERIFY( p2b.first.m == 1 && p2b.second.m == 1 );
+ }();
+ [&] {
+ pair<B, B> p2b{std::as_const(pair_like)};
+ VERIFY( p2b.first.m == 2 && p2b.second.m == 2 );
+ }();
+ [&] {
+ pair<B, B> p2b{std::move(std::as_const(pair_like))};
+ VERIFY( p2b.first.m == 3 && p2b.second.m == 3 );
+ }();
+
+ return true;
+}
+
+template<template<typename> class pair_like_t>
+constexpr bool
+test03()
+{
+ struct B {
+ int m;
+ constexpr B& operator=(A&) { m = 0; return *this; }
+ constexpr B& operator=(A&&) { m = 1; return *this; }
+ constexpr B& operator=(const A&) { m = 2; return *this; }
+ constexpr B& operator=(const A&&) { m = 3; return *this; }
+ };
+
+ // template<pair-like UPair>
+ // constexpr pair& operator=(UPair&&);
+
+ pair_like_t<A> pair_like;
+
+ pair<B, B> p2b;
+ p2b = pair_like;
+ VERIFY( p2b.first.m == 0 && p2b.second.m == 0 );
+ p2b = std::move(pair_like);
+ VERIFY( p2b.first.m == 1 && p2b.second.m == 1 );
+ p2b = std::as_const(pair_like);
+ VERIFY( p2b.first.m == 2 && p2b.second.m == 2 );
+ p2b = std::move(std::as_const(pair_like));
+ VERIFY( p2b.first.m == 3 && p2b.second.m == 3 );
+
+ return true;
+}
+
+template<template<typename> class pair_like_t>
+constexpr bool
+test04()
+{
+ struct B {
+ mutable int m;
+ constexpr const B& operator=(A&) const { m = 0; return *this; }
+ constexpr const B& operator=(A&&) const { m = 1; return *this; }
+ constexpr const B& operator=(const A&) const { m = 2; return *this; }
+ constexpr const B& operator=(const A&&) const { m = 3; return *this; }
+ };
+
+ // template<pair-like UPair>
+ // constexpr const pair& operator=(UPair&&) const;
+
+ pair_like_t<A> pair_like;
+
+ const pair<B, B> p2b;
+ p2b = pair_like;
+ VERIFY( p2b.first.m == 0 && p2b.second.m == 0 );
+ p2b = std::move(pair_like);
+ VERIFY( p2b.first.m == 1 && p2b.second.m == 1 );
+ p2b = std::as_const(pair_like);
+ VERIFY( p2b.first.m == 2 && p2b.second.m == 2 );
+ p2b = std::move(std::as_const(pair_like));
+ VERIFY( p2b.first.m == 3 && p2b.second.m == 3 );
+
+ return true;
+}
+
+template<typename T>
+using pair_like_array = array<T, 2>;
+
+template<typename T>
+using pair_like_tuple = tuple<T, T>;
+
+int
+main()
+{
+ static_assert( test01<pair_like_array>() );
+ static_assert( test02<pair_like_array>() );
+ static_assert( test03<pair_like_array>() );
+ static_assert( test04<pair_like_array>() );
+
+ static_assert( test01<pair_like_tuple>() );
+ static_assert( test02<pair_like_tuple>() );
+ static_assert( test03<pair_like_tuple>() );
+ static_assert( test04<pair_like_tuple>() );
+}
diff --git a/libstdc++-v3/testsuite/20_util/tuple/p2165r4.cc b/libstdc++-v3/testsuite/20_util/tuple/p2165r4.cc
new file mode 100644
index 0000000..e2437c4
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/tuple/p2165r4.cc
@@ -0,0 +1,335 @@
+// Verify P2165R4 enhancements to std::tuple.
+// { dg-do run { target c++23 } }
+
+#include <array>
+#include <tuple>
+#include <utility>
+#include <memory>
+#include <testsuite_hooks.h>
+
+using std::array;
+using std::pair;
+using std::tuple;
+using std::allocator;
+using std::allocator_arg_t;
+using std::allocator_arg;
+
+namespace alloc {
+ struct B01;
+ struct B02;
+}
+
+template<> struct std::uses_allocator<alloc::B01, allocator<int>> : std::true_type { };
+template<> struct std::uses_allocator<alloc::B02, allocator<int>> : std::true_type { };
+
+struct A { };
+
+template<template<typename> class tuple_like_t>
+constexpr bool
+test01()
+{
+ struct B {
+ int m;
+ constexpr B(A&) : m(0) { }
+ constexpr B(A&&) : m(1) { }
+ constexpr B(const A&) : m(2) { }
+ constexpr B(const A&&) : m(3) { }
+ };
+
+ // template<tuple-like UTuple>
+ // constexpr explicit(false) tuple(UTuple&&);
+
+ tuple_like_t<A> tuple_like;
+
+ [&] {
+ tuple<B, B, B> t3b = tuple_like;
+ VERIFY( std::get<0>(t3b).m == 0 && std::get<1>(t3b).m == 0 && std::get<2>(t3b).m == 0 );
+ }();
+ [&] {
+ tuple<B, B, B> t3b = std::move(tuple_like);
+ VERIFY( std::get<0>(t3b).m == 1 && std::get<1>(t3b).m == 1 && std::get<2>(t3b).m == 1 );
+ }();
+ [&] {
+ tuple<B, B, B> t3b = std::as_const(tuple_like);
+ VERIFY( std::get<0>(t3b).m == 2 && std::get<1>(t3b).m == 2 && std::get<2>(t3b).m == 2 );
+ }();
+ [&] {
+ tuple<B, B, B> t3b = std::move(std::as_const(tuple_like));
+ VERIFY( std::get<0>(t3b).m == 3 && std::get<1>(t3b).m == 3 && std::get<2>(t3b).m == 3 );
+ }();
+
+ // Verify dangling checks.
+ static_assert( !std::is_constructible_v<tuple<const int&, int, int>, tuple_like_t<long>> );
+ static_assert( !std::is_constructible_v<tuple<int, const int&, int>, tuple_like_t<long>> );
+ static_assert( !std::is_constructible_v<tuple<int, int, const int&>, tuple_like_t<long>> );
+
+ return true;
+}
+
+namespace alloc
+{
+ struct B01 {
+ int m;
+ B01(A&);
+ B01(A&&);
+ B01(const A&);
+ B01(const A&&);
+ constexpr B01(allocator_arg_t, allocator<int>, A&) : m(0) { }
+ constexpr B01(allocator_arg_t, allocator<int>, A&&) : m(1) { }
+ constexpr B01(allocator_arg_t, allocator<int>, const A&) : m(2) { }
+ constexpr B01(allocator_arg_t, allocator<int>, const A&&) : m(3) { }
+ };
+
+ template<template<typename> class tuple_like_t>
+ constexpr bool
+ test01()
+ {
+ using B = B01;
+
+ // template<tuple-like UTuple>
+ // constexpr explicit(false) tuple(allocator_arg_t, const Alloc&, UTuple&&);
+
+ tuple_like_t<A> tuple_like;
+
+ [&] {
+ tuple<B, B, B> t3b = {allocator_arg, allocator<int>{}, tuple_like};
+ VERIFY( std::get<0>(t3b).m == 0 && std::get<1>(t3b).m == 0 && std::get<2>(t3b).m == 0 );
+ }();
+ [&] {
+ tuple<B, B, B> t3b = {allocator_arg, allocator<int>{}, std::move(tuple_like)};
+ VERIFY( std::get<0>(t3b).m == 1 && std::get<1>(t3b).m == 1 && std::get<2>(t3b).m == 1 );
+ }();
+ [&] {
+ tuple<B, B, B> t3b = {allocator_arg, allocator<int>{}, std::as_const(tuple_like)};
+ VERIFY( std::get<0>(t3b).m == 2 && std::get<1>(t3b).m == 2 && std::get<2>(t3b).m == 2 );
+ }();
+ [&] {
+ tuple<B, B, B> t3b = {allocator_arg, allocator<int>{}, std::move(std::as_const(tuple_like))};
+ VERIFY( std::get<0>(t3b).m == 3 && std::get<1>(t3b).m == 3 && std::get<2>(t3b).m == 3 );
+ }();
+
+ // Verify dangling checks.
+ static_assert( !std::is_constructible_v<tuple<const int&, int, int>,
+ allocator_arg_t, allocator<int>,
+ tuple_like_t<long>> );
+ static_assert( !std::is_constructible_v<tuple<int, const int&, int>,
+ allocator_arg_t, allocator<int>,
+ tuple_like_t<long>> );
+ static_assert( !std::is_constructible_v<tuple<int, int, const int&>,
+ allocator_arg_t, allocator<int>,
+ tuple_like_t<long>> );
+
+ return true;
+ }
+}
+
+template<template<typename> class tuple_like_t>
+constexpr bool
+test02()
+{
+ struct B {
+ int m;
+ constexpr explicit B(A&) : m(0) { }
+ constexpr explicit B(A&&) : m(1) { }
+ constexpr explicit B(const A&) : m(2) { }
+ constexpr explicit B(const A&&) : m(3) { }
+ };
+
+ // template<tuple-like UTuple>
+ // constexpr explicit(true) tuple(UTuple&&);
+
+ static_assert( !std::is_convertible_v<tuple_like_t<A>, tuple<B, B, B>> );
+
+ tuple_like_t<A> tuple_like;
+
+ [&] {
+ tuple<B, B, B> t3b{tuple_like};
+ VERIFY( std::get<0>(t3b).m == 0 && std::get<1>(t3b).m == 0 && std::get<2>(t3b).m == 0 );
+ }();
+ [&] {
+ tuple<B, B, B> t3b{std::move(tuple_like)};
+ VERIFY( std::get<0>(t3b).m == 1 && std::get<1>(t3b).m == 1 && std::get<2>(t3b).m == 1 );
+ }();
+ [&] {
+ tuple<B, B, B> t3b{std::as_const(tuple_like)};
+ VERIFY( std::get<0>(t3b).m == 2 && std::get<1>(t3b).m == 2 && std::get<2>(t3b).m == 2 );
+ }();
+ [&] {
+ tuple<B, B, B> t3b{std::move(std::as_const(tuple_like))};
+ VERIFY( std::get<0>(t3b).m == 3 && std::get<1>(t3b).m == 3 && std::get<2>(t3b).m == 3 );
+ }();
+
+ return true;
+}
+
+namespace alloc
+{
+ struct B02 {
+ int m;
+ explicit B02(A&);
+ explicit B02(A&&);
+ explicit B02(const A&);
+ explicit B02(const A&&);
+ explicit constexpr B02(allocator_arg_t, allocator<int>, A&) : m(0) { }
+ explicit constexpr B02(allocator_arg_t, allocator<int>, A&&) : m(1) { }
+ explicit constexpr B02(allocator_arg_t, allocator<int>, const A&) : m(2) { }
+ explicit constexpr B02(allocator_arg_t, allocator<int>, const A&&) : m(3) { }
+ };
+
+ template<template<typename> class tuple_like_t>
+ constexpr bool
+ test02()
+ {
+ using B = B02;
+
+ // template<tuple-like UTuple>
+ // constexpr explicit(true) tuple(allocator_arg_t, const Alloc&, UTuple&&);
+
+ static_assert( !std::is_convertible_v<tuple_like_t<A>, tuple<B, B, B>> );
+
+ tuple_like_t<A> tuple_like;
+
+ [&] {
+ tuple<B, B, B> t3b{allocator_arg, allocator<int>{}, tuple_like};
+ VERIFY( std::get<0>(t3b).m == 0 && std::get<1>(t3b).m == 0 && std::get<2>(t3b).m == 0 );
+ }();
+ [&] {
+ tuple<B, B, B> t3b{allocator_arg, allocator<int>{}, std::move(tuple_like)};
+ VERIFY( std::get<0>(t3b).m == 1 && std::get<1>(t3b).m == 1 && std::get<2>(t3b).m == 1 );
+ }();
+ [&] {
+ tuple<B, B, B> t3b{allocator_arg, allocator<int>{}, std::as_const(tuple_like)};
+ VERIFY( std::get<0>(t3b).m == 2 && std::get<1>(t3b).m == 2 && std::get<2>(t3b).m == 2 );
+ }();
+ [&] {
+ tuple<B, B, B> t3b{allocator_arg, allocator<int>{}, std::move(std::as_const(tuple_like))};
+ VERIFY( std::get<0>(t3b).m == 3 && std::get<1>(t3b).m == 3 && std::get<2>(t3b).m == 3 );
+ }();
+
+ return true;
+ }
+}
+
+
+template<template<typename> class tuple_like_t>
+constexpr bool
+test03()
+{
+ struct B {
+ int m;
+ constexpr B& operator=(A&) { m = 0; return *this; }
+ constexpr B& operator=(A&&) { m = 1; return *this; }
+ constexpr B& operator=(const A&) { m = 2; return *this; }
+ constexpr B& operator=(const A&&) { m = 3; return *this; }
+ };
+
+ // template<tuple-like UTuple>
+ // constexpr tuple& operator=(UTuple&&);
+
+ tuple_like_t<A> tuple_like;
+
+ tuple<B, B, B> t3b;
+ t3b = tuple_like;
+ VERIFY( std::get<0>(t3b).m == 0 && std::get<1>(t3b).m == 0 && std::get<2>(t3b).m == 0 );
+ t3b = std::move(tuple_like);
+ VERIFY( std::get<0>(t3b).m == 1 && std::get<1>(t3b).m == 1 && std::get<2>(t3b).m == 1 );
+ t3b = std::as_const(tuple_like);
+ VERIFY( std::get<0>(t3b).m == 2 && std::get<1>(t3b).m == 2 && std::get<2>(t3b).m == 2 );
+ t3b = std::move(std::as_const(tuple_like));
+ VERIFY( std::get<0>(t3b).m == 3 && std::get<1>(t3b).m == 3 && std::get<2>(t3b).m == 3 );
+
+ return true;
+}
+
+template<template<typename> class tuple_like_t>
+constexpr bool
+test04()
+{
+ struct B {
+ mutable int m;
+ constexpr const B& operator=(A&) const { m = 0; return *this; }
+ constexpr const B& operator=(A&&) const { m = 1; return *this; }
+ constexpr const B& operator=(const A&) const { m = 2; return *this; }
+ constexpr const B& operator=(const A&&) const { m = 3; return *this; }
+ };
+
+ // template<tuple-like UTuple>
+ // constexpr const tuple& operator=(UTuple&&) const;
+
+ tuple_like_t<A> tuple_like;
+
+ const tuple<B, B, B> t3b;
+ t3b = tuple_like;
+ VERIFY( std::get<0>(t3b).m == 0 && std::get<1>(t3b).m == 0 && std::get<2>(t3b).m == 0 );
+ t3b = std::move(tuple_like);
+ VERIFY( std::get<0>(t3b).m == 1 && std::get<1>(t3b).m == 1 && std::get<2>(t3b).m == 1 );
+ t3b = std::as_const(tuple_like);
+ VERIFY( std::get<0>(t3b).m == 2 && std::get<1>(t3b).m == 2 && std::get<2>(t3b).m == 2 );
+ t3b = std::move(std::as_const(tuple_like));
+ VERIFY( std::get<0>(t3b).m == 3 && std::get<1>(t3b).m == 3 && std::get<2>(t3b).m == 3 );
+
+ return true;
+}
+
+template<template<typename> class tuple_like_t>
+constexpr bool
+test05()
+{
+ // template<tuple-like UTuple>
+ // constexpr bool operator==(const tuple&, const UTuple&);
+
+ static_assert( tuple{1, 2, 3} == tuple_like_t{1, 2, 3} );
+ static_assert( tuple{1, 2, 4} != tuple_like_t{1, 2, 3} );
+ static_assert( tuple_like_t{1, 2, 3} == tuple{1, 2, 3} );
+ static_assert( tuple_like_t{1, 2, 3} != tuple{1, 2, 4} );
+
+ // template<tuple-like UTuple>
+ // constexpr bool operator<=>const tuple&, const UTuple&);
+
+ static_assert( (tuple{1, 2, 3} <=> tuple_like_t{1, 2, 3}) == std::strong_ordering::equal );
+ static_assert( (tuple{1, 2, 4} <=> tuple_like_t{1, 2, 3}) == std::strong_ordering::greater );
+ static_assert( (tuple_like_t{1, 2, 3} <=> tuple{1, 2, 3}) == std::strong_ordering::equal );
+ static_assert( (tuple_like_t{1, 2, 3} <=> tuple{1, 2, 4}) == std::strong_ordering::less );
+
+ static_assert( tuple{1, 2, 4} > tuple_like_t{1, 2, 3} );
+ static_assert( tuple_like_t{1, 2, 3} < tuple{1, 2, 4} );
+
+ // template<tuple-like TTuple, tuple-like UTuple, ...>
+ // struct basic_common_reference<TTuple, UTuple, ...>;
+
+ static_assert( std::same_as<std::common_reference_t<tuple_like_t<int>,
+ tuple<int, long, int>>,
+ tuple<int, long, int>> );
+
+ static_assert( std::same_as<std::common_reference_t<tuple<int, long, int>,
+ tuple_like_t<int>>,
+ tuple<int, long, int>> );
+
+ // template<tuple-like TTuple, tuple-like UTuple>
+ // struct common_type<TTuple, UTuple>;
+
+ static_assert( std::same_as<std::common_type_t<tuple_like_t<const int&>,
+ tuple<int, long, int>>,
+ tuple<int, long, int>> );
+
+ static_assert( std::same_as<std::common_type_t<tuple<int, long, int>,
+ tuple_like_t<const int&>>,
+ tuple<int, long, int>> );
+
+ return true;
+}
+
+template<typename T>
+using tuple_like_array = array<T, 3>;
+
+int
+main()
+{
+ static_assert( test01<tuple_like_array>() );
+ static_assert( alloc::test01<tuple_like_array>() );
+ static_assert( test02<tuple_like_array>() );
+ static_assert( alloc::test02<tuple_like_array>() );
+ static_assert( test03<tuple_like_array>() );
+ static_assert( test04<tuple_like_array>() );
+ static_assert( test05<tuple_like_array>() );
+}
diff --git a/libstdc++-v3/testsuite/std/ranges/zip/1.cc b/libstdc++-v3/testsuite/std/ranges/zip/1.cc
index b7717ae..ea4274d 100644
--- a/libstdc++-v3/testsuite/std/ranges/zip/1.cc
+++ b/libstdc++-v3/testsuite/std/ranges/zip/1.cc
@@ -41,8 +41,8 @@ test01()
VERIFY( i2 == z2.end() );
VERIFY( ranges::size(z2) == 2 );
VERIFY( ranges::size(std::as_const(z2)) == 2 );
- VERIFY( z2[0].first == 1 && z2[0].second == 3 );
- VERIFY( z2[1].first == 2 && z2[1].second == 4 );
+ VERIFY( std::get<0>(z2[0]) == 1 && std::get<1>(z2[0]) == 3 );
+ VERIFY( std::get<0>(z2[1]) == 2 && std::get<1>(z2[1]) == 4 );
for (const auto [x, y] : z2)
{
VERIFY( y - x == 2 );
@@ -124,6 +124,18 @@ test04()
return true;
}
+constexpr bool
+test05()
+{
+ // PR libstdc++/109203
+ int x[] = {1, 1, 2};
+ int y[] = {2, 1, 3};
+ auto r = views::zip(x, y);
+ ranges::sort(r);
+
+ return true;
+}
+
int
main()
{
@@ -131,4 +143,5 @@ main()
static_assert(test02());
static_assert(test03());
static_assert(test04());
+ static_assert(test05());
}