https://gcc.gnu.org/g:f191c8301545658543773ba3d0e6f3f0927529e0
commit r15-4555-gf191c8301545658543773ba3d0e6f3f0927529e0 Author: Patrick Palka <ppa...@redhat.com> Date: Tue Oct 22 17:01:59 2024 -0400 libstdc++: Implement LWG 4166 changes to concat_view::end() This patch proactively implements the proposed resolution for this LWG issue, which seems straightforward and slated to get approved as-is. (No _GLIBCXX_RESOLVE_LIB_DEFECTS code comment is added since concat_view is C++26, so this isn't a defect against a published standard.) libstdc++-v3/ChangeLog: * include/std/ranges (concat_view::begin): Add space after 'requires' starting a requires-clause. (concat_view::end): Likewise. 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. Reviewed-by: Jonathan Wakely <jwak...@redhat.com> Diff: --- libstdc++-v3/include/std/ranges | 10 ++++++---- libstdc++-v3/testsuite/std/ranges/concat/1.cc | 20 ++++++++++++++++++++ 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/libstdc++-v3/include/std/ranges b/libstdc++-v3/include/std/ranges index 9f233729d9c7..cebe10683f91 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 6ffe28ece511..e5d10f476e93 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,28 @@ 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); + ranges::range auto view1 = views::concat(range_copyable_it, range_noncopyable_it); + 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); + ranges::range auto view2 = views::concat(range_noncopyable_it, range_copyable_it); + VERIFY( ranges::equal(view2, std::vector{4, 5, 6, 1, 2, 3}) ); +} + int main() { static_assert(test01()); test02(); + test03(); }