diff options
author | Jonathan Wakely <jwakely@redhat.com> | 2025-03-26 11:21:32 +0000 |
---|---|---|
committer | Jonathan Wakely <redi@gcc.gnu.org> | 2025-03-27 11:14:52 +0000 |
commit | 3e52eb28c537aaa03afb78ef9dff8325c5f41f78 (patch) | |
tree | 3b12c6075086db1b39cf1473000589cc149cd1f4 | |
parent | b631ff45f231db55b28b4c92cf1a1b46b3638ddd (diff) | |
download | gcc-3e52eb28c537aaa03afb78ef9dff8325c5f41f78.zip gcc-3e52eb28c537aaa03afb78ef9dff8325c5f41f78.tar.gz gcc-3e52eb28c537aaa03afb78ef9dff8325c5f41f78.tar.bz2 |
libstdc++: Fix std::ranges::iter_move for function references [PR119469]
The result of std::move (or a cast to an rvalue reference) on a function
reference is always an lvalue. Because std::ranges::iter_move was using
the type std::remove_reference_t<X>&& as the result of std::move, it was
giving the wrong type for function references. Use a decltype-specifier
with declval<remove_reference_t<X>>() instead of just using the
remove_reference_t<X>&& type directly. This gives the right result,
while still avoiding the cost of doing overload resolution for
std::move.
libstdc++-v3/ChangeLog:
PR libstdc++/119469
* include/bits/iterator_concepts.h (_IterMove::__result): Use
decltype-specifier instead of an explicit type.
* testsuite/24_iterators/customization_points/iter_move.cc:
Check results for function references.
Reviewed-by: Tomasz KamiĆski <tkaminsk@redhat.com>
-rw-r--r-- | libstdc++-v3/include/bits/iterator_concepts.h | 11 | ||||
-rw-r--r-- | libstdc++-v3/testsuite/24_iterators/customization_points/iter_move.cc | 11 |
2 files changed, 20 insertions, 2 deletions
diff --git a/libstdc++-v3/include/bits/iterator_concepts.h b/libstdc++-v3/include/bits/iterator_concepts.h index a201e24..e36556d 100644 --- a/libstdc++-v3/include/bits/iterator_concepts.h +++ b/libstdc++-v3/include/bits/iterator_concepts.h @@ -133,12 +133,19 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION struct __result<_Tp> { using type = decltype(iter_move(std::declval<_Tp>())); }; - // Otherwise, if *E if an lvalue, use std::move(*E). + // Otherwise, if *E is an lvalue, use std::move(*E). template<typename _Tp> requires (!__adl_imove<_Tp>) && is_lvalue_reference_v<__iter_ref_t<_Tp>> struct __result<_Tp> - { using type = remove_reference_t<__iter_ref_t<_Tp>>&&; }; + { + // Instead of decltype(std::move(*E)) we define the type as the + // return type of std::move, i.e. remove_reference_t<iter_ref>&&. + // N.B. the use of decltype(declval<X>()) instead of just X&& is + // needed for function reference types, see PR libstdc++/119469. + using type + = decltype(std::declval<remove_reference_t<__iter_ref_t<_Tp>>>()); + }; template<typename _Tp> static constexpr bool diff --git a/libstdc++-v3/testsuite/24_iterators/customization_points/iter_move.cc b/libstdc++-v3/testsuite/24_iterators/customization_points/iter_move.cc index 341bd5b..8737574 100644 --- a/libstdc++-v3/testsuite/24_iterators/customization_points/iter_move.cc +++ b/libstdc++-v3/testsuite/24_iterators/customization_points/iter_move.cc @@ -157,9 +157,20 @@ test_pr106612() static_assert( std::same_as<decltype(std::ranges::iter_move(I3{})), F> ); } +void +test_pr119469() +{ + // rvalue references to function types are weird. + using F = int(); + static_assert( std::same_as<std::iter_rvalue_reference_t<F>, F&> ); + static_assert( std::same_as<std::iter_rvalue_reference_t<F&>, F&> ); + static_assert( std::same_as<std::iter_rvalue_reference_t<F&&>, F&> ); +} + int main() { test01(); test_adl(); + test_pr119469(); } |