diff --git a/libcxx/docs/Status/Cxx2bIssues.csv b/libcxx/docs/Status/Cxx2bIssues.csv --- a/libcxx/docs/Status/Cxx2bIssues.csv +++ b/libcxx/docs/Status/Cxx2bIssues.csv @@ -130,7 +130,7 @@ `3580 `__,"``iota_view``'s ``iterator``'s binary ``operator+`` should be improved","October 2021","|Complete|","14.0","|ranges|" `3581 `__,"The range constructor makes ``basic_string_view`` not trivially move constructible","October 2021","|Complete|","14.0","|ranges|" `3585 `__,"``variant`` converting assignment with immovable alternative","October 2021","","" -`3589 `__,"The ``const`` lvalue reference overload of ``get`` for ``subrange`` does not constrain ``I`` to be ``copyable`` when ``N == 0``","October 2021","","","|ranges|" +`3589 `__,"The ``const`` lvalue reference overload of ``get`` for ``subrange`` does not constrain ``I`` to be ``copyable`` when ``N == 0``","October 2021","|Complete|","14.0","|ranges|" `3590 `__,"``split_view::base() const &`` is overconstrained","October 2021","","","|ranges|" `3591 `__,"``lazy_split_view::inner-iterator::base() &&`` invalidates outer iterators","October 2021","","","|ranges|" `3592 `__,"``lazy_split_view`` needs to check the simpleness of Pattern","October 2021","","","|ranges|" diff --git a/libcxx/include/__ranges/subrange.h b/libcxx/include/__ranges/subrange.h --- a/libcxx/include/__ranges/subrange.h +++ b/libcxx/include/__ranges/subrange.h @@ -227,7 +227,7 @@ -> subrange, sentinel_t<_Range>, subrange_kind::sized>; template - requires (_Index < 2) + requires ((_Index == 0 && copyable<_Iter>) || _Index == 1) _LIBCPP_HIDE_FROM_ABI constexpr auto get(const subrange<_Iter, _Sent, _Kind>& __subrange) { if constexpr (_Index == 0) diff --git a/libcxx/test/std/ranges/range.utility/range.subrange/get.pass.cpp b/libcxx/test/std/ranges/range.utility/range.subrange/get.pass.cpp --- a/libcxx/test/std/ranges/range.utility/range.subrange/get.pass.cpp +++ b/libcxx/test/std/ranges/range.utility/range.subrange/get.pass.cpp @@ -17,26 +17,75 @@ #include #include "test_macros.h" #include "test_iterators.h" -#include "types.h" template -concept GetInvocable = requires { +concept HasGet = requires { std::get(std::declval()); }; -static_assert( GetInvocable<0, std::ranges::subrange>); -static_assert( GetInvocable<1, std::ranges::subrange>); -static_assert(!GetInvocable<2, std::ranges::subrange>); -static_assert(!GetInvocable<3, std::ranges::subrange>); +static_assert( HasGet<0, std::ranges::subrange>); +static_assert( HasGet<1, std::ranges::subrange>); +static_assert(!HasGet<2, std::ranges::subrange>); +static_assert(!HasGet<3, std::ranges::subrange>); constexpr bool test() { - std::ranges::subrange a(globalBuff, globalBuff + 8, 8); - assert(std::get<0>(a) == a.begin()); - assert(std::get<1>(a) == a.end()); - - assert(a.begin() == std::get<0>(std::move(a))); - std::ranges::subrange b(globalBuff, globalBuff + 8, 8); - assert(b.end() == std::get<1>(std::move(b))); + { + using It = int*; + using Sent = sentinel_wrapper; + int a[] = {1, 2, 3}; + using R = std::ranges::subrange; + R r = R(It(a), Sent(It(a + 3))); + ASSERT_SAME_TYPE(decltype(std::get<0>(r)), It); + ASSERT_SAME_TYPE(decltype(std::get<1>(r)), Sent); + ASSERT_SAME_TYPE(decltype(std::get<0>(static_cast(r))), It); + ASSERT_SAME_TYPE(decltype(std::get<1>(static_cast(r))), Sent); + ASSERT_SAME_TYPE(decltype(std::get<0>(static_cast(r))), It); + ASSERT_SAME_TYPE(decltype(std::get<1>(static_cast(r))), Sent); + ASSERT_SAME_TYPE(decltype(std::get<0>(static_cast(r))), It); + ASSERT_SAME_TYPE(decltype(std::get<1>(static_cast(r))), Sent); + assert(base(std::get<0>(r)) == a); // copy from It + assert(base(base(std::get<1>(r))) == a + 3); // copy from Sent + assert(base(std::get<0>(std::move(r))) == a); // copy from It + assert(base(base(std::get<1>(std::move(r)))) == a + 3); // copy from Sent + } + { + using It = int*; + using Sent = sentinel_wrapper; + int a[] = {1, 2, 3}; + using R = std::ranges::subrange; + R r = R(It(a), Sent(It(a + 3)), 3); + ASSERT_SAME_TYPE(decltype(std::get<0>(r)), It); + ASSERT_SAME_TYPE(decltype(std::get<1>(r)), Sent); + ASSERT_SAME_TYPE(decltype(std::get<0>(static_cast(r))), It); + ASSERT_SAME_TYPE(decltype(std::get<1>(static_cast(r))), Sent); + ASSERT_SAME_TYPE(decltype(std::get<0>(static_cast(r))), It); + ASSERT_SAME_TYPE(decltype(std::get<1>(static_cast(r))), Sent); + ASSERT_SAME_TYPE(decltype(std::get<0>(static_cast(r))), It); + ASSERT_SAME_TYPE(decltype(std::get<1>(static_cast(r))), Sent); + assert(base(std::get<0>(r)) == a); // copy from It + assert(base(base(std::get<1>(r))) == a + 3); // copy from Sent + assert(base(std::get<0>(std::move(r))) == a); // copy from It + assert(base(base(std::get<1>(std::move(r)))) == a + 3); // copy from Sent + } + { + // Test the fix for LWG 3589. + using It = cpp20_input_iterator; + using Sent = sentinel_wrapper; + int a[] = {1, 2, 3}; + using R = std::ranges::subrange; + R r = R(It(a), Sent(It(a + 3))); + static_assert(!HasGet<0, R&>); + ASSERT_SAME_TYPE(decltype(std::get<1>(r)), Sent); + ASSERT_SAME_TYPE(decltype(std::get<0>(static_cast(r))), It); + ASSERT_SAME_TYPE(decltype(std::get<1>(static_cast(r))), Sent); + static_assert(!HasGet<0, const R&>); + ASSERT_SAME_TYPE(decltype(std::get<1>(static_cast(r))), Sent); + static_assert(!HasGet<0, const R&&>); + ASSERT_SAME_TYPE(decltype(std::get<1>(static_cast(r))), Sent); + assert(base(base(std::get<1>(r))) == a + 3); // copy from Sent + assert(base(std::get<0>(std::move(r))) == a); // move from It + assert(base(base(std::get<1>(std::move(r)))) == a + 3); // copy from Sent + } return true; }