Skip to content

Commit 6cd8e5c

Browse files
committed
[libc++] Disallow std::prev(non_cpp17_bidi_iterator)
1 parent 51a2f50 commit 6cd8e5c

File tree

2 files changed

+24
-1
lines changed
  • libcxx
    • include/__iterator
    • test/std/iterators/iterator.primitives/iterator.operations

2 files changed

+24
-1
lines changed

libcxx/include/__iterator/prev.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include <__iterator/incrementable_traits.h>
1818
#include <__iterator/iterator_traits.h>
1919
#include <__type_traits/enable_if.h>
20+
#include <__utility/move.h>
2021

2122
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
2223
# pragma GCC system_header
@@ -26,7 +27,7 @@ _LIBCPP_BEGIN_NAMESPACE_STD
2627

2728
template <class _InputIter, __enable_if_t<__has_input_iterator_category<_InputIter>::value, int> = 0>
2829
[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 _InputIter
29-
prev(_InputIter __x, typename iterator_traits<_InputIter>::difference_type __n = 1) {
30+
prev(_InputIter __x, typename iterator_traits<_InputIter>::difference_type __n) {
3031
// Calling `advance` with a negative value on a non-bidirectional iterator is a no-op in the current implementation.
3132
// Note that this check duplicates the similar check in `std::advance`.
3233
_LIBCPP_ASSERT_PEDANTIC(__n <= 0 || __has_bidirectional_iterator_category<_InputIter>::value,
@@ -35,6 +36,13 @@ prev(_InputIter __x, typename iterator_traits<_InputIter>::difference_type __n =
3536
return __x;
3637
}
3738

39+
template <class _BidirectionalIterator,
40+
__enable_if_t<__has_bidirectional_iterator_category<_BidirectionalIterator>::value, int> = 0>
41+
[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 _BidirectionalIterator
42+
prev(_BidirectionalIterator __it) {
43+
return std::prev(std::move(__it), 1);
44+
}
45+
3846
#if _LIBCPP_STD_VER >= 20
3947

4048
// [range.iter.op.prev]

libcxx/test/std/iterators/iterator.primitives/iterator.operations/prev.pass.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,21 @@
1818
#include "test_macros.h"
1919
#include "test_iterators.h"
2020

21+
template <class Iter>
22+
std::false_type prev_test(...);
23+
24+
template <class Iter>
25+
decltype((void) std::prev(std::declval<Iter>()), std::true_type()) prev_test(int);
26+
27+
template <class Iter>
28+
using CanPrev = decltype(prev_test<Iter>(0));
29+
30+
static_assert(!CanPrev<cpp17_input_iterator<int*> >::value, "");
31+
static_assert(CanPrev<bidirectional_iterator<int*> >::value, "");
32+
#if TEST_STD_VER >= 20
33+
static_assert(!CanPrev<cpp20_random_access_iterator<int*> >::value);
34+
#endif
35+
2136
template <class It>
2237
TEST_CONSTEXPR_CXX17 void
2338
check_prev_n(It it, typename std::iterator_traits<It>::difference_type n, It result)

0 commit comments

Comments
 (0)