Message ID | 20241013235316.1722410-1-jwakely@redhat.com |
---|---|
State | New |
Headers | show |
Series | libstdc++: Implement LWG 3798 for range adaptors [PR106676] | expand |
On Mon, 14 Oct 2024, Jonathan Wakely wrote: > Tested x86_64-linux. > > -- >8 -- > > LWG 3798 modified the iterator_category of the iterator types for > transform_view, join_with_view, zip_transform_view and > adjacent_transform_view, to allow the iterator's reference type to be an > rvalue reference. > > libstdc++-v3/ChangeLog: > > PR libstdc++/106676 > * include/bits/iterator_concepts.h (__cpp17_fwd_iterator): Use > is_reference instead of is_value_reference. > rvalue references. > * include/std/ranges (transform_view:__iter_cat::_S_iter_cat): > Likewise. > (zip_transform_view::__iter_cat::_S_iter_cat): Likewise. > (adjacent_transform_view::__iter_cat::_S_iter_cat): Likewise. > (join_with_view::__iter_cat::_S_iter_cat): Likewise. > * testsuite/std/ranges/adaptors/transform.cc: Check > iterator_category when the transformation function returns an > rvalue reference type. > --- > libstdc++-v3/include/bits/iterator_concepts.h | 4 +++- > libstdc++-v3/include/std/ranges | 16 ++++++++++++---- > .../testsuite/std/ranges/adaptors/transform.cc | 16 ++++++++++++++++ > 3 files changed, 31 insertions(+), 5 deletions(-) > > diff --git a/libstdc++-v3/include/bits/iterator_concepts.h b/libstdc++-v3/include/bits/iterator_concepts.h > index 490a362cdf1..669d3ddfd1e 100644 > --- a/libstdc++-v3/include/bits/iterator_concepts.h > +++ b/libstdc++-v3/include/bits/iterator_concepts.h > @@ -333,10 +333,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > typename incrementable_traits<_Iter>::difference_type>; > }; > > + // _GLIBCXX_RESOLVE_LIB_DEFECTS > + // 3798. Rvalue reference and iterator_category > template<typename _Iter> > concept __cpp17_fwd_iterator = __cpp17_input_iterator<_Iter> > && constructible_from<_Iter> > - && is_lvalue_reference_v<iter_reference_t<_Iter>> > + && is_reference_v<iter_reference_t<_Iter>> > && same_as<remove_cvref_t<iter_reference_t<_Iter>>, > typename indirectly_readable_traits<_Iter>::value_type> > && requires(_Iter __it) > diff --git a/libstdc++-v3/include/std/ranges b/libstdc++-v3/include/std/ranges > index f0d81cbea0c..941189d65c3 100644 > --- a/libstdc++-v3/include/std/ranges > +++ b/libstdc++-v3/include/std/ranges > @@ -1892,7 +1892,9 @@ namespace views::__adaptor > using _Fpc = __detail::__maybe_const_t<_Const, _Fp>; > using _Base = transform_view::_Base<_Const>; > using _Res = invoke_result_t<_Fpc&, range_reference_t<_Base>>; > - if constexpr (is_lvalue_reference_v<_Res>) > + // _GLIBCXX_RESOLVE_LIB_DEFECTS > + // 3798. Rvalue reference and iterator_category > + if constexpr (is_reference_v<_Res>) > { > using _Cat > = typename iterator_traits<iterator_t<_Base>>::iterator_category; > @@ -5047,7 +5049,9 @@ namespace views::__adaptor > using __detail::__range_iter_cat; > using _Res = invoke_result_t<__maybe_const_t<_Const, _Fp>&, > range_reference_t<__maybe_const_t<_Const, _Vs>>...>; > - if constexpr (!is_lvalue_reference_v<_Res>) > + // _GLIBCXX_RESOLVE_LIB_DEFECTS > + // 3798. Rvalue reference and iterator_category > + if constexpr (!is_reference_v<_Res>) > return input_iterator_tag{}; > else if constexpr ((derived_from<__range_iter_cat<_Vs, _Const>, > random_access_iterator_tag> && ...)) > @@ -5820,7 +5824,9 @@ namespace views::__adaptor > using _Res = invoke_result_t<__unarize<__maybe_const_t<_Const, _Fp>&, _Nm>, > range_reference_t<_Base>>; > using _Cat = typename iterator_traits<iterator_t<_Base>>::iterator_category; > - if constexpr (!is_lvalue_reference_v<_Res>) > + // _GLIBCXX_RESOLVE_LIB_DEFECTS > + // 3798. Rvalue reference and iterator_category > + if constexpr (!is_reference_v<_Res>) > return input_iterator_tag{}; > else if constexpr (derived_from<_Cat, random_access_iterator_tag>) > return random_access_iterator_tag{}; > @@ -7228,7 +7234,9 @@ namespace views::__adaptor > using _OuterCat = typename iterator_traits<_OuterIter>::iterator_category; > using _InnerCat = typename iterator_traits<_InnerIter>::iterator_category; > using _PatternCat = typename iterator_traits<_PatternIter>::iterator_category; > - if constexpr (!is_lvalue_reference_v<common_reference_t<iter_reference_t<_InnerIter>, > + // _GLIBCXX_RESOLVE_LIB_DEFECTS > + // 3798. Rvalue reference and iterator_category > + if constexpr (!is_reference_v<common_reference_t<iter_reference_t<_InnerIter>, > iter_reference_t<_PatternIter>>>) This line is misaligned with the previous one now. LGTM besides that > return input_iterator_tag{}; > else if constexpr (derived_from<_OuterCat, bidirectional_iterator_tag> > diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/transform.cc b/libstdc++-v3/testsuite/std/ranges/adaptors/transform.cc > index ca695349650..e1b74353e63 100644 > --- a/libstdc++-v3/testsuite/std/ranges/adaptors/transform.cc > +++ b/libstdc++-v3/testsuite/std/ranges/adaptors/transform.cc > @@ -214,6 +214,21 @@ test10() > static_assert(std::same_as<cat, std::random_access_iterator_tag>); > } > > +void > +test11() > +{ > + struct MoveIt { > + int&& operator()(int& i) const { return std::move(i); } > + }; > + > + int x[] {2, 4}; > + auto xform = x | views::transform(MoveIt{}); > + using iterator = decltype(xform.begin()); > + // LWG 3798. Rvalue reference and iterator_category > + using cat = std::iterator_traits<iterator>::iterator_category; > + static_assert(std::same_as<cat, std::random_access_iterator_tag>); > +} > + > int > main() > { > @@ -227,4 +242,5 @@ main() > test08(); > test09(); > test10(); > + test11(); > } > -- > 2.46.2 > >
On Tue, 15 Oct 2024 at 14:30, Patrick Palka <ppalka@redhat.com> wrote: > > On Mon, 14 Oct 2024, Jonathan Wakely wrote: > > > Tested x86_64-linux. > > > > -- >8 -- > > > > LWG 3798 modified the iterator_category of the iterator types for > > transform_view, join_with_view, zip_transform_view and > > adjacent_transform_view, to allow the iterator's reference type to be an > > rvalue reference. > > > > libstdc++-v3/ChangeLog: > > > > PR libstdc++/106676 > > * include/bits/iterator_concepts.h (__cpp17_fwd_iterator): Use > > is_reference instead of is_value_reference. > > rvalue references. > > * include/std/ranges (transform_view:__iter_cat::_S_iter_cat): > > Likewise. > > (zip_transform_view::__iter_cat::_S_iter_cat): Likewise. > > (adjacent_transform_view::__iter_cat::_S_iter_cat): Likewise. > > (join_with_view::__iter_cat::_S_iter_cat): Likewise. > > * testsuite/std/ranges/adaptors/transform.cc: Check > > iterator_category when the transformation function returns an > > rvalue reference type. > > --- > > libstdc++-v3/include/bits/iterator_concepts.h | 4 +++- > > libstdc++-v3/include/std/ranges | 16 ++++++++++++---- > > .../testsuite/std/ranges/adaptors/transform.cc | 16 ++++++++++++++++ > > 3 files changed, 31 insertions(+), 5 deletions(-) > > > > diff --git a/libstdc++-v3/include/bits/iterator_concepts.h b/libstdc++-v3/include/bits/iterator_concepts.h > > index 490a362cdf1..669d3ddfd1e 100644 > > --- a/libstdc++-v3/include/bits/iterator_concepts.h > > +++ b/libstdc++-v3/include/bits/iterator_concepts.h > > @@ -333,10 +333,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > > typename incrementable_traits<_Iter>::difference_type>; > > }; > > > > + // _GLIBCXX_RESOLVE_LIB_DEFECTS > > + // 3798. Rvalue reference and iterator_category > > template<typename _Iter> > > concept __cpp17_fwd_iterator = __cpp17_input_iterator<_Iter> > > && constructible_from<_Iter> > > - && is_lvalue_reference_v<iter_reference_t<_Iter>> > > + && is_reference_v<iter_reference_t<_Iter>> > > && same_as<remove_cvref_t<iter_reference_t<_Iter>>, > > typename indirectly_readable_traits<_Iter>::value_type> > > && requires(_Iter __it) > > diff --git a/libstdc++-v3/include/std/ranges b/libstdc++-v3/include/std/ranges > > index f0d81cbea0c..941189d65c3 100644 > > --- a/libstdc++-v3/include/std/ranges > > +++ b/libstdc++-v3/include/std/ranges > > @@ -1892,7 +1892,9 @@ namespace views::__adaptor > > using _Fpc = __detail::__maybe_const_t<_Const, _Fp>; > > using _Base = transform_view::_Base<_Const>; > > using _Res = invoke_result_t<_Fpc&, range_reference_t<_Base>>; > > - if constexpr (is_lvalue_reference_v<_Res>) > > + // _GLIBCXX_RESOLVE_LIB_DEFECTS > > + // 3798. Rvalue reference and iterator_category > > + if constexpr (is_reference_v<_Res>) > > { > > using _Cat > > = typename iterator_traits<iterator_t<_Base>>::iterator_category; > > @@ -5047,7 +5049,9 @@ namespace views::__adaptor > > using __detail::__range_iter_cat; > > using _Res = invoke_result_t<__maybe_const_t<_Const, _Fp>&, > > range_reference_t<__maybe_const_t<_Const, _Vs>>...>; > > - if constexpr (!is_lvalue_reference_v<_Res>) > > + // _GLIBCXX_RESOLVE_LIB_DEFECTS > > + // 3798. Rvalue reference and iterator_category > > + if constexpr (!is_reference_v<_Res>) > > return input_iterator_tag{}; > > else if constexpr ((derived_from<__range_iter_cat<_Vs, _Const>, > > random_access_iterator_tag> && ...)) > > @@ -5820,7 +5824,9 @@ namespace views::__adaptor > > using _Res = invoke_result_t<__unarize<__maybe_const_t<_Const, _Fp>&, _Nm>, > > range_reference_t<_Base>>; > > using _Cat = typename iterator_traits<iterator_t<_Base>>::iterator_category; > > - if constexpr (!is_lvalue_reference_v<_Res>) > > + // _GLIBCXX_RESOLVE_LIB_DEFECTS > > + // 3798. Rvalue reference and iterator_category > > + if constexpr (!is_reference_v<_Res>) > > return input_iterator_tag{}; > > else if constexpr (derived_from<_Cat, random_access_iterator_tag>) > > return random_access_iterator_tag{}; > > @@ -7228,7 +7234,9 @@ namespace views::__adaptor > > using _OuterCat = typename iterator_traits<_OuterIter>::iterator_category; > > using _InnerCat = typename iterator_traits<_InnerIter>::iterator_category; > > using _PatternCat = typename iterator_traits<_PatternIter>::iterator_category; > > - if constexpr (!is_lvalue_reference_v<common_reference_t<iter_reference_t<_InnerIter>, > > + // _GLIBCXX_RESOLVE_LIB_DEFECTS > > + // 3798. Rvalue reference and iterator_category > > + if constexpr (!is_reference_v<common_reference_t<iter_reference_t<_InnerIter>, > > iter_reference_t<_PatternIter>>>) > > This line is misaligned with the previous one now. LGTM besides that Ah yes, good catch. I'll fix and push, thanks. > > > return input_iterator_tag{}; > > else if constexpr (derived_from<_OuterCat, bidirectional_iterator_tag> > > diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/transform.cc b/libstdc++-v3/testsuite/std/ranges/adaptors/transform.cc > > index ca695349650..e1b74353e63 100644 > > --- a/libstdc++-v3/testsuite/std/ranges/adaptors/transform.cc > > +++ b/libstdc++-v3/testsuite/std/ranges/adaptors/transform.cc > > @@ -214,6 +214,21 @@ test10() > > static_assert(std::same_as<cat, std::random_access_iterator_tag>); > > } > > > > +void > > +test11() > > +{ > > + struct MoveIt { > > + int&& operator()(int& i) const { return std::move(i); } > > + }; > > + > > + int x[] {2, 4}; > > + auto xform = x | views::transform(MoveIt{}); > > + using iterator = decltype(xform.begin()); > > + // LWG 3798. Rvalue reference and iterator_category > > + using cat = std::iterator_traits<iterator>::iterator_category; > > + static_assert(std::same_as<cat, std::random_access_iterator_tag>); > > +} > > + > > int > > main() > > { > > @@ -227,4 +242,5 @@ main() > > test08(); > > test09(); > > test10(); > > + test11(); > > } > > -- > > 2.46.2 > > > > >
diff --git a/libstdc++-v3/include/bits/iterator_concepts.h b/libstdc++-v3/include/bits/iterator_concepts.h index 490a362cdf1..669d3ddfd1e 100644 --- a/libstdc++-v3/include/bits/iterator_concepts.h +++ b/libstdc++-v3/include/bits/iterator_concepts.h @@ -333,10 +333,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION typename incrementable_traits<_Iter>::difference_type>; }; + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 3798. Rvalue reference and iterator_category template<typename _Iter> concept __cpp17_fwd_iterator = __cpp17_input_iterator<_Iter> && constructible_from<_Iter> - && is_lvalue_reference_v<iter_reference_t<_Iter>> + && is_reference_v<iter_reference_t<_Iter>> && same_as<remove_cvref_t<iter_reference_t<_Iter>>, typename indirectly_readable_traits<_Iter>::value_type> && requires(_Iter __it) diff --git a/libstdc++-v3/include/std/ranges b/libstdc++-v3/include/std/ranges index f0d81cbea0c..941189d65c3 100644 --- a/libstdc++-v3/include/std/ranges +++ b/libstdc++-v3/include/std/ranges @@ -1892,7 +1892,9 @@ namespace views::__adaptor using _Fpc = __detail::__maybe_const_t<_Const, _Fp>; using _Base = transform_view::_Base<_Const>; using _Res = invoke_result_t<_Fpc&, range_reference_t<_Base>>; - if constexpr (is_lvalue_reference_v<_Res>) + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 3798. Rvalue reference and iterator_category + if constexpr (is_reference_v<_Res>) { using _Cat = typename iterator_traits<iterator_t<_Base>>::iterator_category; @@ -5047,7 +5049,9 @@ namespace views::__adaptor using __detail::__range_iter_cat; using _Res = invoke_result_t<__maybe_const_t<_Const, _Fp>&, range_reference_t<__maybe_const_t<_Const, _Vs>>...>; - if constexpr (!is_lvalue_reference_v<_Res>) + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 3798. Rvalue reference and iterator_category + if constexpr (!is_reference_v<_Res>) return input_iterator_tag{}; else if constexpr ((derived_from<__range_iter_cat<_Vs, _Const>, random_access_iterator_tag> && ...)) @@ -5820,7 +5824,9 @@ namespace views::__adaptor using _Res = invoke_result_t<__unarize<__maybe_const_t<_Const, _Fp>&, _Nm>, range_reference_t<_Base>>; using _Cat = typename iterator_traits<iterator_t<_Base>>::iterator_category; - if constexpr (!is_lvalue_reference_v<_Res>) + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 3798. Rvalue reference and iterator_category + if constexpr (!is_reference_v<_Res>) return input_iterator_tag{}; else if constexpr (derived_from<_Cat, random_access_iterator_tag>) return random_access_iterator_tag{}; @@ -7228,7 +7234,9 @@ namespace views::__adaptor using _OuterCat = typename iterator_traits<_OuterIter>::iterator_category; using _InnerCat = typename iterator_traits<_InnerIter>::iterator_category; using _PatternCat = typename iterator_traits<_PatternIter>::iterator_category; - if constexpr (!is_lvalue_reference_v<common_reference_t<iter_reference_t<_InnerIter>, + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 3798. Rvalue reference and iterator_category + if constexpr (!is_reference_v<common_reference_t<iter_reference_t<_InnerIter>, iter_reference_t<_PatternIter>>>) return input_iterator_tag{}; else if constexpr (derived_from<_OuterCat, bidirectional_iterator_tag> diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/transform.cc b/libstdc++-v3/testsuite/std/ranges/adaptors/transform.cc index ca695349650..e1b74353e63 100644 --- a/libstdc++-v3/testsuite/std/ranges/adaptors/transform.cc +++ b/libstdc++-v3/testsuite/std/ranges/adaptors/transform.cc @@ -214,6 +214,21 @@ test10() static_assert(std::same_as<cat, std::random_access_iterator_tag>); } +void +test11() +{ + struct MoveIt { + int&& operator()(int& i) const { return std::move(i); } + }; + + int x[] {2, 4}; + auto xform = x | views::transform(MoveIt{}); + using iterator = decltype(xform.begin()); + // LWG 3798. Rvalue reference and iterator_category + using cat = std::iterator_traits<iterator>::iterator_category; + static_assert(std::same_as<cat, std::random_access_iterator_tag>); +} + int main() { @@ -227,4 +242,5 @@ main() test08(); test09(); test10(); + test11(); }