From a7c73b5f1caac74c1e1dec6b1587b4c994576f37 Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Wed, 27 Nov 2024 21:13:14 +0800 Subject: [PATCH 1/4] Implement LWG-4112 --- stl/inc/ranges | 2 +- tests/std/tests/P0896R4_views_filter/test.cpp | 48 ++++++++++++++++ tests/std/tests/P0896R4_views_join/test.cpp | 55 +++++++++++++++++++ 3 files changed, 104 insertions(+), 1 deletion(-) 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/std/tests/P0896R4_views_filter/test.cpp b/tests/std/tests/P0896R4_views_filter/test.cpp index 3af705a5198..3234f561374 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,53 @@ using move_only_view = test::range}, test::ProxyRef{!derived_from}, test::CanView::yes, test::Copyability::move_only>; +// LWG-4112 "possibly-const-range should prefer returning const R&" + +template +concept CanArrow = requires(T&& t) { forward(t).operator->(); }; + +enum class arrow_status : bool { bad, good }; + +template +struct arrowed_iterator { + using value_type = int; + using difference_type = ptrdiff_t; + + int& operator*() const { + return *p_; + } + + int* operator->() + requires (S == arrow_status::bad) + { + return p_; + } + int* operator->() const + requires (S == arrow_status::good) + { + return p_; + } + + arrowed_iterator& operator++() { + ++p_; + return *this; + } + arrowed_iterator operator++(int) { + auto old = *this; + ++*this; + return old; + } + + friend bool operator==(arrowed_iterator, arrowed_iterator) = default; + + int* p_; +}; + +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..fbfc31afb79 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,60 @@ constexpr bool test_lwg3791() { return true; } +// LWG-4112 "possibly-const-range should prefer returning const R&" + +template +concept CanArrow = requires(T&& t) { forward(t).operator->(); }; + +enum class arrow_status : bool { bad, good }; + +template +struct arrowed_iterator { + using value_type = int; + using difference_type = ptrdiff_t; + + int& operator*() const { + return *p_; + } + + int* operator->() + requires (S == arrow_status::bad) + { + return p_; + } + int* operator->() const + requires (S == arrow_status::good) + { + return p_; + } + + arrowed_iterator& operator++() { + ++p_; + return *this; + } + arrowed_iterator operator++(int) { + auto old = *this; + ++*this; + return old; + } + + friend bool operator==(arrowed_iterator, arrowed_iterator) = default; + + int* p_; +}; + +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; From 0d4faf7bb0f3952f73650ba3ef4734e2847fc2bb Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Wed, 27 Nov 2024 21:47:09 +0800 Subject: [PATCH 2/4] Skip one libcxx test --- tests/libcxx/expected_results.txt | 3 +++ 1 file changed, 3 insertions(+) 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 From de71dca1669b633cbcf4614d60ace6ac52914069 Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Thu, 28 Nov 2024 00:12:06 +0800 Subject: [PATCH 3/4] Fix copy-pasta! --- tests/std/tests/P0896R4_views_filter/test.cpp | 2 +- tests/std/tests/P0896R4_views_join/test.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/std/tests/P0896R4_views_filter/test.cpp b/tests/std/tests/P0896R4_views_filter/test.cpp index 3234f561374..871415a2d24 100644 --- a/tests/std/tests/P0896R4_views_filter/test.cpp +++ b/tests/std/tests/P0896R4_views_filter/test.cpp @@ -348,7 +348,7 @@ using move_only_view = test::range}, test::ProxyRef{!derived_from}, test::CanView::yes, test::Copyability::move_only>; -// LWG-4112 "possibly-const-range should prefer returning const R&" +// LWG-4112 "has-arrow should require operator->() to be const-qualified" template concept CanArrow = requires(T&& t) { forward(t).operator->(); }; diff --git a/tests/std/tests/P0896R4_views_join/test.cpp b/tests/std/tests/P0896R4_views_join/test.cpp index fbfc31afb79..f23232c06b1 100644 --- a/tests/std/tests/P0896R4_views_join/test.cpp +++ b/tests/std/tests/P0896R4_views_join/test.cpp @@ -689,7 +689,7 @@ constexpr bool test_lwg3791() { return true; } -// LWG-4112 "possibly-const-range should prefer returning const R&" +// LWG-4112 "has-arrow should require operator->() to be const-qualified" template concept CanArrow = requires(T&& t) { forward(t).operator->(); }; From c9c1b0fef76e09827e09ffc1d407ea4bab40668b Mon Sep 17 00:00:00 2001 From: Casey Carter Date: Wed, 27 Nov 2024 09:04:06 -0800 Subject: [PATCH 4/4] Casey's review comments --- tests/std/tests/P0896R4_views_filter/test.cpp | 34 ++++--------------- tests/std/tests/P0896R4_views_join/test.cpp | 34 ++++--------------- 2 files changed, 14 insertions(+), 54 deletions(-) diff --git a/tests/std/tests/P0896R4_views_filter/test.cpp b/tests/std/tests/P0896R4_views_filter/test.cpp index 871415a2d24..34f7f04a2dd 100644 --- a/tests/std/tests/P0896R4_views_filter/test.cpp +++ b/tests/std/tests/P0896R4_views_filter/test.cpp @@ -357,37 +357,17 @@ enum class arrow_status : bool { bad, good }; template struct arrowed_iterator { - using value_type = int; using difference_type = ptrdiff_t; + using value_type = int; - int& operator*() const { - return *p_; - } - + int& operator*() const; int* operator->() - requires (S == arrow_status::bad) - { - return p_; - } + requires (S == arrow_status::bad); int* operator->() const - requires (S == arrow_status::good) - { - return p_; - } - - arrowed_iterator& operator++() { - ++p_; - return *this; - } - arrowed_iterator operator++(int) { - auto old = *this; - ++*this; - return old; - } - - friend bool operator==(arrowed_iterator, arrowed_iterator) = default; - - int* p_; + requires (S == arrow_status::good); + arrowed_iterator& operator++(); + arrowed_iterator operator++(int); + friend bool operator==(arrowed_iterator, arrowed_iterator); }; static_assert(CanArrow>{} // diff --git a/tests/std/tests/P0896R4_views_join/test.cpp b/tests/std/tests/P0896R4_views_join/test.cpp index f23232c06b1..d909d97b9c7 100644 --- a/tests/std/tests/P0896R4_views_join/test.cpp +++ b/tests/std/tests/P0896R4_views_join/test.cpp @@ -698,37 +698,17 @@ enum class arrow_status : bool { bad, good }; template struct arrowed_iterator { - using value_type = int; using difference_type = ptrdiff_t; + using value_type = int; - int& operator*() const { - return *p_; - } - + int& operator*() const; int* operator->() - requires (S == arrow_status::bad) - { - return p_; - } + requires (S == arrow_status::bad); int* operator->() const - requires (S == arrow_status::good) - { - return p_; - } - - arrowed_iterator& operator++() { - ++p_; - return *this; - } - arrowed_iterator operator++(int) { - auto old = *this; - ++*this; - return old; - } - - friend bool operator==(arrowed_iterator, arrowed_iterator) = default; - - int* p_; + 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