On Tue, 22 Oct 2024 at 19:22, Patrick Palka <ppa...@redhat.com> wrote: > > Tested on x86_64-pc-linux-gnu, does this look OK for trunk?
OK, thanks. > > -- >8 -- > > This patch proactively implements the proposed resolution for this LWG > issue, which seems straightforward and slated to be approved as-is. > > I opted to not add a _GLIBCXX_RESOLVE_LIB_DEFECTS code comment for this > since concat_view is C++26 and hasn't been shipped in a GCC release yet. Yup, that's fine. The LWG issue isn't a DR against a published standard, so once we get a finished C++26 standard, this issue will already be part of that standard. > > libstdc++-v3/ChangeLog: > > * include/std/ranges (concat_view::begin): Add space after > 'requires' starting a requires-clause. > (concat_view::end): Refine condition for returning an iterator > rather than default_sentinel as per LWG 4166. > * testsuite/std/ranges/concat/1.cc (test03): Verify LWG 4166 > example. > --- > libstdc++-v3/include/std/ranges | 10 ++++---- > libstdc++-v3/testsuite/std/ranges/concat/1.cc | 23 +++++++++++++++++++ > 2 files changed, 29 insertions(+), 4 deletions(-) > > diff --git a/libstdc++-v3/include/std/ranges b/libstdc++-v3/include/std/ranges > index 5b455888536..a6c4d66520c 100644 > --- a/libstdc++-v3/include/std/ranges > +++ b/libstdc++-v3/include/std/ranges > @@ -9687,7 +9687,7 @@ namespace ranges > { } > > constexpr iterator<false> > - begin() requires(!(__detail::__simple_view<_Vs> && ...)) > + begin() requires (!(__detail::__simple_view<_Vs> && ...)) > { > iterator<false> __it(this, in_place_index<0>, > ranges::begin(std::get<0>(_M_views))); > __it.template _M_satisfy<0>(); > @@ -9703,9 +9703,10 @@ namespace ranges > } > > constexpr auto > - end() requires(!(__detail::__simple_view<_Vs> && ...)) > + end() requires (!(__detail::__simple_view<_Vs> && ...)) > { > - if constexpr (__detail::__last_is_common<_Vs...>::value) > + if constexpr ((semiregular<iterator_t<_Vs>> && ...) > + && __detail::__last_is_common<_Vs...>::value) > { > constexpr auto __n = sizeof...(_Vs); > return iterator<false>(this, in_place_index<__n - 1>, > @@ -9718,7 +9719,8 @@ namespace ranges > constexpr auto > end() const requires (range<const _Vs> && ...) && > __detail::__concatable<const _Vs...> > { > - if constexpr (__detail::__last_is_common<const _Vs...>::value) > + if constexpr ((semiregular<iterator_t<const _Vs>> && ...) > + && __detail::__last_is_common<const _Vs...>::value) > { > constexpr auto __n = sizeof...(_Vs); > return iterator<true>(this, in_place_index<__n - 1>, > diff --git a/libstdc++-v3/testsuite/std/ranges/concat/1.cc > b/libstdc++-v3/testsuite/std/ranges/concat/1.cc > index 6ffe28ece51..511a7e8a858 100644 > --- a/libstdc++-v3/testsuite/std/ranges/concat/1.cc > +++ b/libstdc++-v3/testsuite/std/ranges/concat/1.cc > @@ -10,6 +10,7 @@ > #include <algorithm> > #include <vector> > #include <array> > +#include <sstream> > #include <utility> > #include <testsuite_hooks.h> > #include <testsuite_iterators.h> > @@ -66,9 +67,31 @@ test02() > VERIFY( ranges::equal(v | views::drop(1), x) ); > } > > +void > +test03() > +{ > + // LWG 4166 - concat_view::end() should be more constrained in order to > + // support noncopyable iterators > + auto range_copyable_it = std::vector<int>{1, 2, 3}; > + > + std::stringstream ss{"4 5 6"}; > + auto range_noncopyable_it = views::istream<int>(ss); > + > + auto view1 = views::concat(range_copyable_it, range_noncopyable_it); > + static_assert( ranges::range<decltype(view1)> ); > + VERIFY( ranges::equal(view1, std::vector{1, 2, 3, 4, 5, 6}) ); > + > + ss = std::stringstream{"4 5 6"}; > + range_noncopyable_it = views::istream<int>(ss); > + auto view2 = views::concat(range_noncopyable_it, range_copyable_it); > + static_assert( ranges::range<decltype(view2)> ); > + VERIFY( ranges::equal(view2, std::vector{4, 5, 6, 1, 2, 3}) ); > +} > + > int > main() > { > static_assert(test01()); > test02(); > + test03(); > } > -- > 2.47.0.107.g34b6ce9b30 >