On Wed, 5 Mar 2025 at 15:37, Patrick Palkawrote:
>
> On Mon, 17 Feb 2025, Patrick Palka wrote:
>
> > Tested on x86_64-pc-linux-gnu, does this look OK for trunk?
> >
> > -- >8 --
> >
> > - Use __builtin_unreachable to suppress a false-positive "control
> >   reaches end of non-void function" warning in the recursive lambda
> >   (which the existing tests failed to notice since test01 wasn't
> >   being called at runtime)
> > - Relax the constraints on views::concat in the single-argument case
> >   as per PR115215
> > - Add an input_range requirement to that same case as per LWG 4082
> > - In the const-converting constructor of concat_view's iterator,
> >   don't require the first iterator to be default constructible
> >
> >       PR libstdc++/115215
> >       PR libstdc++/115218
> >
> > libstdc++-v3/ChangeLog:
> >
> >       * include/std/ranges
> >       (concat_view::iterator::_S_invoke_with_runtime_index): Use
> >       __builtin_unreachable in recursive lambda to certify it always
> >       exits via 'return'.
> >       (concat_view::iterator::iterator): In the const-converting
> >       constructor, direct initialize _M_it.
> >       (views::_Concat::operator()): Adjust constraints in the
> >       single-argument case as per LWG 4082.
> >       * testsuite/std/ranges/concat/1.cc (test01): Call it at runtime
> >       too.
> >       (test04): New test.
> > ---
> >  libstdc++-v3/include/std/ranges               | 28 +++++++++----------
> >  libstdc++-v3/testsuite/std/ranges/concat/1.cc | 16 +++++++++++
> >  2 files changed, 30 insertions(+), 14 deletions(-)
> >
> > diff --git a/libstdc++-v3/include/std/ranges 
> > b/libstdc++-v3/include/std/ranges
> > index 22e0c9cae44..a56dae43625 100644
> > --- a/libstdc++-v3/include/std/ranges
> > +++ b/libstdc++-v3/include/std/ranges
> > @@ -9919,6 +9919,7 @@ namespace ranges
> >           return __f.template operator()<_Idx>();
> >         if constexpr (_Idx + 1 < sizeof...(_Vs))
> >           return __self.template operator()<_Idx + 1>();
> > +       __builtin_unreachable();
> >       }.template operator()<0>();
> >        }
> >
> > @@ -9940,12 +9941,12 @@ namespace ranges
> >      constexpr
> >      iterator(iterator<!_Const> __it)
> >        requires _Const && (convertible_to<iterator_t<_Vs>, iterator_t<const 
> > _Vs>> && ...)
> > -    : _M_parent(__it._M_parent)
> > -    {
> > -      _M_invoke_with_runtime_index([this, &__it]<size_t _Idx>() {
> > -     _M_it.template emplace<_Idx>(std::get<_Idx>(std::move(__it._M_it)));
> > -      });
> > -    }
> > +    : _M_parent(__it._M_parent),
> > +      _M_it(_S_invoke_with_runtime_index([this, &__it]<size_t _Idx>() {
> > +           return __base_iter(in_place_index<_Idx>,
> > +                              std::get<_Idx>(std::move(__it._M_it)));
> > +         }, __it._M_it.index()))
> > +    { }
> >
> >      constexpr decltype(auto)
> >      operator*() const
> > @@ -10179,16 +10180,15 @@ namespace ranges
> >
> >      struct _Concat
> >      {
> > -      template<typename... _Ts>
> > -     requires __detail::__can_concat_view<_Ts...>
> > +      template<__detail::__can_concat_view... _Ts>
>
> As pointed out by Tomasz, this change is incorrect and unnecessary.
> The former checks __can_concat_view<_Ts...> whereas the latter checks
> (__can_concat_view<Ts> && ...).  Here's v2 with this change reverted:

I was just looking at that exact line and scratching my head.

Patch v2 is OK for trunk, thanks.

>
> -- >8 --
>
> Subject: [PATCH v2] libstdc++: Some concat_view bugfixes [PR115215, PR115218, 
> LWG
>  4082]
>
> - Use __builtin_unreachable to suppress a false-positive "control
>   reaches end of non-void function" warning in the recursive lambda
>   (which the existing tests failed to notice since test01 wasn't
>   being called at runtime)
> - Relax the constraints on views::concat in the single-argument case
>   as per PR115215
> - Add an input_range requirement to that same case as per LWG 4082
> - In the const-converting constructor of concat_view's iterator,
>   don't require the first iterator to be default constructible
>
>         PR libstdc++/115215
>         PR libstdc++/115218
>
> libstdc++-v3/ChangeLog:
>
>         * include/std/ranges
>         (concat_view::iterator::_S_invoke_with_runtime_index): Use
>         __builtin_unreachable in recursive lambda to certify it always
>         exits via 'return'.
>         (concat_view::iterator::iterator): In the const-converting
>         constructor, direct initialize _M_it.
>         (views::_Concat::operator()): Adjust constraints in the
>         single-argument case as per LWG 4082.
>         * testsuite/std/ranges/concat/1.cc (test01): Call it at runtime
>         too.
>         (test04): New test.
> ---
>  libstdc++-v3/include/std/ranges               | 25 ++++++++++---------
>  libstdc++-v3/testsuite/std/ranges/concat/1.cc | 16 ++++++++++++
>  2 files changed, 29 insertions(+), 12 deletions(-)
>
> diff --git a/libstdc++-v3/include/std/ranges b/libstdc++-v3/include/std/ranges
> index 6c65722b687..2228ab8c5ee 100644
> --- a/libstdc++-v3/include/std/ranges
> +++ b/libstdc++-v3/include/std/ranges
> @@ -9919,6 +9919,7 @@ namespace ranges
>             return __f.template operator()<_Idx>();
>           if constexpr (_Idx + 1 < sizeof...(_Vs))
>             return __self.template operator()<_Idx + 1>();
> +         __builtin_unreachable();
>         }.template operator()<0>();
>        }
>
> @@ -9940,12 +9941,12 @@ namespace ranges
>      constexpr
>      _Iterator(_Iterator<!_Const> __it)
>        requires _Const && (convertible_to<iterator_t<_Vs>, iterator_t<const 
> _Vs>> && ...)
> -    : _M_parent(__it._M_parent)
> -    {
> -      _M_invoke_with_runtime_index([this, &__it]<size_t _Idx>() {
> -       _M_it.template emplace<_Idx>(std::get<_Idx>(std::move(__it._M_it)));
> -      });
> -    }
> +    : _M_parent(__it._M_parent),
> +      _M_it(_S_invoke_with_runtime_index([this, &__it]<size_t _Idx>() {
> +             return __base_iter(in_place_index<_Idx>,
> +                                std::get<_Idx>(std::move(__it._M_it)));
> +           }, __it._M_it.index()))
> +    { }
>
>      constexpr decltype(auto)
>      operator*() const
> @@ -10183,12 +10184,12 @@ namespace ranges
>         requires __detail::__can_concat_view<_Ts...>
>        constexpr auto
>        operator() [[nodiscard]] (_Ts&&... __ts) const
> -      {
> -       if constexpr (sizeof...(_Ts) == 1)
> -         return views::all(std::forward<_Ts>(__ts)...);
> -       else
> -         return concat_view(std::forward<_Ts>(__ts)...);
> -      }
> +      { return concat_view(std::forward<_Ts>(__ts)...); }
> +
> +      template<input_range _Range>
> +      constexpr auto
> +      operator() [[nodiscard]] (_Range&& __t) const
> +      { return views::all(std::forward<_Range>(__t)); }
>      };
>
>      inline constexpr _Concat concat;
> diff --git a/libstdc++-v3/testsuite/std/ranges/concat/1.cc 
> b/libstdc++-v3/testsuite/std/ranges/concat/1.cc
> index e5d10f476e9..16721912a37 100644
> --- a/libstdc++-v3/testsuite/std/ranges/concat/1.cc
> +++ b/libstdc++-v3/testsuite/std/ranges/concat/1.cc
> @@ -85,10 +85,26 @@ test03()
>    VERIFY( ranges::equal(view2, std::vector{4, 5, 6, 1, 2, 3}) );
>  }
>
> +void
> +test04()
> +{
> +  // PR libstdc++/115215 - views::concat rejects non-movable reference
> +  int x[] = {1,2,3};
> +  struct nomove {
> +    nomove() = default;
> +    nomove(const nomove&) = delete;
> +  };
> +  auto v = x | views::transform([](int) { return nomove{}; });
> +  using type = decltype(views::concat(v));
> +  using type = decltype(v);
> +}
> +
>  int
>  main()
>  {
>    static_assert(test01());
> +  test01();
>    test02();
>    test03();
> +  test04();
>  }
> --
> 2.49.0.rc0.57.gdb91954e18
>

Reply via email to