From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 1464) id 0FCDF3890410; Thu, 23 Jul 2020 19:00:24 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 0FCDF3890410 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1595530824; bh=VGsXkM+fWY3nYTKvZIiFY3juEiqKJLnqHNFOeBe5tWQ=; h=From:To:Subject:Date:From; b=r53y2W8zGi9ZGcOQtIO2P67xwn85dK+Hy9GWgSYOK+VOA8EPwFtbVr5g9qP2cDUtd HT26mmE5KLzn2KkBSy48XCRwMLDrAijf/YPqqFo3v2diuqUkD8XZiClrwLfNsunNxQ +k2AT5USvstleGWe13E2DahMeq5jzUSbMuKbZCaM= Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: Peter Bergner To: gcc-cvs@gcc.gnu.org, libstdc++-cvs@gcc.gnu.org Subject: [gcc(refs/vendors/ibm/heads/gcc-10-branch)] libstdc++: Fix view adaptors for mixed-const sentinels and iterators (PR 95322) X-Act-Checkin: gcc X-Git-Author: Jonathan Wakely X-Git-Refname: refs/vendors/ibm/heads/gcc-10-branch X-Git-Oldrev: 6b19640035d2df46758c7d31e5aab1186518e514 X-Git-Newrev: 38250e577e26de7aace65b4d32a94a1404f076a9 Message-Id: <20200723190024.0FCDF3890410@sourceware.org> Date: Thu, 23 Jul 2020 19:00:24 +0000 (GMT) X-BeenThere: libstdc++-cvs@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Libstdc++-cvs mailing list List-Unsubscribe: , List-Archive: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 23 Jul 2020 19:00:24 -0000 https://gcc.gnu.org/g:38250e577e26de7aace65b4d32a94a1404f076a9 commit 38250e577e26de7aace65b4d32a94a1404f076a9 Author: Jonathan Wakely Date: Wed May 27 22:08:15 2020 +0100 libstdc++: Fix view adaptors for mixed-const sentinels and iterators (PR 95322) The bug report is that transform_view's sentinel cannot be compared to its iterator. The comparison is supposed to use operator==(iterator, sentinel) after converting sentinel to sentinel. However, the operator== is a hidden friend so is not a candidate when comparing iterator with sentinel. The required conversion would only happen if we'd found the operator, but we can't find the operator until after the conversion happens. A new LWG issue has been reported, but not yet assigned a number. The solution suggested by Casey Carter is to make the hidden friends of the sentinel types work with iterators of any const-ness, so that no conversions are required. Patrick Palka observed that join_view has a similar problem and a similar fix is used for its sentinel. PR libstdc++/95322 * include/std/ranges (transform_view::_Sentinel): Allow hidden friends to work with _Iterator and _Iterator. (join_view::_Sentinel): Likewise. * testsuite/std/ranges/adaptors/95322.cc: New test. (cherry picked from commit 6c2582c0406250c66e2eb3651f8e8638796b7f53) Diff: --- libstdc++-v3/include/std/ranges | 67 +++++++++++++--------- .../testsuite/std/ranges/adaptors/95322.cc | 48 +++++++++------- 2 files changed, 68 insertions(+), 47 deletions(-) diff --git a/libstdc++-v3/include/std/ranges b/libstdc++-v3/include/std/ranges index 0c602c7200f..b8023e67c9f 100644 --- a/libstdc++-v3/include/std/ranges +++ b/libstdc++-v3/include/std/ranges @@ -1853,7 +1853,7 @@ namespace views { return ranges::iter_swap(__x._M_current, __y._M_current); } friend _Iterator; - friend _Sentinel<_Const>; + template friend struct _Sentinel; }; template @@ -1863,13 +1863,15 @@ namespace views using _Parent = __detail::__maybe_const_t<_Const, transform_view>; using _Base = __detail::__maybe_const_t<_Const, _Vp>; - constexpr range_difference_t<_Base> - __distance_from(const _Iterator<_Const>& __i) const - { return _M_end - __i._M_current; } + template + constexpr range_difference_t<_Base> + __distance_from(const _Iterator<_Const2>& __i) const + { return _M_end - __i._M_current; } - constexpr bool - __equal(const _Iterator<_Const>& __i) const - { return __i._M_current == _M_end; } + template + constexpr bool + __equal(const _Iterator<_Const2>& __i) const + { return __i._M_current == _M_end; } sentinel_t<_Base> _M_end = sentinel_t<_Base>(); @@ -1892,19 +1894,26 @@ namespace views base() const { return _M_end; } - friend constexpr bool - operator==(const _Iterator<_Const>& __x, const _Sentinel& __y) - { return __y.__equal(__x); } - - friend constexpr range_difference_t<_Base> - operator-(const _Iterator<_Const>& __x, const _Sentinel& __y) - requires sized_sentinel_for, iterator_t<_Base>> - { return -__y.__distance_from(__x); } - - friend constexpr range_difference_t<_Base> - operator-(const _Sentinel& __y, const _Iterator<_Const>& __x) - requires sized_sentinel_for, iterator_t<_Base>> - { return __y.__distance_from(__x); } + template + requires sentinel_for, + iterator_t<__detail::__maybe_const_t<_Const2, _Vp>>> + friend constexpr bool + operator==(const _Iterator<_Const2>& __x, const _Sentinel& __y) + { return __y.__equal(__x); } + + template + requires sized_sentinel_for, + iterator_t<__detail::__maybe_const_t<_Const2, _Vp>>> + friend constexpr range_difference_t<_Base> + operator-(const _Iterator<_Const2>& __x, const _Sentinel& __y) + { return -__y.__distance_from(__x); } + + template + requires sized_sentinel_for, + iterator_t<__detail::__maybe_const_t<_Const2, _Vp>>> + friend constexpr range_difference_t<_Base> + operator-(const _Sentinel& __y, const _Iterator<_Const2>& __x) + { return __y.__distance_from(__x); } friend _Sentinel; }; @@ -2571,7 +2580,7 @@ namespace views { return ranges::iter_swap(__x._M_inner, __y._M_inner); } friend _Iterator; - friend _Sentinel<_Const>; + template friend struct _Sentinel; }; template @@ -2581,9 +2590,10 @@ namespace views using _Parent = __detail::__maybe_const_t<_Const, join_view>; using _Base = __detail::__maybe_const_t<_Const, _Vp>; - constexpr bool - __equal(const _Iterator<_Const>& __i) const - { return __i._M_outer == _M_end; } + template + constexpr bool + __equal(const _Iterator<_Const2>& __i) const + { return __i._M_outer == _M_end; } sentinel_t<_Base> _M_end = sentinel_t<_Base>(); @@ -2601,9 +2611,12 @@ namespace views : _M_end(std::move(__s._M_end)) { } - friend constexpr bool - operator==(const _Iterator<_Const>& __x, const _Sentinel& __y) - { return __y.__equal(__x); } + template + requires sentinel_for, + iterator_t<__detail::__maybe_const_t<_Const2, _Vp>>> + friend constexpr bool + operator==(const _Iterator<_Const2>& __x, const _Sentinel& __y) + { return __y.__equal(__x); } friend _Sentinel; }; diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/95322.cc b/libstdc++-v3/testsuite/std/ranges/adaptors/95322.cc index 44619d6719a..9279d5520a8 100644 --- a/libstdc++-v3/testsuite/std/ranges/adaptors/95322.cc +++ b/libstdc++-v3/testsuite/std/ranges/adaptors/95322.cc @@ -15,36 +15,44 @@ // with this library; see the file COPYING3. If not see // . -// { dg-options "-std=gnu++2a" } +// { dg-options "-std=gnu++20" } // { dg-do run { target c++2a } } #include -#include -#include +#include -namespace ranges = std::ranges; -namespace views = std::views; +using __gnu_test::test_forward_range; void test01() { - std::list container{1, 2, 3, 4, 5}; - auto v = (container - | views::take(3) - | views::transform(std::negate{}) - | views::common); - auto i = ranges::cbegin(v); - VERIFY( *i == -1 ); - ++i; - VERIFY( *i == -2 ); - ++i; - VERIFY( *i == -3 ); - ++i; - VERIFY( i == ranges::end(v) ); + // PR libstdc++/95322 + int a[2]{1, 2}; + test_forward_range v{a}; + auto view1 = v | std::views::take(2); + auto view2 = view1 | std::views::transform(std::identity{}); + const bool eq = std::ranges::cbegin(view2) == std::ranges::end(view2); + VERIFY( !eq ); } -int -main() +void +test02() +{ + using irange = test_forward_range; + + int a[2]{1, 2}; + int b[3]{3, 4, 5}; + irange u[2]{ irange{a}, irange{b} }; + test_forward_range v{u}; + auto view = (std::views::counted(v.begin(), 2) + | std::views::transform(std::identity{}) + | std::views::join); + const bool eq = std::ranges::cbegin(view) == std::ranges::end(view); + VERIFY( !eq ); +} + +int main() { test01(); + test02(); }