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> 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.48.1.356.g0394451348.dirty