diff --git a/libcxx/include/__algorithm/iterator_operations.h b/libcxx/include/__algorithm/iterator_operations.h --- a/libcxx/include/__algorithm/iterator_operations.h +++ b/libcxx/include/__algorithm/iterator_operations.h @@ -17,6 +17,7 @@ #include <__iterator/iter_swap.h> #include <__iterator/iterator_traits.h> #include <__iterator/next.h> +#include <__utility/declval.h> #include <__utility/forward.h> #include <__utility/move.h> #include @@ -63,24 +64,37 @@ return std::distance(__first, __last); } + template + using __deref_t = decltype(*std::declval<_Iter>()); + + template + using __move_t = decltype(std::move(std::declval<__deref_t<_Iter> >())); + // iter_move template - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX11 - // Declaring the return type is necessary for C++03, so we basically mirror what `decltype(auto)` would deduce. - static __enable_if_t< - is_reference >::reference>::value, - typename remove_reference< typename iterator_traits<__uncvref_t<_Iter> >::reference >::type&&> - __iter_move(_Iter&& __i) { + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX11 static + // Declaring the return type is necessary for C++03. + // If the result of dereferencing `_Iter` is a reference type, deduce the result of calling `std::move` on it. + // Note that we can't rely on `iterator_traits` because those might be invalid. While that makes the user code + // non-conforming, it wouldn't be visible if the implementation used `foo = std::move(*iter);` rather than + // `foo = _IterOps<_Policy>::__iter_move(iter)`. + __enable_if_t< + is_reference<__deref_t<_Iter> >::value, + __move_t<_Iter> > + __iter_move(_Iter&& __i) { return std::move(*std::forward<_Iter>(__i)); } template - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX11 - // Declaring the return type is necessary for C++03, so we basically mirror what `decltype(auto)` would deduce. - static __enable_if_t< - !is_reference >::reference>::value, - typename iterator_traits<__uncvref_t<_Iter> >::reference> - __iter_move(_Iter&& __i) { + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX11 static + // Declaring the return type is necessary for C++03. + // If the result of dereferencing `_Iter` is a value type, deduce the return value of this function to also be a + // value -- otherwise, after `operator*` returns a temporary, this function would return a dangling reference to that + // temporary. + __enable_if_t< + !is_reference<__deref_t<_Iter> >::value, + __deref_t<_Iter> > + __iter_move(_Iter&& __i) { return *std::forward<_Iter>(__i); } @@ -100,7 +114,7 @@ template _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR_AFTER_CXX11 - __uncvref_t<_Iter> next(_Iter&& __it, + __uncvref_t<_Iter> next(_Iter&& __it, typename iterator_traits<__uncvref_t<_Iter> >::difference_type __n = 1){ return std::next(std::forward<_Iter>(__it), __n); }