diff mbox series

libstdc++/ranges: Implement various small LWG issues

Message ID 20241004020844.116894-1-ppalka@redhat.com
State New
Headers show
Series libstdc++/ranges: Implement various small LWG issues | expand

Commit Message

Patrick Palka Oct. 4, 2024, 2:08 a.m. UTC
Tested on x86_64-pc-linux-gnu, does this look OK for trunk/14 and perhaps
13?

-- >8 --

This implements the following small LWG issues:

  3848. adjacent_view, adjacent_transform_view and slide_view missing base accessor
  3851. chunk_view::inner-iterator missing custom iter_move and iter_swap
  3947. Unexpected constraints on adjacent_transform_view::base()
  4001. iota_view should provide empty
  4012. common_view::begin/end are missing the simple-view check
  4013. lazy_split_view::outer-iterator::value_type should not provide default constructor
  4035. single_view should provide empty
  4053. Unary call to std::views::repeat does not decay the argument
  4054. Repeating a repeat_view should repeat the view

libstdc++-v3/ChangeLog:

	* include/std/ranges (single_view::empty): Define as per LWG 4035.
	(iota_view::empty): Define as per LWG 4001.
	(lazy_split_view::_OuterIter::value_type): Remove default
	constructor and make other constructor private as per LWG 4013.
	(common_view::begin): Disable non-const overload for simple
	views as per LWG 4012.
	(common_view::end): Likewise.
	(adjacent_view::base): Define as per LWG 3848.
	(adjacent_transform_view::base): Likewise.
	(chunk_view::_InnerIter::iter_move): Define as per LWG 3851.
	(chunk_view::_InnerIter::itep_swap): Likewise.
	(slide_view::base): Define as per LWG 3848.
	(repeat_view): Adjust deduction guide as per LWG 4053.
	(_Repeat::operator()): Adjust single-parameter overload
	as per LWG 4054.
	* testsuite/std/ranges/adaptors/adjacent/1.cc: Verify existence
	of base member function.
	* testsuite/std/ranges/adaptors/adjacent_transform/1.cc: Likewise.
	* testsuite/std/ranges/adaptors/chunk/1.cc: Test LWG 3851 example.
	* testsuite/std/ranges/adaptors/slide/1.cc: Verify existence of
	base member function.
	* testsuite/std/ranges/iota/iota_view.cc: Test LWG 4001 example.
	* testsuite/std/ranges/repeat/1.cc: Test LWG 4053/4054 examples.
---
 libstdc++-v3/include/std/ranges               | 84 +++++++++++++++++--
 .../std/ranges/adaptors/adjacent/1.cc         |  3 +
 .../ranges/adaptors/adjacent_transform/1.cc   |  3 +
 .../testsuite/std/ranges/adaptors/chunk/1.cc  | 15 ++++
 .../testsuite/std/ranges/adaptors/slide/1.cc  |  3 +
 .../testsuite/std/ranges/iota/iota_view.cc    | 12 +++
 libstdc++-v3/testsuite/std/ranges/repeat/1.cc | 23 +++++
 7 files changed, 135 insertions(+), 8 deletions(-)

Comments

Jonathan Wakely Oct. 4, 2024, 11:30 a.m. UTC | #1
On Fri, 4 Oct 2024 at 03:09, Patrick Palka <ppalka@redhat.com> wrote:
>
> Tested on x86_64-pc-linux-gnu, does this look OK for trunk/14 and perhaps
> 13?

OK for all, thanks.

>
> -- >8 --
>
> This implements the following small LWG issues:
>
>   3848. adjacent_view, adjacent_transform_view and slide_view missing base accessor
>   3851. chunk_view::inner-iterator missing custom iter_move and iter_swap
>   3947. Unexpected constraints on adjacent_transform_view::base()
>   4001. iota_view should provide empty
>   4012. common_view::begin/end are missing the simple-view check
>   4013. lazy_split_view::outer-iterator::value_type should not provide default constructor
>   4035. single_view should provide empty
>   4053. Unary call to std::views::repeat does not decay the argument
>   4054. Repeating a repeat_view should repeat the view
>
> libstdc++-v3/ChangeLog:
>
>         * include/std/ranges (single_view::empty): Define as per LWG 4035.
>         (iota_view::empty): Define as per LWG 4001.
>         (lazy_split_view::_OuterIter::value_type): Remove default
>         constructor and make other constructor private as per LWG 4013.
>         (common_view::begin): Disable non-const overload for simple
>         views as per LWG 4012.
>         (common_view::end): Likewise.
>         (adjacent_view::base): Define as per LWG 3848.
>         (adjacent_transform_view::base): Likewise.
>         (chunk_view::_InnerIter::iter_move): Define as per LWG 3851.
>         (chunk_view::_InnerIter::itep_swap): Likewise.
>         (slide_view::base): Define as per LWG 3848.
>         (repeat_view): Adjust deduction guide as per LWG 4053.
>         (_Repeat::operator()): Adjust single-parameter overload
>         as per LWG 4054.
>         * testsuite/std/ranges/adaptors/adjacent/1.cc: Verify existence
>         of base member function.
>         * testsuite/std/ranges/adaptors/adjacent_transform/1.cc: Likewise.
>         * testsuite/std/ranges/adaptors/chunk/1.cc: Test LWG 3851 example.
>         * testsuite/std/ranges/adaptors/slide/1.cc: Verify existence of
>         base member function.
>         * testsuite/std/ranges/iota/iota_view.cc: Test LWG 4001 example.
>         * testsuite/std/ranges/repeat/1.cc: Test LWG 4053/4054 examples.
> ---
>  libstdc++-v3/include/std/ranges               | 84 +++++++++++++++++--
>  .../std/ranges/adaptors/adjacent/1.cc         |  3 +
>  .../ranges/adaptors/adjacent_transform/1.cc   |  3 +
>  .../testsuite/std/ranges/adaptors/chunk/1.cc  | 15 ++++
>  .../testsuite/std/ranges/adaptors/slide/1.cc  |  3 +
>  .../testsuite/std/ranges/iota/iota_view.cc    | 12 +++
>  libstdc++-v3/testsuite/std/ranges/repeat/1.cc | 23 +++++
>  7 files changed, 135 insertions(+), 8 deletions(-)
>
> diff --git a/libstdc++-v3/include/std/ranges b/libstdc++-v3/include/std/ranges
> index 30f45e0a750..6e6e3b97d82 100644
> --- a/libstdc++-v3/include/std/ranges
> +++ b/libstdc++-v3/include/std/ranges
> @@ -335,6 +335,12 @@ namespace ranges
>        end() const noexcept
>        { return data() + 1; }
>
> +      // _GLIBCXX_RESOLVE_LIB_DEFECTS
> +      // 4035. single_view should provide empty
> +      static constexpr bool
> +      empty() noexcept
> +      { return false; }
> +
>        static constexpr size_t
>        size() noexcept
>        { return 1; }
> @@ -695,6 +701,12 @@ namespace ranges
>        end() const requires same_as<_Winc, _Bound>
>        { return _Iterator{_M_bound}; }
>
> +      // _GLIBCXX_RESOLVE_LIB_DEFECTS
> +      // 4001. iota_view should provide empty
> +      constexpr bool
> +      empty() const
> +      { return _M_value == _M_bound; }
> +
>        constexpr auto
>        size() const
>        requires (same_as<_Winc, _Bound> && __detail::__advanceable<_Winc>)
> @@ -3349,14 +3361,17 @@ namespace views::__adaptor
>           private:
>             _OuterIter _M_i = _OuterIter();
>
> -         public:
> -           value_type() = default;
> -
> +           // _GLIBCXX_RESOLVE_LIB_DEFECTS
> +           // 4013. lazy_split_view::outer-iterator::value_type should not
> +           // provide default constructor
>             constexpr explicit
>             value_type(_OuterIter __i)
>               : _M_i(std::move(__i))
>             { }
>
> +           friend _OuterIter;
> +
> +         public:
>             constexpr _InnerIter<_Const>
>             begin() const
>             { return _InnerIter<_Const>{_M_i}; }
> @@ -3948,8 +3963,10 @@ namespace views::__adaptor
>        base() &&
>        { return std::move(_M_base); }
>
> +      // _GLIBCXX_RESOLVE_LIB_DEFECTS
> +      // 4012. common_view::begin/end are missing the simple-view check
>        constexpr auto
> -      begin()
> +      begin() requires (!__detail::__simple_view<_Vp>)
>        {
>         if constexpr (random_access_range<_Vp> && sized_range<_Vp>)
>           return ranges::begin(_M_base);
> @@ -3969,7 +3986,7 @@ namespace views::__adaptor
>        }
>
>        constexpr auto
> -      end()
> +      end() requires (!__detail::__simple_view<_Vp>)
>        {
>         if constexpr (random_access_range<_Vp> && sized_range<_Vp>)
>           return ranges::begin(_M_base) + ranges::size(_M_base);
> @@ -5316,6 +5333,16 @@ namespace views::__adaptor
>        : _M_base(std::move(__base))
>      { }
>
> +    // _GLIBCXX_RESOLVE_LIB_DEFECTS
> +    // 3848. adjacent_view, adjacent_transform_view and slide_view missing base accessor
> +    constexpr _Vp
> +    base() const & requires copy_constructible<_Vp>
> +    { return _M_base; }
> +
> +    constexpr _Vp
> +    base() &&
> +    { return std::move(_M_base); }
> +
>      constexpr auto
>      begin() requires (!__detail::__simple_view<_Vp>)
>      { return _Iterator<false>(ranges::begin(_M_base), ranges::end(_M_base)); }
> @@ -5709,6 +5736,17 @@ namespace views::__adaptor
>        : _M_fun(std::move(__fun)), _M_inner(std::move(__base))
>      { }
>
> +    // _GLIBCXX_RESOLVE_LIB_DEFECTS
> +    // 3848. adjacent_view, adjacent_transform_view and slide_view missing base accessor
> +    // 3947. Unexpected constraints on adjacent_transform_view::base()
> +    constexpr _Vp
> +    base() const & requires copy_constructible<_Vp>
> +    { return _M_inner.base(); }
> +
> +    constexpr _Vp
> +    base() &&
> +    { return std::move(_M_inner.base()); }
> +
>      constexpr auto
>      begin()
>      { return _Iterator<false>(*this, _M_inner.begin()); }
> @@ -6236,6 +6274,20 @@ namespace views::__adaptor
>      operator-(const _InnerIter& __x, default_sentinel_t __y)
>        requires sized_sentinel_for<sentinel_t<_Vp>, iterator_t<_Vp>>
>      { return -(__y - __x); }
> +
> +    // _GLIBCXX_RESOLVE_LIB_DEFECTS
> +    // 3851. chunk_view::inner-iterator missing custom iter_move and iter_swap
> +    friend constexpr range_rvalue_reference_t<_Vp>
> +    iter_move(const _InnerIter& __i)
> +    noexcept(noexcept(ranges::iter_move(*__i._M_parent->_M_current)))
> +    { return ranges::iter_move(*__i._M_parent->_M_current); }
> +
> +    friend constexpr void
> +    iter_swap(const _InnerIter& __x, const _InnerIter& __y)
> +    noexcept(noexcept(ranges::iter_swap(*__x._M_parent->_M_current,
> +                                       *__x._M_parent->_M_current)))
> +    requires indirectly_swappable<iterator_t<_Vp>>
> +    { return ranges::iter_swap(*__x._M_parent->_M_current, *__y._M_parent->_M_current); }
>    };
>
>    template<view _Vp>
> @@ -6577,6 +6629,16 @@ namespace views::__adaptor
>      : _M_base(std::move(__base)), _M_n(__n)
>      { __glibcxx_assert(__n > 0); }
>
> +    // _GLIBCXX_RESOLVE_LIB_DEFECTS
> +    // 3848. adjacent_view, adjacent_transform_view and slide_view missing base accessor
> +    constexpr _Vp
> +    base() const & requires copy_constructible<_Vp>
> +    { return _M_base; }
> +
> +    constexpr _Vp
> +    base() &&
> +    { return std::move(_M_base); }
> +
>      constexpr auto
>      begin() requires (!(__detail::__simple_view<_Vp>
>                         && __detail::__slide_caches_nothing<const _Vp>))
> @@ -7692,8 +7754,10 @@ namespace views::__adaptor
>      { return __detail::__to_unsigned_like(_M_bound); }
>    };
>
> -  template<typename _Tp, typename _Bound>
> -    repeat_view(_Tp, _Bound) -> repeat_view<_Tp, _Bound>;
> +  // _GLIBCXX_RESOLVE_LIB_DEFECTS
> +  // 4053. Unary call to std::views::repeat does not decay the argument
> +  template<typename _Tp, typename _Bound = unreachable_sentinel_t>
> +    repeat_view(_Tp, _Bound = _Bound()) -> repeat_view<_Tp, _Bound>;
>
>    template<move_constructible _Tp, semiregular _Bound>
>      requires is_object_v<_Tp> && same_as<_Tp, remove_cv_t<_Tp>>
> @@ -7840,7 +7904,11 @@ namespace views::__adaptor
>         requires __detail::__can_repeat_view<_Tp>
>        constexpr auto
>        operator() [[nodiscard]] (_Tp&& __value) const
> -      { return repeat_view(std::forward<_Tp>(__value)); }
> +      {
> +       // _GLIBCXX_RESOLVE_LIB_DEFECTS
> +       // 4054. Repeating a repeat_view should repeat the view
> +       return repeat_view<decay_t<_Tp>>(std::forward<_Tp>(__value));
> +      }
>
>        template<typename _Tp, typename _Bound>
>         requires __detail::__can_bounded_repeat_view<_Tp, _Bound>
> diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/adjacent/1.cc b/libstdc++-v3/testsuite/std/ranges/adaptors/adjacent/1.cc
> index b83743a745c..085cd4a8c54 100644
> --- a/libstdc++-v3/testsuite/std/ranges/adaptors/adjacent/1.cc
> +++ b/libstdc++-v3/testsuite/std/ranges/adaptors/adjacent/1.cc
> @@ -47,6 +47,9 @@ test01()
>        VERIFY( &std::get<2>(v3[i]) == &y[i] + 2 );
>      }
>
> +  // LWG 3848 - adjacent_view etc missing base accessor
> +  v3.base();
> +
>    const auto v5 = y | views::adjacent<5>;
>    VERIFY( ranges::equal(v5, views::single(std::make_tuple(1, 2, 3, 4, 5))) );
>
> diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/adjacent_transform/1.cc b/libstdc++-v3/testsuite/std/ranges/adaptors/adjacent_transform/1.cc
> index 6aeedbaa648..a5791b3da70 100644
> --- a/libstdc++-v3/testsuite/std/ranges/adaptors/adjacent_transform/1.cc
> +++ b/libstdc++-v3/testsuite/std/ranges/adaptors/adjacent_transform/1.cc
> @@ -39,6 +39,9 @@ test01()
>    VERIFY( ranges::size(v3) == 4 );
>    VERIFY( ranges::equal(v3, (int[]){3, 4, 5, 6}) );
>
> +  // LWG 3848 - adjacent_transform_view etc missing base accessor
> +  v3.base();
> +
>    const auto v6 = y | views::adjacent_transform<6>([](auto...) { return 0; });
>    VERIFY( ranges::equal(v6, (int[]){0}) );
>
> diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/chunk/1.cc b/libstdc++-v3/testsuite/std/ranges/adaptors/chunk/1.cc
> index 90eb608ca5e..82f9f1b674c 100644
> --- a/libstdc++-v3/testsuite/std/ranges/adaptors/chunk/1.cc
> +++ b/libstdc++-v3/testsuite/std/ranges/adaptors/chunk/1.cc
> @@ -8,6 +8,7 @@
>  #endif
>
>  #include <algorithm>
> +#include <sstream>
>  #include <vector>
>  #include <testsuite_hooks.h>
>  #include <testsuite_iterators.h>
> @@ -76,10 +77,24 @@ test02()
>      VERIFY( ranges::equal(wrapper(x) | views::chunk(i) | views::join, x) );
>  }
>
> +void
> +test03()
> +{
> +  // LWG 3851 - chunk_view::inner-iterator missing custom iter_move and iter_swap
> +  auto ints = std::istringstream{"0 1 2 3 4"};
> +  std::vector<std::string> vs{"the", "quick", "brown", "fox"};
> +  auto r = views::zip(vs, views::istream<int>(ints)) | views::chunk(2) | views::join;
> +  std::vector<std::tuple<std::string, int>> res;
> +  ranges::copy(std::move_iterator(r.begin()), std::move_sentinel(r.end()),
> +              std::back_inserter(res));
> +  VERIFY( vs.front().empty() );
> +}
> +
>  int
>  main()
>  {
>    static_assert(test01());
>    test02<__gnu_test::test_input_range<int>>();
>    test02<__gnu_test::test_forward_range<int>>();
> +  test03();
>  }
> diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/slide/1.cc b/libstdc++-v3/testsuite/std/ranges/adaptors/slide/1.cc
> index bafe9fbc4bf..a5d94ea6406 100644
> --- a/libstdc++-v3/testsuite/std/ranges/adaptors/slide/1.cc
> +++ b/libstdc++-v3/testsuite/std/ranges/adaptors/slide/1.cc
> @@ -50,6 +50,9 @@ test01()
>        VERIFY( &v3[i][2] == &y[i] + 2 );
>      }
>
> +  // LWG 3848 - slide_view etc missing base accessor
> +  v3.base();
> +
>    const auto v5 = y | views::slide(5);
>    VERIFY( ranges::size(v5) == 1 );
>    VERIFY( ranges::equal(v5 | views::join, y) );
> diff --git a/libstdc++-v3/testsuite/std/ranges/iota/iota_view.cc b/libstdc++-v3/testsuite/std/ranges/iota/iota_view.cc
> index bec4174a3da..9db61a76596 100644
> --- a/libstdc++-v3/testsuite/std/ranges/iota/iota_view.cc
> +++ b/libstdc++-v3/testsuite/std/ranges/iota/iota_view.cc
> @@ -19,6 +19,7 @@
>
>  #include <algorithm>
>  #include <ranges>
> +#include <vector>
>  #include <testsuite_hooks.h>
>
>  void
> @@ -118,6 +119,16 @@ test07()
>    static_assert(!requires { iota(nullptr, nullptr); });
>  }
>
> +void
> +test08()
> +{
> +  // LWC 4001 - iota_view should provide empty
> +  std::vector<int> v;
> +  auto it = std::back_inserter(v);
> +  auto r = std::views::iota(it);
> +  VERIFY( !r.empty() );
> +}
> +
>  int
>  main()
>  {
> @@ -128,4 +139,5 @@ main()
>    test05();
>    test06();
>    test07();
> +  test08();
>  }
> diff --git a/libstdc++-v3/testsuite/std/ranges/repeat/1.cc b/libstdc++-v3/testsuite/std/ranges/repeat/1.cc
> index cad8c8dcbe7..eb0c848e9ce 100644
> --- a/libstdc++-v3/testsuite/std/ranges/repeat/1.cc
> +++ b/libstdc++-v3/testsuite/std/ranges/repeat/1.cc
> @@ -151,6 +151,27 @@ test07()
>    auto d2 = std::views::repeat(std::make_unique<int>(5), 4) | std::views::drop(2);
>  }
>
> +void
> +test08()
> +{
> +  // LWG 4053 - Unary call to std::views::repeat does not decay the argument
> +  using type = ranges::repeat_view<const char*>;
> +  using type = decltype(views::repeat("foo", std::unreachable_sentinel));
> +  using type = decltype(views::repeat(+"foo", std::unreachable_sentinel));
> +  using type = decltype(views::repeat("foo"));
> +  using type = decltype(views::repeat(+"foo"));
> +}
> +
> +void
> +test09()
> +{
> +  // LWG 4054 - Repeating a repeat_view should repeat the view
> +  auto v = views::repeat(views::repeat(5));
> +  using type = decltype(v);
> +  using type = ranges::repeat_view<ranges::repeat_view<int>>;
> +  VERIFY( v[0][0] == 5 );
> +}
> +
>  int
>  main()
>  {
> @@ -161,4 +182,6 @@ main()
>    test05();
>    test06();
>    test07();
> +  test08();
> +  test09();
>  }
> --
> 2.47.0.rc1
>
diff mbox series

Patch

diff --git a/libstdc++-v3/include/std/ranges b/libstdc++-v3/include/std/ranges
index 30f45e0a750..6e6e3b97d82 100644
--- a/libstdc++-v3/include/std/ranges
+++ b/libstdc++-v3/include/std/ranges
@@ -335,6 +335,12 @@  namespace ranges
       end() const noexcept
       { return data() + 1; }
 
+      // _GLIBCXX_RESOLVE_LIB_DEFECTS
+      // 4035. single_view should provide empty
+      static constexpr bool
+      empty() noexcept
+      { return false; }
+
       static constexpr size_t
       size() noexcept
       { return 1; }
@@ -695,6 +701,12 @@  namespace ranges
       end() const requires same_as<_Winc, _Bound>
       { return _Iterator{_M_bound}; }
 
+      // _GLIBCXX_RESOLVE_LIB_DEFECTS
+      // 4001. iota_view should provide empty
+      constexpr bool
+      empty() const
+      { return _M_value == _M_bound; }
+
       constexpr auto
       size() const
       requires (same_as<_Winc, _Bound> && __detail::__advanceable<_Winc>)
@@ -3349,14 +3361,17 @@  namespace views::__adaptor
 	  private:
 	    _OuterIter _M_i = _OuterIter();
 
-	  public:
-	    value_type() = default;
-
+	    // _GLIBCXX_RESOLVE_LIB_DEFECTS
+	    // 4013. lazy_split_view::outer-iterator::value_type should not
+	    // provide default constructor
 	    constexpr explicit
 	    value_type(_OuterIter __i)
 	      : _M_i(std::move(__i))
 	    { }
 
+	    friend _OuterIter;
+
+	  public:
 	    constexpr _InnerIter<_Const>
 	    begin() const
 	    { return _InnerIter<_Const>{_M_i}; }
@@ -3948,8 +3963,10 @@  namespace views::__adaptor
       base() &&
       { return std::move(_M_base); }
 
+      // _GLIBCXX_RESOLVE_LIB_DEFECTS
+      // 4012. common_view::begin/end are missing the simple-view check
       constexpr auto
-      begin()
+      begin() requires (!__detail::__simple_view<_Vp>)
       {
 	if constexpr (random_access_range<_Vp> && sized_range<_Vp>)
 	  return ranges::begin(_M_base);
@@ -3969,7 +3986,7 @@  namespace views::__adaptor
       }
 
       constexpr auto
-      end()
+      end() requires (!__detail::__simple_view<_Vp>)
       {
 	if constexpr (random_access_range<_Vp> && sized_range<_Vp>)
 	  return ranges::begin(_M_base) + ranges::size(_M_base);
@@ -5316,6 +5333,16 @@  namespace views::__adaptor
       : _M_base(std::move(__base))
     { }
 
+    // _GLIBCXX_RESOLVE_LIB_DEFECTS
+    // 3848. adjacent_view, adjacent_transform_view and slide_view missing base accessor
+    constexpr _Vp
+    base() const & requires copy_constructible<_Vp>
+    { return _M_base; }
+
+    constexpr _Vp
+    base() &&
+    { return std::move(_M_base); }
+
     constexpr auto
     begin() requires (!__detail::__simple_view<_Vp>)
     { return _Iterator<false>(ranges::begin(_M_base), ranges::end(_M_base)); }
@@ -5709,6 +5736,17 @@  namespace views::__adaptor
       : _M_fun(std::move(__fun)), _M_inner(std::move(__base))
     { }
 
+    // _GLIBCXX_RESOLVE_LIB_DEFECTS
+    // 3848. adjacent_view, adjacent_transform_view and slide_view missing base accessor
+    // 3947. Unexpected constraints on adjacent_transform_view::base()
+    constexpr _Vp
+    base() const & requires copy_constructible<_Vp>
+    { return _M_inner.base(); }
+
+    constexpr _Vp
+    base() &&
+    { return std::move(_M_inner.base()); }
+
     constexpr auto
     begin()
     { return _Iterator<false>(*this, _M_inner.begin()); }
@@ -6236,6 +6274,20 @@  namespace views::__adaptor
     operator-(const _InnerIter& __x, default_sentinel_t __y)
       requires sized_sentinel_for<sentinel_t<_Vp>, iterator_t<_Vp>>
     { return -(__y - __x); }
+
+    // _GLIBCXX_RESOLVE_LIB_DEFECTS
+    // 3851. chunk_view::inner-iterator missing custom iter_move and iter_swap
+    friend constexpr range_rvalue_reference_t<_Vp>
+    iter_move(const _InnerIter& __i)
+    noexcept(noexcept(ranges::iter_move(*__i._M_parent->_M_current)))
+    { return ranges::iter_move(*__i._M_parent->_M_current); }
+
+    friend constexpr void
+    iter_swap(const _InnerIter& __x, const _InnerIter& __y)
+    noexcept(noexcept(ranges::iter_swap(*__x._M_parent->_M_current,
+					*__x._M_parent->_M_current)))
+    requires indirectly_swappable<iterator_t<_Vp>>
+    { return ranges::iter_swap(*__x._M_parent->_M_current, *__y._M_parent->_M_current); }
   };
 
   template<view _Vp>
@@ -6577,6 +6629,16 @@  namespace views::__adaptor
     : _M_base(std::move(__base)), _M_n(__n)
     { __glibcxx_assert(__n > 0); }
 
+    // _GLIBCXX_RESOLVE_LIB_DEFECTS
+    // 3848. adjacent_view, adjacent_transform_view and slide_view missing base accessor
+    constexpr _Vp
+    base() const & requires copy_constructible<_Vp>
+    { return _M_base; }
+
+    constexpr _Vp
+    base() &&
+    { return std::move(_M_base); }
+
     constexpr auto
     begin() requires (!(__detail::__simple_view<_Vp>
 			&& __detail::__slide_caches_nothing<const _Vp>))
@@ -7692,8 +7754,10 @@  namespace views::__adaptor
     { return __detail::__to_unsigned_like(_M_bound); }
   };
 
-  template<typename _Tp, typename _Bound>
-    repeat_view(_Tp, _Bound) -> repeat_view<_Tp, _Bound>;
+  // _GLIBCXX_RESOLVE_LIB_DEFECTS
+  // 4053. Unary call to std::views::repeat does not decay the argument
+  template<typename _Tp, typename _Bound = unreachable_sentinel_t>
+    repeat_view(_Tp, _Bound = _Bound()) -> repeat_view<_Tp, _Bound>;
 
   template<move_constructible _Tp, semiregular _Bound>
     requires is_object_v<_Tp> && same_as<_Tp, remove_cv_t<_Tp>>
@@ -7840,7 +7904,11 @@  namespace views::__adaptor
 	requires __detail::__can_repeat_view<_Tp>
       constexpr auto
       operator() [[nodiscard]] (_Tp&& __value) const
-      { return repeat_view(std::forward<_Tp>(__value)); }
+      {
+	// _GLIBCXX_RESOLVE_LIB_DEFECTS
+	// 4054. Repeating a repeat_view should repeat the view
+	return repeat_view<decay_t<_Tp>>(std::forward<_Tp>(__value));
+      }
 
       template<typename _Tp, typename _Bound>
 	requires __detail::__can_bounded_repeat_view<_Tp, _Bound>
diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/adjacent/1.cc b/libstdc++-v3/testsuite/std/ranges/adaptors/adjacent/1.cc
index b83743a745c..085cd4a8c54 100644
--- a/libstdc++-v3/testsuite/std/ranges/adaptors/adjacent/1.cc
+++ b/libstdc++-v3/testsuite/std/ranges/adaptors/adjacent/1.cc
@@ -47,6 +47,9 @@  test01()
       VERIFY( &std::get<2>(v3[i]) == &y[i] + 2 );
     }
 
+  // LWG 3848 - adjacent_view etc missing base accessor
+  v3.base();
+
   const auto v5 = y | views::adjacent<5>;
   VERIFY( ranges::equal(v5, views::single(std::make_tuple(1, 2, 3, 4, 5))) );
 
diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/adjacent_transform/1.cc b/libstdc++-v3/testsuite/std/ranges/adaptors/adjacent_transform/1.cc
index 6aeedbaa648..a5791b3da70 100644
--- a/libstdc++-v3/testsuite/std/ranges/adaptors/adjacent_transform/1.cc
+++ b/libstdc++-v3/testsuite/std/ranges/adaptors/adjacent_transform/1.cc
@@ -39,6 +39,9 @@  test01()
   VERIFY( ranges::size(v3) == 4 );
   VERIFY( ranges::equal(v3, (int[]){3, 4, 5, 6}) );
 
+  // LWG 3848 - adjacent_transform_view etc missing base accessor
+  v3.base();
+
   const auto v6 = y | views::adjacent_transform<6>([](auto...) { return 0; });
   VERIFY( ranges::equal(v6, (int[]){0}) );
 
diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/chunk/1.cc b/libstdc++-v3/testsuite/std/ranges/adaptors/chunk/1.cc
index 90eb608ca5e..82f9f1b674c 100644
--- a/libstdc++-v3/testsuite/std/ranges/adaptors/chunk/1.cc
+++ b/libstdc++-v3/testsuite/std/ranges/adaptors/chunk/1.cc
@@ -8,6 +8,7 @@ 
 #endif
 
 #include <algorithm>
+#include <sstream>
 #include <vector>
 #include <testsuite_hooks.h>
 #include <testsuite_iterators.h>
@@ -76,10 +77,24 @@  test02()
     VERIFY( ranges::equal(wrapper(x) | views::chunk(i) | views::join, x) );
 }
 
+void
+test03()
+{
+  // LWG 3851 - chunk_view::inner-iterator missing custom iter_move and iter_swap
+  auto ints = std::istringstream{"0 1 2 3 4"};
+  std::vector<std::string> vs{"the", "quick", "brown", "fox"};
+  auto r = views::zip(vs, views::istream<int>(ints)) | views::chunk(2) | views::join;
+  std::vector<std::tuple<std::string, int>> res;
+  ranges::copy(std::move_iterator(r.begin()), std::move_sentinel(r.end()),
+	       std::back_inserter(res));
+  VERIFY( vs.front().empty() );
+}
+
 int
 main()
 {
   static_assert(test01());
   test02<__gnu_test::test_input_range<int>>();
   test02<__gnu_test::test_forward_range<int>>();
+  test03();
 }
diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/slide/1.cc b/libstdc++-v3/testsuite/std/ranges/adaptors/slide/1.cc
index bafe9fbc4bf..a5d94ea6406 100644
--- a/libstdc++-v3/testsuite/std/ranges/adaptors/slide/1.cc
+++ b/libstdc++-v3/testsuite/std/ranges/adaptors/slide/1.cc
@@ -50,6 +50,9 @@  test01()
       VERIFY( &v3[i][2] == &y[i] + 2 );
     }
 
+  // LWG 3848 - slide_view etc missing base accessor
+  v3.base();
+
   const auto v5 = y | views::slide(5);
   VERIFY( ranges::size(v5) == 1 );
   VERIFY( ranges::equal(v5 | views::join, y) );
diff --git a/libstdc++-v3/testsuite/std/ranges/iota/iota_view.cc b/libstdc++-v3/testsuite/std/ranges/iota/iota_view.cc
index bec4174a3da..9db61a76596 100644
--- a/libstdc++-v3/testsuite/std/ranges/iota/iota_view.cc
+++ b/libstdc++-v3/testsuite/std/ranges/iota/iota_view.cc
@@ -19,6 +19,7 @@ 
 
 #include <algorithm>
 #include <ranges>
+#include <vector>
 #include <testsuite_hooks.h>
 
 void
@@ -118,6 +119,16 @@  test07()
   static_assert(!requires { iota(nullptr, nullptr); });
 }
 
+void
+test08()
+{
+  // LWC 4001 - iota_view should provide empty
+  std::vector<int> v;
+  auto it = std::back_inserter(v);
+  auto r = std::views::iota(it);
+  VERIFY( !r.empty() );
+}
+
 int
 main()
 {
@@ -128,4 +139,5 @@  main()
   test05();
   test06();
   test07();
+  test08();
 }
diff --git a/libstdc++-v3/testsuite/std/ranges/repeat/1.cc b/libstdc++-v3/testsuite/std/ranges/repeat/1.cc
index cad8c8dcbe7..eb0c848e9ce 100644
--- a/libstdc++-v3/testsuite/std/ranges/repeat/1.cc
+++ b/libstdc++-v3/testsuite/std/ranges/repeat/1.cc
@@ -151,6 +151,27 @@  test07()
   auto d2 = std::views::repeat(std::make_unique<int>(5), 4) | std::views::drop(2);
 }
 
+void
+test08()
+{
+  // LWG 4053 - Unary call to std::views::repeat does not decay the argument
+  using type = ranges::repeat_view<const char*>;
+  using type = decltype(views::repeat("foo", std::unreachable_sentinel));
+  using type = decltype(views::repeat(+"foo", std::unreachable_sentinel));
+  using type = decltype(views::repeat("foo"));
+  using type = decltype(views::repeat(+"foo"));
+}
+
+void
+test09()
+{
+  // LWG 4054 - Repeating a repeat_view should repeat the view
+  auto v = views::repeat(views::repeat(5));
+  using type = decltype(v);
+  using type = ranges::repeat_view<ranges::repeat_view<int>>;
+  VERIFY( v[0][0] == 5 );
+}
+
 int
 main()
 {
@@ -161,4 +182,6 @@  main()
   test05();
   test06();
   test07();
+  test08();
+  test09();
 }