Skip to content

Commit e9c0c66

Browse files
authored
[libc++] Add [[nodiscard]] to std::prev and std::next (#109550)
Add `[[nodiscard]]` attribute to `std::prev` and `std::next`. Those are potential pitfalls for users who might think they mutate the iterator. Fixes #109452
1 parent 6022a3a commit e9c0c66

File tree

5 files changed

+33
-19
lines changed

5 files changed

+33
-19
lines changed

libcxx/include/__iterator/next.h

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
_LIBCPP_BEGIN_NAMESPACE_STD
2626

2727
template <class _InputIter, __enable_if_t<__has_input_iterator_category<_InputIter>::value, int> = 0>
28-
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 _InputIter
28+
[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 _InputIter
2929
next(_InputIter __x, typename iterator_traits<_InputIter>::difference_type __n = 1) {
3030
// Calling `advance` with a negative value on a non-bidirectional iterator is a no-op in the current implementation.
3131
// Note that this check duplicates the similar check in `std::advance`.
@@ -43,25 +43,26 @@ next(_InputIter __x, typename iterator_traits<_InputIter>::difference_type __n =
4343
namespace ranges {
4444
struct __next {
4545
template <input_or_output_iterator _Ip>
46-
_LIBCPP_HIDE_FROM_ABI constexpr _Ip operator()(_Ip __x) const {
46+
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Ip operator()(_Ip __x) const {
4747
++__x;
4848
return __x;
4949
}
5050

5151
template <input_or_output_iterator _Ip>
52-
_LIBCPP_HIDE_FROM_ABI constexpr _Ip operator()(_Ip __x, iter_difference_t<_Ip> __n) const {
52+
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Ip operator()(_Ip __x, iter_difference_t<_Ip> __n) const {
5353
ranges::advance(__x, __n);
5454
return __x;
5555
}
5656

5757
template <input_or_output_iterator _Ip, sentinel_for<_Ip> _Sp>
58-
_LIBCPP_HIDE_FROM_ABI constexpr _Ip operator()(_Ip __x, _Sp __bound_sentinel) const {
58+
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Ip operator()(_Ip __x, _Sp __bound_sentinel) const {
5959
ranges::advance(__x, __bound_sentinel);
6060
return __x;
6161
}
6262

6363
template <input_or_output_iterator _Ip, sentinel_for<_Ip> _Sp>
64-
_LIBCPP_HIDE_FROM_ABI constexpr _Ip operator()(_Ip __x, iter_difference_t<_Ip> __n, _Sp __bound_sentinel) const {
64+
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Ip
65+
operator()(_Ip __x, iter_difference_t<_Ip> __n, _Sp __bound_sentinel) const {
6566
ranges::advance(__x, __n, __bound_sentinel);
6667
return __x;
6768
}

libcxx/include/__iterator/prev.h

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
_LIBCPP_BEGIN_NAMESPACE_STD
2626

2727
template <class _InputIter, __enable_if_t<__has_input_iterator_category<_InputIter>::value, int> = 0>
28-
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 _InputIter
28+
[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 _InputIter
2929
prev(_InputIter __x, typename iterator_traits<_InputIter>::difference_type __n = 1) {
3030
// Calling `advance` with a negative value on a non-bidirectional iterator is a no-op in the current implementation.
3131
// Note that this check duplicates the similar check in `std::advance`.
@@ -42,19 +42,20 @@ prev(_InputIter __x, typename iterator_traits<_InputIter>::difference_type __n =
4242
namespace ranges {
4343
struct __prev {
4444
template <bidirectional_iterator _Ip>
45-
_LIBCPP_HIDE_FROM_ABI constexpr _Ip operator()(_Ip __x) const {
45+
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Ip operator()(_Ip __x) const {
4646
--__x;
4747
return __x;
4848
}
4949

5050
template <bidirectional_iterator _Ip>
51-
_LIBCPP_HIDE_FROM_ABI constexpr _Ip operator()(_Ip __x, iter_difference_t<_Ip> __n) const {
51+
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Ip operator()(_Ip __x, iter_difference_t<_Ip> __n) const {
5252
ranges::advance(__x, -__n);
5353
return __x;
5454
}
5555

5656
template <bidirectional_iterator _Ip>
57-
_LIBCPP_HIDE_FROM_ABI constexpr _Ip operator()(_Ip __x, iter_difference_t<_Ip> __n, _Ip __bound_iter) const {
57+
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Ip
58+
operator()(_Ip __x, iter_difference_t<_Ip> __n, _Ip __bound_iter) const {
5859
ranges::advance(__x, -__n, __bound_iter);
5960
return __x;
6061
}

libcxx/test/libcxx/diagnostics/iterator.nodiscard.verify.cpp

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,24 @@
1515
#include <iterator>
1616
#include <vector>
1717

18+
#include "test_macros.h"
19+
1820
void test() {
1921
std::vector<int> container;
2022
int c_array[] = {1, 2, 3};
2123
std::initializer_list<int> initializer_list;
2224

23-
std::empty(container); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
24-
std::empty(c_array); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
25-
std::empty(initializer_list); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
25+
std::empty(container); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
26+
std::empty(c_array); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
27+
std::empty(initializer_list); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
28+
std::prev(c_array); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
29+
std::next(c_array); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
30+
#if TEST_STD_VER >= 20
31+
std::ranges::prev(c_array); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
32+
std::ranges::prev(container.end(), 2); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
33+
std::ranges::next(container.end(), 2, container.begin()); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
34+
std::ranges::next(c_array); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
35+
std::ranges::next(container.begin(), 2); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
36+
std::ranges::next(container.end(), 1, container.end()); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
37+
#endif
2638
}

libcxx/test/libcxx/iterators/assert.next.pass.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@
2323
int main(int, char**) {
2424
int a[] = {1, 2, 3};
2525
forward_iterator<int *> it(a+1);
26-
std::next(it, 1); // should work fine
27-
std::next(it, 0); // should work fine
26+
(void)std::next(it, 1); // should work fine
27+
(void)std::next(it, 0); // should work fine
2828
TEST_LIBCPP_ASSERT_FAILURE(std::next(it, -1), "Attempt to next(it, n) with negative n on a non-bidirectional iterator");
2929

3030
return 0;

libcxx/test/libcxx/iterators/assert.prev.pass.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,13 @@ int main(int, char**) {
2424
int a[] = {1, 2, 3};
2525

2626
bidirectional_iterator<int *> bidi(a+1);
27-
std::prev(bidi, -1); // should work fine
28-
std::prev(bidi, 0); // should work fine
29-
std::prev(bidi, 1); // should work fine
27+
(void)std::prev(bidi, -1); // should work fine
28+
(void)std::prev(bidi, 0); // should work fine
29+
(void)std::prev(bidi, 1); // should work fine
3030

3131
forward_iterator<int *> it(a+1);
32-
std::prev(it, -1); // should work fine
33-
std::prev(it, 0); // should work fine
32+
(void)std::prev(it, -1); // should work fine
33+
(void)std::prev(it, 0); // should work fine
3434
TEST_LIBCPP_ASSERT_FAILURE(std::prev(it, 1), "Attempt to prev(it, n) with a positive n on a non-bidirectional iterator");
3535

3636
return 0;

0 commit comments

Comments
 (0)