diff --git a/stl/inc/ranges b/stl/inc/ranges index 37bb02261d7..38289d7320a 100644 --- a/stl/inc/ranges +++ b/stl/inc/ranges @@ -89,7 +89,7 @@ namespace ranges { && same_as, sentinel_t>; template - concept _Has_arrow = input_iterator<_It> && (is_pointer_v<_It> || _Has_member_arrow<_It&>); + concept _Has_arrow = input_iterator<_It> && (is_pointer_v<_It> || _Has_member_arrow); template using _Maybe_wrapped = conditional_t<_IsWrapped, _Ty, _Unwrapped_t<_Ty>>; diff --git a/tests/libcxx/expected_results.txt b/tests/libcxx/expected_results.txt index 28d2fc987aa..56e77fbc616 100644 --- a/tests/libcxx/expected_results.txt +++ b/tests/libcxx/expected_results.txt @@ -152,6 +152,9 @@ std/ranges/range.factories/range.iota.view/iterator/member_typedefs.compile.pass std/ranges/range.adaptors/range.lazy.split/range.lazy.split.outer.value/ctor.default.pass.cpp FAIL std/ranges/range.adaptors/range.lazy.split/range.lazy.split.outer.value/ctor.iter.pass.cpp FAIL +# libc++ doesn't implement LWG-4112 +std/ranges/range.adaptors/range.join/range.join.iterator/arrow.pass.cpp FAIL + # If any feature-test macro test is failing, this consolidated test will also fail. std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp FAIL diff --git a/tests/std/tests/P0896R4_views_filter/test.cpp b/tests/std/tests/P0896R4_views_filter/test.cpp index 3af705a5198..34f7f04a2dd 100644 --- a/tests/std/tests/P0896R4_views_filter/test.cpp +++ b/tests/std/tests/P0896R4_views_filter/test.cpp @@ -3,6 +3,7 @@ #include #include +#include #include #include #include @@ -347,6 +348,33 @@ using move_only_view = test::range}, test::ProxyRef{!derived_from}, test::CanView::yes, test::Copyability::move_only>; +// LWG-4112 "has-arrow should require operator->() to be const-qualified" + +template +concept CanArrow = requires(T&& t) { forward(t).operator->(); }; + +enum class arrow_status : bool { bad, good }; + +template +struct arrowed_iterator { + using difference_type = ptrdiff_t; + using value_type = int; + + int& operator*() const; + int* operator->() + requires (S == arrow_status::bad); + int* operator->() const + requires (S == arrow_status::good); + arrowed_iterator& operator++(); + arrowed_iterator operator++(int); + friend bool operator==(arrowed_iterator, arrowed_iterator); +}; + +static_assert(CanArrow>{} // + | views::filter(is_even))>>); +static_assert(!CanArrow>{} // + | views::filter(is_even))>>); + int main() { // Validate views { // ... copyable diff --git a/tests/std/tests/P0896R4_views_join/test.cpp b/tests/std/tests/P0896R4_views_join/test.cpp index 46725c14859..d909d97b9c7 100644 --- a/tests/std/tests/P0896R4_views_join/test.cpp +++ b/tests/std/tests/P0896R4_views_join/test.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -688,6 +689,40 @@ constexpr bool test_lwg3791() { return true; } +// LWG-4112 "has-arrow should require operator->() to be const-qualified" + +template +concept CanArrow = requires(T&& t) { forward(t).operator->(); }; + +enum class arrow_status : bool { bad, good }; + +template +struct arrowed_iterator { + using difference_type = ptrdiff_t; + using value_type = int; + + int& operator*() const; + int* operator->() + requires (S == arrow_status::bad); + int* operator->() const + requires (S == arrow_status::good); + arrowed_iterator& operator++(); + arrowed_iterator operator++(int); + friend bool operator==(arrowed_iterator, arrowed_iterator); +}; + +void test_lwg_4112() { // COMPILE-ONLY + using good_inner_range = ranges::subrange>; + using good_nested_range = span; + using good_joined_range = decltype(good_nested_range{} | views::join); + static_assert(CanArrow>); + + using bad_inner_range = ranges::subrange>; + using bad_nested_range = span; + using bad_joined_range = decltype(bad_nested_range{} | views::join); + static_assert(!CanArrow>); +} + int main() { // Validate views constexpr string_view expected = "Hello World!"sv;