-
Notifications
You must be signed in to change notification settings - Fork 13.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[libc++] Remove redundant and somewhat confusing assertions around advance() #133276
base: main
Are you sure you want to change the base?
Conversation
…vance() The std::advance function has a clear precondition that it can only be called with a negative distance when a bidirectional iterator is used. However, prev() and next() don't have such preconditions explicitly, they inherit it from calling advance(). This patch removes assertions in prev() and next() that were duplicates of similar ones in advance(), and removes a copy-pasted comment that was trying to justify the use of _LIBCPP_ASSERT_PEDANTIC but IMO is creating confusion with little benefit.
@llvm/pr-subscribers-libcxx Author: Louis Dionne (ldionne) ChangesThe std::advance function has a clear precondition that it can only be called with a negative distance when a bidirectional iterator is used. However, prev() and next() don't have such preconditions explicitly, they inherit it from calling advance(). This patch removes assertions in prev() and next() that were duplicates of similar ones in advance(), and removes a copy-pasted comment that was trying to justify the use of _LIBCPP_ASSERT_PEDANTIC but IMO is creating confusion with little benefit. Full diff: https://github.com/llvm/llvm-project/pull/133276.diff 3 Files Affected:
diff --git a/libcxx/include/__iterator/advance.h b/libcxx/include/__iterator/advance.h
index 57b1b845f1afa..f1a8d28f39aa0 100644
--- a/libcxx/include/__iterator/advance.h
+++ b/libcxx/include/__iterator/advance.h
@@ -65,8 +65,7 @@ template < class _InputIter,
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 void advance(_InputIter& __i, _Distance __orig_n) {
typedef typename iterator_traits<_InputIter>::difference_type _Difference;
_Difference __n = static_cast<_Difference>(std::__convert_to_integral(__orig_n));
- // Calling `advance` with a negative value on a non-bidirectional iterator is a no-op in the current implementation.
- _LIBCPP_ASSERT_PEDANTIC(__n >= 0 || __has_bidirectional_iterator_category<_InputIter>::value,
+ _LIBCPP_ASSERT_PEDANTIC(__has_bidirectional_iterator_category<_InputIter>::value || __n >= 0,
"Attempt to advance(it, n) with negative n on a non-bidirectional iterator");
std::__advance(__i, __n, typename iterator_traits<_InputIter>::iterator_category());
}
@@ -98,9 +97,8 @@ struct __advance {
// Preconditions: If `I` does not model `bidirectional_iterator`, `n` is not negative.
template <input_or_output_iterator _Ip>
_LIBCPP_HIDE_FROM_ABI constexpr void operator()(_Ip& __i, iter_difference_t<_Ip> __n) const {
- // Calling `advance` with a negative value on a non-bidirectional iterator is a no-op in the current implementation.
- _LIBCPP_ASSERT_PEDANTIC(
- __n >= 0 || bidirectional_iterator<_Ip>, "If `n < 0`, then `bidirectional_iterator<I>` must be true.");
+ _LIBCPP_ASSERT_PEDANTIC(bidirectional_iterator<_Ip> || __n >= 0,
+ "ranges::advance: Can only pass a negative `n` with a bidirectional_iterator.");
// If `I` models `random_access_iterator`, equivalent to `i += n`.
if constexpr (random_access_iterator<_Ip>) {
@@ -149,9 +147,9 @@ struct __advance {
template <input_or_output_iterator _Ip, sentinel_for<_Ip> _Sp>
_LIBCPP_HIDE_FROM_ABI constexpr iter_difference_t<_Ip>
operator()(_Ip& __i, iter_difference_t<_Ip> __n, _Sp __bound_sentinel) const {
- // Calling `advance` with a negative value on a non-bidirectional iterator is a no-op in the current implementation.
- _LIBCPP_ASSERT_PEDANTIC((__n >= 0) || (bidirectional_iterator<_Ip> && same_as<_Ip, _Sp>),
- "If `n < 0`, then `bidirectional_iterator<I> && same_as<I, S>` must be true.");
+ _LIBCPP_ASSERT_PEDANTIC(
+ (bidirectional_iterator<_Ip> && same_as<_Ip, _Sp>) || (__n >= 0),
+ "ranges::advance: Can only pass a negative `n` with a bidirectional_iterator coming from a common_range.");
// If `S` and `I` model `sized_sentinel_for<S, I>`:
if constexpr (sized_sentinel_for<_Sp, _Ip>) {
// If |n| >= |bound_sentinel - i|, equivalent to `ranges::advance(i, bound_sentinel)`.
diff --git a/libcxx/include/__iterator/next.h b/libcxx/include/__iterator/next.h
index 1f68a5bec8f39..1143ab31ff7c2 100644
--- a/libcxx/include/__iterator/next.h
+++ b/libcxx/include/__iterator/next.h
@@ -10,7 +10,6 @@
#ifndef _LIBCPP___ITERATOR_NEXT_H
#define _LIBCPP___ITERATOR_NEXT_H
-#include <__assert>
#include <__config>
#include <__iterator/advance.h>
#include <__iterator/concepts.h>
@@ -27,11 +26,6 @@ _LIBCPP_BEGIN_NAMESPACE_STD
template <class _InputIter, __enable_if_t<__has_input_iterator_category<_InputIter>::value, int> = 0>
[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 _InputIter
next(_InputIter __x, typename iterator_traits<_InputIter>::difference_type __n = 1) {
- // 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,
- "Attempt to next(it, n) with negative n on a non-bidirectional iterator");
-
std::advance(__x, __n);
return __x;
}
diff --git a/libcxx/include/__iterator/prev.h b/libcxx/include/__iterator/prev.h
index bffd5527dc953..97139e067c896 100644
--- a/libcxx/include/__iterator/prev.h
+++ b/libcxx/include/__iterator/prev.h
@@ -10,7 +10,6 @@
#ifndef _LIBCPP___ITERATOR_PREV_H
#define _LIBCPP___ITERATOR_PREV_H
-#include <__assert>
#include <__config>
#include <__iterator/advance.h>
#include <__iterator/concepts.h>
@@ -31,10 +30,6 @@ _LIBCPP_BEGIN_NAMESPACE_STD
template <class _InputIter, __enable_if_t<__has_input_iterator_category<_InputIter>::value, int> = 0>
[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 _InputIter
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,
- "Attempt to prev(it, n) with a positive n on a non-bidirectional iterator");
std::advance(__x, -__n);
return __x;
}
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am a bit surprised there are no failing tests.
LGTM modulo one comment.
@@ -65,8 +65,7 @@ template < class _InputIter, | |||
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 void advance(_InputIter& __i, _Distance __orig_n) { | |||
typedef typename iterator_traits<_InputIter>::difference_type _Difference; | |||
_Difference __n = static_cast<_Difference>(std::__convert_to_integral(__orig_n)); | |||
// Calling `advance` with a negative value on a non-bidirectional iterator is a no-op in the current implementation. | |||
_LIBCPP_ASSERT_PEDANTIC(__n >= 0 || __has_bidirectional_iterator_category<_InputIter>::value, | |||
_LIBCPP_ASSERT_PEDANTIC(__has_bidirectional_iterator_category<_InputIter>::value || __n >= 0, | |||
"Attempt to advance(it, n) with negative n on a non-bidirectional iterator"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This makes the message consistent with what's used in ranges.
"Attempt to advance(it, n) with negative n on a non-bidirectional iterator"); | |
"std::advance: Can only pass a negative `n` with a bidirectional_iterator."); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is an unrelated change though. I'd much rather have this in a separate PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll do this as a follow-up.
You can test this locally with the following command:git-clang-format --diff HEAD~1 HEAD --extensions cpp,h -- libcxx/include/__iterator/advance.h libcxx/include/__iterator/next.h libcxx/include/__iterator/prev.h libcxx/test/libcxx/iterators/assert.next.pass.cpp libcxx/test/libcxx/iterators/assert.prev.pass.cpp View the diff from clang-format here.diff --git a/libcxx/test/libcxx/iterators/assert.next.pass.cpp b/libcxx/test/libcxx/iterators/assert.next.pass.cpp
index 1e8672308..927070075 100644
--- a/libcxx/test/libcxx/iterators/assert.next.pass.cpp
+++ b/libcxx/test/libcxx/iterators/assert.next.pass.cpp
@@ -25,7 +25,8 @@ int main(int, char**) {
forward_iterator<int *> it(a+1);
(void)std::next(it, 1); // should work fine
(void)std::next(it, 0); // should work fine
- TEST_LIBCPP_ASSERT_FAILURE(std::next(it, -1), "Attempt to advance(it, n) with negative n on a non-bidirectional iterator");
+ TEST_LIBCPP_ASSERT_FAILURE(
+ std::next(it, -1), "Attempt to advance(it, n) with negative n on a non-bidirectional iterator");
return 0;
}
diff --git a/libcxx/test/libcxx/iterators/assert.prev.pass.cpp b/libcxx/test/libcxx/iterators/assert.prev.pass.cpp
index 29b8d6ed5..34b8a7365 100644
--- a/libcxx/test/libcxx/iterators/assert.prev.pass.cpp
+++ b/libcxx/test/libcxx/iterators/assert.prev.pass.cpp
@@ -31,7 +31,8 @@ int main(int, char**) {
forward_iterator<int *> it(a+1);
(void)std::prev(it, -1); // should work fine
(void)std::prev(it, 0); // should work fine
- TEST_LIBCPP_ASSERT_FAILURE(std::prev(it, 1), "Attempt to advance(it, n) with negative n on a non-bidirectional iterator");
+ TEST_LIBCPP_ASSERT_FAILURE(
+ std::prev(it, 1), "Attempt to advance(it, n) with negative n on a non-bidirectional iterator");
return 0;
}
|
The std::advance function has a clear precondition that it can only be called with a negative distance when a bidirectional iterator is used. However, prev() and next() don't have such preconditions explicitly, they inherit it from calling advance().
This patch removes assertions in prev() and next() that were duplicates of similar ones in advance(), and removes a copy-pasted comment that was trying to justify the use of _LIBCPP_ASSERT_PEDANTIC but IMO is creating confusion with little benefit.