libstdc++: Fix noexcept guarantees for ranges::split_view
authorJonathan Wakely <jwakely@redhat.com>
Tue, 10 Mar 2020 17:45:45 +0000 (17:45 +0000)
committerJonathan Wakely <jwakely@redhat.com>
Tue, 10 Mar 2020 17:45:45 +0000 (17:45 +0000)
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
libstdc++-v3/include/std/ranges
libstdc++-v3/testsuite/std/ranges/adaptors/split.cc

index 9dbc8516457b9a1ff7b6250f59bbb9aa0825b0b8..0c447ff08065f078adbeef584c161ec24d15df35 100644 (file)
@@ -1,5 +1,20 @@
 2020-03-10  Jonathan Wakely  <jwakely@redhat.com>
 
+       * 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.
index 292132db990fcc5c75395829011253690ef577dc..4dc7342e2f78a24f0f925e542d27b231a32a0909 100644 (file)
@@ -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<decltype(*__i)>)
-             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<decltype(*__i)>)
+             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<iterator_t<_Base>>
-         { __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
index e7556725e4f924e36b13d4ab2a553841c7caa699..abdbfb41d8b19f30c13d5878bb119bdf4472cd62 100644 (file)
@@ -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();
 }