From cf0c3a457319df1e8dc9321227162a7c57169a39 Mon Sep 17 00:00:00 2001 From: Jonathan Wakely Date: Tue, 10 Mar 2020 17:45:45 +0000 Subject: [PATCH] libstdc++: Fix noexcept guarantees for ranges::split_view Also introduce the _M_i_current() accessors to solve the problem of access to the private member of _OuterIter from the iter_move and iter_swap overloads (which are only friends of _InnerIter not _OuterIter). * include/std/ranges (transform_view::_Iterator::__iter_move): Remove. (transform_view::_Iterator::operator*): Add noexcept-specifier. (transform_view::_Iterator::iter_move): Inline __iter_move body here. (split_view::_OuterIter::__current): Add noexcept. (split_view::_InnerIter::__iter_swap): Remove. (split_view::_InnerIter::__iter_move): Remove. (split_view::_InnerIter::_M_i_current): New accessors. (split_view::_InnerIter::__at_end): Use _M_i_current(). (split_view::_InnerIter::operator*): Likewise. (split_view::_InnerIter::operator++): Likewise. (iter_move(const _InnerIter&)): Likewise. (iter_swap(const _InnerIter&, const _InnerIter&)): Likewise. * testsuite/std/ranges/adaptors/split.cc: Check noexcept-specifier for iter_move and iter_swap on split_view's inner iterator. --- libstdc++-v3/ChangeLog | 15 +++++ libstdc++-v3/include/std/ranges | 65 ++++++++++------------ .../testsuite/std/ranges/adaptors/split.cc | 13 +++++ 3 files changed, 58 insertions(+), 35 deletions(-) diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index 9dbc8516..0c447ff 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,5 +1,20 @@ 2020-03-10 Jonathan Wakely + * include/std/ranges (transform_view::_Iterator::__iter_move): Remove. + (transform_view::_Iterator::operator*): Add noexcept-specifier. + (transform_view::_Iterator::iter_move): Inline __iter_move body here. + (split_view::_OuterIter::__current): Add noexcept. + (split_view::_InnerIter::__iter_swap): Remove. + (split_view::_InnerIter::__iter_move): Remove. + (split_view::_InnerIter::_M_i_current): New accessors. + (split_view::_InnerIter::__at_end): Use _M_i_current(). + (split_view::_InnerIter::operator*): Likewise. + (split_view::_InnerIter::operator++): Likewise. + (iter_move(const _InnerIter&)): Likewise. + (iter_swap(const _InnerIter&, const _InnerIter&)): Likewise. + * testsuite/std/ranges/adaptors/split.cc: Check noexcept-specifier + for iter_move and iter_swap on split_view's inner iterator. + PR c++/94117 * include/std/ranges (ranges::transform_view::_Iterator::iter_move): Change expression in noexcept-specifier to match function body. diff --git a/libstdc++-v3/include/std/ranges b/libstdc++-v3/include/std/ranges index 292132d..4dc7342 100644 --- a/libstdc++-v3/include/std/ranges +++ b/libstdc++-v3/include/std/ranges @@ -1679,17 +1679,6 @@ namespace views return input_iterator_tag{}; } - static constexpr decltype(auto) - __iter_move(const _Iterator& __i = {}) - noexcept(noexcept(std::__invoke(*__i._M_parent->_M_fun, - *__i._M_current))) - { - if constexpr (is_lvalue_reference_v) - return std::move(*__i); - else - return *__i; - } - using _Base_iter = iterator_t<_Base>; _Base_iter _M_current = _Base_iter(); @@ -1728,6 +1717,7 @@ namespace views constexpr decltype(auto) operator*() const + noexcept(noexcept(std::__invoke(*_M_parent->_M_fun, *_M_current))) { return std::__invoke(*_M_parent->_M_fun, *_M_current); } constexpr _Iterator& @@ -1837,8 +1827,13 @@ namespace views { return __x._M_current - __y._M_current; } friend constexpr decltype(auto) - iter_move(const _Iterator& __i) noexcept(noexcept(__iter_move(__i))) - { return __iter_move(__i); } + iter_move(const _Iterator& __i) noexcept(noexcept(*__i)) + { + if constexpr (is_lvalue_reference_v) + return std::move(*__i); + else + return *__i; + } friend constexpr void iter_swap(const _Iterator& __x, const _Iterator& __y) @@ -2715,7 +2710,7 @@ namespace views // current of outer-iterator. current is equivalent to current_ if // V models forward_range, and parent_->current_ otherwise. constexpr auto& - __current() + __current() noexcept { if constexpr (forward_range<_Vp>) return _M_current; @@ -2724,7 +2719,7 @@ namespace views } constexpr auto& - __current() const + __current() const noexcept { if constexpr (forward_range<_Vp>) return _M_current; @@ -2860,7 +2855,7 @@ namespace views auto __end = ranges::end(_M_i._M_parent->_M_base); if constexpr (__detail::__tiny_range<_Pattern>) { - const auto& __cur = _M_i.__current(); + const auto& __cur = _M_i_current(); if (__cur == __end) return true; if (__pcur == __pend) @@ -2869,7 +2864,7 @@ namespace views } else { - auto __cur = _M_i.__current(); + auto __cur = _M_i_current(); if (__cur == __end) return true; if (__pcur == __pend) @@ -2896,16 +2891,13 @@ namespace views return _Cat{}; } - static constexpr decltype(auto) - __iter_move(const _InnerIter& __i = {}) - noexcept(noexcept(ranges::iter_move(__i._M_i.__current()))) - { return ranges::iter_move(__i._M_i.__current()); } + constexpr auto& + _M_i_current() noexcept + { return _M_i.__current(); } - static constexpr void - __iter_swap(const _InnerIter& __x = {}, const _InnerIter& __y = {}) - noexcept(noexcept(ranges::iter_swap(__x._M_i.__current(), - __y._M_i.__current()))) - { ranges::iter_swap(__x._M_i.__current(), __y._M_i.__current()); } + constexpr auto& + _M_i_current() const noexcept + { return _M_i.__current(); } _OuterIter<_Const> _M_i = _OuterIter<_Const>(); bool _M_incremented = false; @@ -2926,7 +2918,7 @@ namespace views constexpr decltype(auto) operator*() const - { return *_M_i._M_current; } + { return *_M_i_current(); } constexpr _InnerIter& operator++() @@ -2935,7 +2927,7 @@ namespace views if constexpr (!forward_range<_Base>) if constexpr (_Pattern::size() == 0) return *this; - ++_M_i.__current(); + ++_M_i_current(); return *this; } @@ -2962,14 +2954,16 @@ namespace views { return __x.__at_end(); } friend constexpr decltype(auto) - iter_move(const _InnerIter& __i) noexcept(noexcept(__iter_move())) - { return __iter_move(__i); } + iter_move(const _InnerIter& __i) + noexcept(noexcept(ranges::iter_move(__i._M_i_current()))) + { return ranges::iter_move(__i._M_i_current()); } friend constexpr void iter_swap(const _InnerIter& __x, const _InnerIter& __y) - noexcept(noexcept(__iter_swap())) + noexcept(noexcept(ranges::iter_swap(__x._M_i_current(), + __y._M_i_current()))) requires indirectly_swappable> - { __iter_swap(__x, __y); } + { ranges::iter_swap(__x._M_i_current(), __y._M_i_current()); } }; _Vp _M_base = _Vp(); @@ -3010,8 +3004,8 @@ namespace views begin() { if constexpr (forward_range<_Vp>) - return _OuterIter<__detail::__simple_view<_Vp>>{*this, - ranges::begin(_M_base)}; + return _OuterIter<__detail::__simple_view<_Vp>>{ + *this, ranges::begin(_M_base)}; else { _M_current = ranges::begin(_M_base); @@ -3028,7 +3022,8 @@ namespace views constexpr auto end() requires forward_range<_Vp> && common_range<_Vp> { - return _OuterIter<__detail::__simple_view<_Vp>>{*this, ranges::end(_M_base)}; + return _OuterIter<__detail::__simple_view<_Vp>>{ + *this, ranges::end(_M_base)}; } constexpr auto diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/split.cc b/libstdc++-v3/testsuite/std/ranges/adaptors/split.cc index e755672..abdbfb4 100644 --- a/libstdc++-v3/testsuite/std/ranges/adaptors/split.cc +++ b/libstdc++-v3/testsuite/std/ranges/adaptors/split.cc @@ -121,6 +121,18 @@ test06() b = ranges::begin(v); } +void +test07() +{ + char str[] = "banana split"; + auto split = str | views::split(' '); + auto val = *split.begin(); + auto b = val.begin(); + auto b2 = b++; + static_assert( noexcept(iter_move(b)) ); + static_assert( noexcept(iter_swap(b, b2)) ); +} + int main() { @@ -130,4 +142,5 @@ main() test04(); test05(); test06(); + test07(); } -- 2.7.4