Skip to content

Commit a4ae6c3

Browse files
Implement LWG-4112 has-arrow should require operator->() to be const-qualified (#5152)
Co-authored-by: Casey Carter <[email protected]>
1 parent e0b8a11 commit a4ae6c3

File tree

4 files changed

+67
-1
lines changed

4 files changed

+67
-1
lines changed

stl/inc/ranges

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ namespace ranges {
8989
&& same_as<sentinel_t<_Rng>, sentinel_t<const _Rng>>;
9090

9191
template <class _It>
92-
concept _Has_arrow = input_iterator<_It> && (is_pointer_v<_It> || _Has_member_arrow<_It&>);
92+
concept _Has_arrow = input_iterator<_It> && (is_pointer_v<_It> || _Has_member_arrow<const _It&>);
9393

9494
template <bool _IsWrapped, class _Ty>
9595
using _Maybe_wrapped = conditional_t<_IsWrapped, _Ty, _Unwrapped_t<_Ty>>;

tests/libcxx/expected_results.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,9 @@ std/ranges/range.factories/range.iota.view/iterator/member_typedefs.compile.pass
152152
std/ranges/range.adaptors/range.lazy.split/range.lazy.split.outer.value/ctor.default.pass.cpp FAIL
153153
std/ranges/range.adaptors/range.lazy.split/range.lazy.split.outer.value/ctor.iter.pass.cpp FAIL
154154

155+
# libc++ doesn't implement LWG-4112
156+
std/ranges/range.adaptors/range.join/range.join.iterator/arrow.pass.cpp FAIL
157+
155158
# If any feature-test macro test is failing, this consolidated test will also fail.
156159
std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp FAIL
157160

tests/std/tests/P0896R4_views_filter/test.cpp

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
#include <algorithm>
55
#include <cassert>
6+
#include <cstddef>
67
#include <forward_list>
78
#include <ranges>
89
#include <span>
@@ -347,6 +348,33 @@ using move_only_view = test::range<Category, const int, test::Sized{is_random},
347348
IsCommon, test::CanCompare{derived_from<Category, forward_iterator_tag>},
348349
test::ProxyRef{!derived_from<Category, contiguous_iterator_tag>}, test::CanView::yes, test::Copyability::move_only>;
349350

351+
// LWG-4112 "has-arrow should require operator->() to be const-qualified"
352+
353+
template <class T>
354+
concept CanArrow = requires(T&& t) { forward<T>(t).operator->(); };
355+
356+
enum class arrow_status : bool { bad, good };
357+
358+
template <arrow_status S>
359+
struct arrowed_iterator {
360+
using difference_type = ptrdiff_t;
361+
using value_type = int;
362+
363+
int& operator*() const;
364+
int* operator->()
365+
requires (S == arrow_status::bad);
366+
int* operator->() const
367+
requires (S == arrow_status::good);
368+
arrowed_iterator& operator++();
369+
arrowed_iterator operator++(int);
370+
friend bool operator==(arrowed_iterator, arrowed_iterator);
371+
};
372+
373+
static_assert(CanArrow<ranges::iterator_t<decltype(ranges::subrange<arrowed_iterator<arrow_status::good>>{} //
374+
| views::filter(is_even))>>);
375+
static_assert(!CanArrow<ranges::iterator_t<decltype(ranges::subrange<arrowed_iterator<arrow_status::bad>>{} //
376+
| views::filter(is_even))>>);
377+
350378
int main() {
351379
// Validate views
352380
{ // ... copyable

tests/std/tests/P0896R4_views_join/test.cpp

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#include <algorithm>
55
#include <array>
66
#include <cassert>
7+
#include <cstddef>
78
#include <forward_list>
89
#include <list>
910
#include <ranges>
@@ -688,6 +689,40 @@ constexpr bool test_lwg3791() {
688689
return true;
689690
}
690691

692+
// LWG-4112 "has-arrow should require operator->() to be const-qualified"
693+
694+
template <class T>
695+
concept CanArrow = requires(T&& t) { forward<T>(t).operator->(); };
696+
697+
enum class arrow_status : bool { bad, good };
698+
699+
template <arrow_status S>
700+
struct arrowed_iterator {
701+
using difference_type = ptrdiff_t;
702+
using value_type = int;
703+
704+
int& operator*() const;
705+
int* operator->()
706+
requires (S == arrow_status::bad);
707+
int* operator->() const
708+
requires (S == arrow_status::good);
709+
arrowed_iterator& operator++();
710+
arrowed_iterator operator++(int);
711+
friend bool operator==(arrowed_iterator, arrowed_iterator);
712+
};
713+
714+
void test_lwg_4112() { // COMPILE-ONLY
715+
using good_inner_range = ranges::subrange<arrowed_iterator<arrow_status::good>>;
716+
using good_nested_range = span<const good_inner_range>;
717+
using good_joined_range = decltype(good_nested_range{} | views::join);
718+
static_assert(CanArrow<ranges::iterator_t<good_joined_range>>);
719+
720+
using bad_inner_range = ranges::subrange<arrowed_iterator<arrow_status::bad>>;
721+
using bad_nested_range = span<const bad_inner_range>;
722+
using bad_joined_range = decltype(bad_nested_range{} | views::join);
723+
static_assert(!CanArrow<ranges::iterator_t<bad_joined_range>>);
724+
}
725+
691726
int main() {
692727
// Validate views
693728
constexpr string_view expected = "Hello World!"sv;

0 commit comments

Comments
 (0)