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
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();
}