diff --git a/libcxx/include/__iterator/prev.h b/libcxx/include/__iterator/prev.h index 7e97203836eb9..bffd5527dc953 100644 --- a/libcxx/include/__iterator/prev.h +++ b/libcxx/include/__iterator/prev.h @@ -17,16 +17,20 @@ #include <__iterator/incrementable_traits.h> #include <__iterator/iterator_traits.h> #include <__type_traits/enable_if.h> +#include <__utility/move.h> #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header #endif +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + _LIBCPP_BEGIN_NAMESPACE_STD template ::value, int> = 0> [[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 _InputIter -prev(_InputIter __x, typename iterator_traits<_InputIter>::difference_type __n = 1) { +prev(_InputIter __x, typename iterator_traits<_InputIter>::difference_type __n) { // Calling `advance` with a negative value on a non-bidirectional iterator is a no-op in the current implementation. // Note that this check duplicates the similar check in `std::advance`. _LIBCPP_ASSERT_PEDANTIC(__n <= 0 || __has_bidirectional_iterator_category<_InputIter>::value, @@ -35,6 +39,16 @@ prev(_InputIter __x, typename iterator_traits<_InputIter>::difference_type __n = return __x; } +// LWG 3197 +// It is unclear what the implications of "BidirectionalIterator" in the standard are. +// However, calling std::prev(non-bidi-iterator) is obviously an error and we should catch it at compile time. +template ::value, int> = 0> +[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 _InputIter prev(_InputIter __it) { + static_assert(__has_bidirectional_iterator_category<_InputIter>::value, + "Attempt to prev(it) with a non-bidirectional iterator"); + return std::prev(std::move(__it), 1); +} + #if _LIBCPP_STD_VER >= 20 // [range.iter.op.prev] @@ -70,4 +84,6 @@ inline constexpr auto prev = __prev{}; _LIBCPP_END_NAMESPACE_STD +_LIBCPP_POP_MACROS + #endif // _LIBCPP___ITERATOR_PREV_H diff --git a/libcxx/test/libcxx/iterators/iterator.primitives/iterator.operations/prev.verify.cpp b/libcxx/test/libcxx/iterators/iterator.primitives/iterator.operations/prev.verify.cpp new file mode 100644 index 0000000000000..da0a336815a5c --- /dev/null +++ b/libcxx/test/libcxx/iterators/iterator.primitives/iterator.operations/prev.verify.cpp @@ -0,0 +1,19 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// std::prev + +#include +#include "test_iterators.h" + +void test() { + int arr[] = {1, 2}; + cpp17_input_iterator it(&arr[0]); + it = std::prev(it); + // expected-error-re@*:* {{static assertion failed due to requirement {{.*}}: Attempt to prev(it) with a non-bidirectional iterator}} +}