Fix a minor bug with std::next and prev not and negative numbers. In particular, std::prev cannot require Bidirectional Iterators, because you might 'go back' -1 places, which goes forward. Thanks to Ville and Jonathan for the bug report.
git-svn-id: https://llvm.org/svn/llvm-project/libcxx/trunk@356818 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/iterator b/include/iterator
index 16c1bcb..5846c1b 100644
--- a/include/iterator
+++ b/include/iterator
@@ -584,6 +584,8 @@
void advance(_InputIter& __i,
typename iterator_traits<_InputIter>::difference_type __n)
{
+ _LIBCPP_ASSERT(__n >= 0 || __is_bidirectional_iterator<_InputIter>::value,
+ "Attempt to advance(it, -n) on a non-bidi iterator");
__advance(__i, __n, typename iterator_traits<_InputIter>::iterator_category());
}
@@ -624,20 +626,25 @@
next(_InputIter __x,
typename iterator_traits<_InputIter>::difference_type __n = 1)
{
+ _LIBCPP_ASSERT(__n >= 0 || __is_bidirectional_iterator<_InputIter>::value,
+ "Attempt to next(it, -n) on a non-bidi iterator");
+
_VSTD::advance(__x, __n);
return __x;
}
-template <class _BidirectionalIter>
+template <class _InputIter>
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14
typename enable_if
<
- __is_bidirectional_iterator<_BidirectionalIter>::value,
- _BidirectionalIter
+ __is_input_iterator<_InputIter>::value,
+ _InputIter
>::type
-prev(_BidirectionalIter __x,
- typename iterator_traits<_BidirectionalIter>::difference_type __n = 1)
+prev(_InputIter __x,
+ typename iterator_traits<_InputIter>::difference_type __n = 1)
{
+ _LIBCPP_ASSERT(__n <= 0 || __is_bidirectional_iterator<_InputIter>::value,
+ "Attempt to prev(it, +n) on a non-bidi iterator");
_VSTD::advance(__x, -__n);
return __x;
}
diff --git a/test/libcxx/iterators/advance.debug1.pass.cpp b/test/libcxx/iterators/advance.debug1.pass.cpp
new file mode 100644
index 0000000..37aa3df
--- /dev/null
+++ b/test/libcxx/iterators/advance.debug1.pass.cpp
@@ -0,0 +1,42 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// Can't test the system lib because this test enables debug mode
+// MODULES_DEFINES: _LIBCPP_DEBUG=1
+// UNSUPPORTED: c++98, c++03
+// UNSUPPORTED: windows
+// UNSUPPORTED: with_system_cxx_lib
+
+// <list>
+
+// Call advance(non-bidi iterator, -1)
+
+#define _LIBCPP_DEBUG 0
+
+#include <iterator>
+#include "debug_mode_helper.h"
+
+#include "test_iterators.h"
+
+int main(int, char**)
+{
+ int a[] = {1, 2, 3};
+
+ bidirectional_iterator<int *> bidi(a+1);
+ std::advance(bidi, 1); // should work fine
+ std::advance(bidi, 0); // should work fine
+ std::advance(bidi, -1); // should work fine
+
+ forward_iterator<int *> it(a+1);
+ std::advance(it, 1); // should work fine
+ std::advance(it, 0); // should work fine
+ EXPECT_DEATH( std::advance(it, -1) ); // can't go backwards on a FwdIter
+
+ return 0;
+}
+
diff --git a/test/libcxx/iterators/next.debug1.pass.cpp b/test/libcxx/iterators/next.debug1.pass.cpp
new file mode 100644
index 0000000..72d9fd4
--- /dev/null
+++ b/test/libcxx/iterators/next.debug1.pass.cpp
@@ -0,0 +1,38 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// Can't test the system lib because this test enables debug mode
+// MODULES_DEFINES: _LIBCPP_DEBUG=1
+// UNSUPPORTED: c++98, c++03
+// UNSUPPORTED: windows
+// UNSUPPORTED: with_system_cxx_lib
+
+// <list>
+
+// Call next(non-bidi iterator, -1)
+
+#define _LIBCPP_DEBUG 0
+
+#include <iterator>
+#include "debug_mode_helper.h"
+
+#include "test_iterators.h"
+
+int main(int, char**)
+{
+ int a[] = {1, 2, 3};
+
+
+ forward_iterator<int *> it(a+1);
+ std::next(it, 1); // should work fine
+ std::next(it, 0); // should work fine
+ EXPECT_DEATH( std::next(it, -1) ); // can't go backwards on a FwdIter
+
+ return 0;
+}
+
diff --git a/test/libcxx/iterators/prev.debug1.pass.cpp b/test/libcxx/iterators/prev.debug1.pass.cpp
new file mode 100644
index 0000000..da7c931
--- /dev/null
+++ b/test/libcxx/iterators/prev.debug1.pass.cpp
@@ -0,0 +1,42 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// Can't test the system lib because this test enables debug mode
+// MODULES_DEFINES: _LIBCPP_DEBUG=1
+// UNSUPPORTED: with_system_cxx_lib
+// UNSUPPORTED: c++98, c++03
+// UNSUPPORTED: windows
+// UNSUPPORTED: with_system_cxx_lib
+
+// <list>
+
+// Call prev(forward_iterator, -1)
+
+#define _LIBCPP_DEBUG 0
+
+#include <iterator>
+#include "debug_mode_helper.h"
+
+#include "test_iterators.h"
+
+int main(int, char**)
+{
+ int a[] = {1, 2, 3};
+
+ bidirectional_iterator<int *> bidi(a+1);
+ std::prev(bidi, -1); // should work fine
+ std::prev(bidi, 0); // should work fine
+ std::prev(bidi, 1); // should work fine
+
+ forward_iterator<int *> it(a+1);
+ std::prev(it, -1); // should work fine
+ std::prev(it, 0); // should work fine
+ EXPECT_DEATH( std::prev(it, 1) ); // can't go backwards on a FwdIter
+
+ return 0;
+}
diff --git a/test/std/iterators/iterator.primitives/iterator.operations/next.pass.cpp b/test/std/iterators/iterator.primitives/iterator.operations/next.pass.cpp
index 87f79fb..26ec32c 100644
--- a/test/std/iterators/iterator.primitives/iterator.operations/next.pass.cpp
+++ b/test/std/iterators/iterator.primitives/iterator.operations/next.pass.cpp
@@ -55,10 +55,12 @@
{
{
const char* s = "1234567890";
- test(input_iterator<const char*>(s), 10, input_iterator<const char*>(s+10));
- test(forward_iterator<const char*>(s), 10, forward_iterator<const char*>(s+10));
- test(bidirectional_iterator<const char*>(s), 10, bidirectional_iterator<const char*>(s+10));
- test(random_access_iterator<const char*>(s), 10, random_access_iterator<const char*>(s+10));
+ test(input_iterator<const char*>(s), 10, input_iterator<const char*>(s+10));
+ test(forward_iterator<const char*>(s), 10, forward_iterator<const char*>(s+10));
+ test(bidirectional_iterator<const char*>(s), 10, bidirectional_iterator<const char*>(s+10));
+ test(bidirectional_iterator<const char*>(s+10), -10, bidirectional_iterator<const char*>(s));
+ test(random_access_iterator<const char*>(s), 10, random_access_iterator<const char*>(s+10));
+ test(random_access_iterator<const char*>(s+10), -10, random_access_iterator<const char*>(s));
test(s, 10, s+10);
test(input_iterator<const char*>(s), input_iterator<const char*>(s+1));
@@ -70,10 +72,12 @@
#if TEST_STD_VER > 14
{
constexpr const char* s = "1234567890";
- static_assert( constexpr_test(input_iterator<const char*>(s), 10, input_iterator<const char*>(s+10)), "" );
- static_assert( constexpr_test(forward_iterator<const char*>(s), 10, forward_iterator<const char*>(s+10)), "" );
- static_assert( constexpr_test(bidirectional_iterator<const char*>(s), 10, bidirectional_iterator<const char*>(s+10)), "" );
- static_assert( constexpr_test(random_access_iterator<const char*>(s), 10, random_access_iterator<const char*>(s+10)), "" );
+ static_assert( constexpr_test(input_iterator<const char*>(s), 10, input_iterator<const char*>(s+10)), "" );
+ static_assert( constexpr_test(forward_iterator<const char*>(s), 10, forward_iterator<const char*>(s+10)), "" );
+ static_assert( constexpr_test(bidirectional_iterator<const char*>(s), 10, bidirectional_iterator<const char*>(s+10)), "" );
+ static_assert( constexpr_test(bidirectional_iterator<const char*>(s+10), -10, bidirectional_iterator<const char*>(s)), "" );
+ static_assert( constexpr_test(random_access_iterator<const char*>(s), 10, random_access_iterator<const char*>(s+10)), "" );
+ static_assert( constexpr_test(random_access_iterator<const char*>(s+10), -10, random_access_iterator<const char*>(s)), "" );
static_assert( constexpr_test(s, 10, s+10), "" );
static_assert( constexpr_test(input_iterator<const char*>(s), input_iterator<const char*>(s+1)), "" );
diff --git a/test/std/iterators/iterator.primitives/iterator.operations/prev.pass.cpp b/test/std/iterators/iterator.primitives/iterator.operations/prev.pass.cpp
index 2ee0444..8faaf3d 100644
--- a/test/std/iterators/iterator.primitives/iterator.operations/prev.pass.cpp
+++ b/test/std/iterators/iterator.primitives/iterator.operations/prev.pass.cpp
@@ -8,7 +8,7 @@
// <iterator>
-// template <BidirectionalIterator Iter>
+// template <InputIterator Iter>
// Iter prev(Iter x, Iter::difference_type n = 1);
#include <iterator>
@@ -53,8 +53,11 @@
{
{
const char* s = "1234567890";
- test(bidirectional_iterator<const char*>(s+10), 10, bidirectional_iterator<const char*>(s));
- test(random_access_iterator<const char*>(s+10), 10, random_access_iterator<const char*>(s));
+ test(forward_iterator <const char*>(s), -10, forward_iterator <const char*>(s+10));
+ test(bidirectional_iterator<const char*>(s+10), 10, bidirectional_iterator<const char*>(s));
+ test(bidirectional_iterator<const char*>(s), -10, bidirectional_iterator<const char*>(s+10));
+ test(random_access_iterator<const char*>(s+10), 10, random_access_iterator<const char*>(s));
+ test(random_access_iterator<const char*>(s), -10, random_access_iterator<const char*>(s+10));
test(s+10, 10, s);
test(bidirectional_iterator<const char*>(s+1), bidirectional_iterator<const char*>(s));
@@ -64,8 +67,11 @@
#if TEST_STD_VER > 14
{
constexpr const char* s = "1234567890";
- static_assert( constexpr_test(bidirectional_iterator<const char*>(s+10), 10, bidirectional_iterator<const char*>(s)), "" );
- static_assert( constexpr_test(random_access_iterator<const char*>(s+10), 10, random_access_iterator<const char*>(s)), "" );
+ static_assert( constexpr_test(forward_iterator <const char*>(s), -10, forward_iterator <const char*>(s+10)), "" );
+ static_assert( constexpr_test(bidirectional_iterator<const char*>(s+10), 10, bidirectional_iterator<const char*>(s)), "" );
+ static_assert( constexpr_test(forward_iterator <const char*>(s), -10, forward_iterator <const char*>(s+10)), "" );
+ static_assert( constexpr_test(random_access_iterator<const char*>(s+10), 10, random_access_iterator<const char*>(s)), "" );
+ static_assert( constexpr_test(forward_iterator <const char*>(s), -10, forward_iterator <const char*>(s+10)), "" );
static_assert( constexpr_test(s+10, 10, s), "" );
static_assert( constexpr_test(bidirectional_iterator<const char*>(s+1), bidirectional_iterator<const char*>(s)), "" );