aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJonathan Wakely <jwakely@redhat.com>2025-03-26 11:21:32 +0000
committerJonathan Wakely <redi@gcc.gnu.org>2025-03-27 11:14:52 +0000
commit3e52eb28c537aaa03afb78ef9dff8325c5f41f78 (patch)
tree3b12c6075086db1b39cf1473000589cc149cd1f4
parentb631ff45f231db55b28b4c92cf1a1b46b3638ddd (diff)
downloadgcc-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.h11
-rw-r--r--libstdc++-v3/testsuite/24_iterators/customization_points/iter_move.cc11
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();
}