Skip to content

Commit 6a56d5c

Browse files
committed
[libc++] Fix LWG3589 "The const lvalue reference overload of get for subrange..."
https://cplusplus.github.io/LWG/issue3589 Differential Revision: https://reviews.llvm.org/D117961
1 parent aefb2e1 commit 6a56d5c

File tree

3 files changed

+64
-15
lines changed

3 files changed

+64
-15
lines changed

libcxx/docs/Status/Cxx2bIssues.csv

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@
130130
`3580 <https://wg21.link/LWG3580>`__,"``iota_view``'s ``iterator``'s binary ``operator+`` should be improved","October 2021","|Complete|","14.0","|ranges|"
131131
`3581 <https://wg21.link/LWG3581>`__,"The range constructor makes ``basic_string_view`` not trivially move constructible","October 2021","|Complete|","14.0","|ranges|"
132132
`3585 <https://wg21.link/LWG3585>`__,"``variant`` converting assignment with immovable alternative","October 2021","",""
133-
`3589 <https://wg21.link/LWG3589>`__,"The ``const`` lvalue reference overload of ``get`` for ``subrange`` does not constrain ``I`` to be ``copyable`` when ``N == 0``","October 2021","","","|ranges|"
133+
`3589 <https://wg21.link/LWG3589>`__,"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|"
134134
`3590 <https://wg21.link/LWG3590>`__,"``split_view::base() const &`` is overconstrained","October 2021","","","|ranges|"
135135
`3591 <https://wg21.link/LWG3591>`__,"``lazy_split_view<input_view>::inner-iterator::base() &&`` invalidates outer iterators","October 2021","","","|ranges|"
136136
`3592 <https://wg21.link/LWG3592>`__,"``lazy_split_view`` needs to check the simpleness of Pattern","October 2021","","","|ranges|"

libcxx/include/__ranges/subrange.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,7 @@ namespace ranges {
227227
-> subrange<iterator_t<_Range>, sentinel_t<_Range>, subrange_kind::sized>;
228228

229229
template<size_t _Index, class _Iter, class _Sent, subrange_kind _Kind>
230-
requires (_Index < 2)
230+
requires ((_Index == 0 && copyable<_Iter>) || _Index == 1)
231231
_LIBCPP_HIDE_FROM_ABI
232232
constexpr auto get(const subrange<_Iter, _Sent, _Kind>& __subrange) {
233233
if constexpr (_Index == 0)

libcxx/test/std/ranges/range.utility/range.subrange/get.pass.cpp

Lines changed: 62 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -17,26 +17,75 @@
1717
#include <cassert>
1818
#include "test_macros.h"
1919
#include "test_iterators.h"
20-
#include "types.h"
2120

2221
template<size_t I, class S>
23-
concept GetInvocable = requires {
22+
concept HasGet = requires {
2423
std::get<I>(std::declval<S>());
2524
};
2625

27-
static_assert( GetInvocable<0, std::ranges::subrange<int*>>);
28-
static_assert( GetInvocable<1, std::ranges::subrange<int*>>);
29-
static_assert(!GetInvocable<2, std::ranges::subrange<int*>>);
30-
static_assert(!GetInvocable<3, std::ranges::subrange<int*>>);
26+
static_assert( HasGet<0, std::ranges::subrange<int*>>);
27+
static_assert( HasGet<1, std::ranges::subrange<int*>>);
28+
static_assert(!HasGet<2, std::ranges::subrange<int*>>);
29+
static_assert(!HasGet<3, std::ranges::subrange<int*>>);
3130

3231
constexpr bool test() {
33-
std::ranges::subrange<int*> a(globalBuff, globalBuff + 8, 8);
34-
assert(std::get<0>(a) == a.begin());
35-
assert(std::get<1>(a) == a.end());
36-
37-
assert(a.begin() == std::get<0>(std::move(a)));
38-
std::ranges::subrange<int*> b(globalBuff, globalBuff + 8, 8);
39-
assert(b.end() == std::get<1>(std::move(b)));
32+
{
33+
using It = int*;
34+
using Sent = sentinel_wrapper<int*>;
35+
int a[] = {1, 2, 3};
36+
using R = std::ranges::subrange<It, Sent, std::ranges::subrange_kind::unsized>;
37+
R r = R(It(a), Sent(It(a + 3)));
38+
ASSERT_SAME_TYPE(decltype(std::get<0>(r)), It);
39+
ASSERT_SAME_TYPE(decltype(std::get<1>(r)), Sent);
40+
ASSERT_SAME_TYPE(decltype(std::get<0>(static_cast<R&&>(r))), It);
41+
ASSERT_SAME_TYPE(decltype(std::get<1>(static_cast<R&&>(r))), Sent);
42+
ASSERT_SAME_TYPE(decltype(std::get<0>(static_cast<const R&>(r))), It);
43+
ASSERT_SAME_TYPE(decltype(std::get<1>(static_cast<const R&>(r))), Sent);
44+
ASSERT_SAME_TYPE(decltype(std::get<0>(static_cast<const R&&>(r))), It);
45+
ASSERT_SAME_TYPE(decltype(std::get<1>(static_cast<const R&&>(r))), Sent);
46+
assert(base(std::get<0>(r)) == a); // copy from It
47+
assert(base(base(std::get<1>(r))) == a + 3); // copy from Sent
48+
assert(base(std::get<0>(std::move(r))) == a); // copy from It
49+
assert(base(base(std::get<1>(std::move(r)))) == a + 3); // copy from Sent
50+
}
51+
{
52+
using It = int*;
53+
using Sent = sentinel_wrapper<int*>;
54+
int a[] = {1, 2, 3};
55+
using R = std::ranges::subrange<It, Sent, std::ranges::subrange_kind::sized>;
56+
R r = R(It(a), Sent(It(a + 3)), 3);
57+
ASSERT_SAME_TYPE(decltype(std::get<0>(r)), It);
58+
ASSERT_SAME_TYPE(decltype(std::get<1>(r)), Sent);
59+
ASSERT_SAME_TYPE(decltype(std::get<0>(static_cast<R&&>(r))), It);
60+
ASSERT_SAME_TYPE(decltype(std::get<1>(static_cast<R&&>(r))), Sent);
61+
ASSERT_SAME_TYPE(decltype(std::get<0>(static_cast<const R&>(r))), It);
62+
ASSERT_SAME_TYPE(decltype(std::get<1>(static_cast<const R&>(r))), Sent);
63+
ASSERT_SAME_TYPE(decltype(std::get<0>(static_cast<const R&&>(r))), It);
64+
ASSERT_SAME_TYPE(decltype(std::get<1>(static_cast<const R&&>(r))), Sent);
65+
assert(base(std::get<0>(r)) == a); // copy from It
66+
assert(base(base(std::get<1>(r))) == a + 3); // copy from Sent
67+
assert(base(std::get<0>(std::move(r))) == a); // copy from It
68+
assert(base(base(std::get<1>(std::move(r)))) == a + 3); // copy from Sent
69+
}
70+
{
71+
// Test the fix for LWG 3589.
72+
using It = cpp20_input_iterator<int*>;
73+
using Sent = sentinel_wrapper<It>;
74+
int a[] = {1, 2, 3};
75+
using R = std::ranges::subrange<It, Sent>;
76+
R r = R(It(a), Sent(It(a + 3)));
77+
static_assert(!HasGet<0, R&>);
78+
ASSERT_SAME_TYPE(decltype(std::get<1>(r)), Sent);
79+
ASSERT_SAME_TYPE(decltype(std::get<0>(static_cast<R&&>(r))), It);
80+
ASSERT_SAME_TYPE(decltype(std::get<1>(static_cast<R&&>(r))), Sent);
81+
static_assert(!HasGet<0, const R&>);
82+
ASSERT_SAME_TYPE(decltype(std::get<1>(static_cast<const R&>(r))), Sent);
83+
static_assert(!HasGet<0, const R&&>);
84+
ASSERT_SAME_TYPE(decltype(std::get<1>(static_cast<const R&&>(r))), Sent);
85+
assert(base(base(std::get<1>(r))) == a + 3); // copy from Sent
86+
assert(base(std::get<0>(std::move(r))) == a); // move from It
87+
assert(base(base(std::get<1>(std::move(r)))) == a + 3); // copy from Sent
88+
}
4089

4190
return true;
4291
}

0 commit comments

Comments
 (0)