[gcc/devel/c++-modules] libstdc++: Make tests for std::ranges access functions more robust

Nathan Sidwell nathan@gcc.gnu.org
Fri Jan 31 17:50:00 GMT 2020


https://gcc.gnu.org/g:5cd2e126f5c5705fa1aa7fafef3d6b94a99593da

commit 5cd2e126f5c5705fa1aa7fafef3d6b94a99593da
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Wed Jan 29 13:36:15 2020 +0000

    libstdc++: Make tests for std::ranges access functions more robust
    
    	* testsuite/std/ranges/access/end.cc: Do not assume test_range::end()
    	returns the same type as test_range::begin(). Add comments.
    	* testsuite/std/ranges/access/rbegin.cc: Likewise.
    	* testsuite/std/ranges/access/rend.cc: Likewise.
    	* testsuite/std/ranges/range.cc: Do not assume the sentinel for
    	test_range is the same as its iterator type.
    	* testsuite/util/testsuite_iterators.h (test_range::sentinel): Add
    	operator- overloads to satisfy sized_sentinel_for when the iterator
    	satisfies random_access_iterator.

Diff:
---
 libstdc++-v3/ChangeLog                             | 12 ++++
 libstdc++-v3/testsuite/std/ranges/access/end.cc    | 12 +++-
 libstdc++-v3/testsuite/std/ranges/access/rbegin.cc | 28 +++++++-
 libstdc++-v3/testsuite/std/ranges/access/rend.cc   | 83 ++++++++++++++--------
 libstdc++-v3/testsuite/std/ranges/range.cc         |  2 +-
 libstdc++-v3/testsuite/util/testsuite_iterators.h  | 10 ++-
 6 files changed, 112 insertions(+), 35 deletions(-)

diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog
index 151ede0..133e216 100644
--- a/libstdc++-v3/ChangeLog
+++ b/libstdc++-v3/ChangeLog
@@ -1,3 +1,15 @@
+2020-01-29  Jonathan Wakely  <jwakely@redhat.com>
+
+	* testsuite/std/ranges/access/end.cc: Do not assume test_range::end()
+	returns the same type as test_range::begin(). Add comments.
+	* testsuite/std/ranges/access/rbegin.cc: Likewise.
+	* testsuite/std/ranges/access/rend.cc: Likewise.
+	* testsuite/std/ranges/range.cc: Do not assume the sentinel for
+	test_range is the same as its iterator type.
+	* testsuite/util/testsuite_iterators.h (test_range::sentinel): Add
+	operator- overloads to satisfy sized_sentinel_for when the iterator
+	satisfies random_access_iterator.
+
 2020-01-28  Jonathan Wakely  <jwakely@redhat.com>
 
 	PR libstdc++/93470
diff --git a/libstdc++-v3/testsuite/std/ranges/access/end.cc b/libstdc++-v3/testsuite/std/ranges/access/end.cc
index 2bb0e52..c3a1028 100644
--- a/libstdc++-v3/testsuite/std/ranges/access/end.cc
+++ b/libstdc++-v3/testsuite/std/ranges/access/end.cc
@@ -29,6 +29,8 @@ test01()
 {
   int a[2] = {};
 
+  // t + extent_v<T> if E is of array type T.
+
   static_assert(same_as<decltype(std::ranges::end(a)), decltype(a + 2)>);
   static_assert(noexcept(std::ranges::end(a)));
   VERIFY( std::ranges::end(a) == (a + 2) );
@@ -44,13 +46,16 @@ test02()
 
   int a[] = { 0, 1 };
 
+  // Otherwise, decay-copy(t.end()) if it is a valid expression
+  // and its type S models sentinel_for<decltype(ranges::begin(E))>.
+
   test_range<int, random_access_iterator_wrapper> r(a);
   static_assert(same_as<decltype(std::ranges::end(r)), decltype(r.end())>);
-  VERIFY( std::ranges::end(r) == r.end() );
+  VERIFY( std::ranges::end(r) == std::ranges::next(r.begin(), 2) );
 
   test_range<int, input_iterator_wrapper> i(a);
   static_assert(same_as<decltype(std::ranges::end(i)), decltype(i.end())>);
-  VERIFY( std::ranges::end(i) == i.end() );
+  VERIFY( std::ranges::end(i) == std::ranges::next(i.begin(), 2) );
 
   test_range<int, output_iterator_wrapper> o(a);
   static_assert(same_as<decltype(std::ranges::end(o)), decltype(o.end())>);
@@ -93,6 +98,9 @@ test03()
   R r;
   const R& c = r;
 
+  // Otherwise, decay-copy(end(t)) if it is a valid expression
+  // and its type S models sentinel_for<decltype(ranges::begin(E))>.
+
   static_assert(same_as<decltype(std::ranges::end(r)), decltype(end(r))>);
   static_assert(!noexcept(std::ranges::end(r)));
   VERIFY( std::ranges::end(r) == end(r) );
diff --git a/libstdc++-v3/testsuite/std/ranges/access/rbegin.cc b/libstdc++-v3/testsuite/std/ranges/access/rbegin.cc
index 03e73a9..e92e5bc 100644
--- a/libstdc++-v3/testsuite/std/ranges/access/rbegin.cc
+++ b/libstdc++-v3/testsuite/std/ranges/access/rbegin.cc
@@ -38,6 +38,8 @@ void
 test01()
 {
   constexpr R1 r;
+  // decay-copy(t.rbegin()) if it is a valid expression
+  // and its type I models input_or_output_iterator.
   static_assert( std::ranges::rbegin(r) == &r.i );
   static_assert( std::ranges::rbegin(std::move(r)) == &r.i );
 }
@@ -60,6 +62,8 @@ void
 test02()
 {
   constexpr R2 r;
+  // Otherwise, decay-copy(rbegin(t)) if it is a valid expression
+  // and its type I models input_or_output_iterator [...]
   static_assert( std::ranges::rbegin(r)
       == std::make_reverse_iterator(std::ranges::end(r)) );
   static_assert( std::ranges::rbegin(std::move(r))
@@ -69,11 +73,29 @@ test02()
 void
 test03()
 {
-  using __gnu_test::test_range;
-  using __gnu_test::bidirectional_iterator_wrapper;
+  struct R3
+  : __gnu_test::test_range<int, __gnu_test::bidirectional_iterator_wrapper>
+  {
+    R3(int (&a)[2]) : test_range(a) { }
+
+    using test_range::begin;
+
+    // Replace test_range::end() to return same type as begin()
+    // so ranges::rbegin will wrap it in a reverse_iterator .
+    auto end() &
+    {
+      using __gnu_test::bidirectional_iterator_wrapper;
+      return bidirectional_iterator_wrapper<int>(bounds.last, &bounds);
+    }
+  };
 
   int a[2] = { };
-  test_range<int, bidirectional_iterator_wrapper> r(a);
+  R3 r(a);
+
+  // Otherwise, make_reverse_iterator(ranges::end(t)) if both ranges::begin(t)
+  // and ranges::end(t) are valid expressions of the same type I which models
+  // bidirectional_iterator.
+
   VERIFY( std::ranges::rbegin(r) == std::make_reverse_iterator(std::ranges::end(r)) );
 }
 
diff --git a/libstdc++-v3/testsuite/std/ranges/access/rend.cc b/libstdc++-v3/testsuite/std/ranges/access/rend.cc
index 42816d9..f6909b8 100644
--- a/libstdc++-v3/testsuite/std/ranges/access/rend.cc
+++ b/libstdc++-v3/testsuite/std/ranges/access/rend.cc
@@ -40,65 +40,91 @@ void
 test01()
 {
   constexpr R1 r;
+
+  // decay-copy(t.rend()) if it is a valid expression
+  // and its type S models sentinel_for<decltype(ranges::rbegin(E))>
+
   static_assert( std::ranges::rend(r) == &r.i + 1 );
   static_assert( std::ranges::rend(std::move(r)) == &r.i + 1 );
 }
 
 struct R2
 {
-  int a[2] = { };
-  long l[2] = { };
+  int i = 0;
 
-  constexpr const int* begin() const { return a; }
-  constexpr const int* end() const { return a + 2; }
+  int* rbegin() noexcept { return &i + 1; }
+  long* rend() noexcept { return nullptr; } // not a sentinel for rbegin()
 
-  friend constexpr const long* begin(const R2&& r) { return r.l; }
-  friend constexpr const long* end(const R2&& r) { return r.l + 2; }
+  friend long* rbegin(R2&) noexcept { return nullptr; }
+  friend int* rend(R2& r) { return &r.i; }
 };
 
-// N.B. this is a lie, begin/end on an R2 rvalue will return a dangling pointer.
-template<> constexpr bool std::ranges::enable_safe_range<R2> = true;
-
 void
 test02()
 {
-  constexpr R2 r;
-  static_assert( std::ranges::rend(r)
-      == std::make_reverse_iterator(std::ranges::begin(r)) );
-  static_assert( std::ranges::rend(std::move(r))
-      == std::make_reverse_iterator(std::ranges::begin(std::move(r))) );
+  R2 r;
+
+  // Otherwise, decay-copy(rend(t)) if it is a valid expression
+  // and its type S models sentinel_for<decltype(ranges::rbegin(E))>
+
+  auto i1 = std::ranges::rbegin(r);
+  auto i2 = rend(r);
+  static_assert( std::sentinel_for<decltype(i2), decltype(i1)> );
+  VERIFY( std::ranges::rend(r) == &r.i );
+  static_assert( !noexcept(std::ranges::rend(r)) );
 }
 
 struct R3
 {
-  int i = 0;
+  int a[2] = { };
+  long l[2] = { };
 
-  int* rbegin() noexcept { return &i + 1; }
-  long* rend() noexcept { return nullptr; } // not a sentinel for rbegin()
+  constexpr const int* begin() const { return a; }
+  constexpr const int* end() const { return a + 2; }
 
-  friend long* rbegin(R3&) noexcept { return nullptr; }
-  friend int* rend(R3& r) { return &r.i; }
+  friend constexpr const long* begin(const R3&& r) { return r.l; }
+  friend constexpr const long* end(const R3&& r) { return r.l + 2; }
 };
 
+// N.B. this is a lie, begin/end on an R3 rvalue will return a dangling pointer.
+template<> constexpr bool std::ranges::enable_safe_range<R3> = true;
+
 void
 test03()
 {
-  R3 r;
-  auto i1 = std::ranges::rbegin(r);
-  auto i2 = rend(r);
-  static_assert( std::sentinel_for<decltype(i2), decltype(i1)> );
-  // VERIFY( std::ranges::rend(r) == r.i );
-  // static_assert( !noexcept(std::ranges::rend(r)) );
+  constexpr R3 r;
+
+  // Otherwise, make_reverse_iterator(ranges::begin(t)) if both
+  // ranges::begin(t) and ranges::end(t) are valid expressions
+  // of the same type I which models bidirectional_iterator.
+
+  static_assert( std::ranges::rend(r)
+      == std::make_reverse_iterator(std::ranges::begin(r)) );
+  static_assert( std::ranges::rend(std::move(r))
+      == std::make_reverse_iterator(std::ranges::begin(std::move(r))) );
 }
 
 void
 test04()
 {
-  using __gnu_test::test_range;
-  using __gnu_test::bidirectional_iterator_wrapper;
+  struct R4
+  : __gnu_test::test_range<int, __gnu_test::bidirectional_iterator_wrapper>
+  {
+    R4(int (&a)[2]) : test_range(a) { }
+
+    using test_range::begin;
+
+    // Replace test_range::end() to return same type as begin()
+    // so ranges::rend will wrap it in a reverse_iterator.
+    auto end() &
+    {
+      using __gnu_test::bidirectional_iterator_wrapper;
+      return bidirectional_iterator_wrapper<int>(bounds.last, &bounds);
+    }
+  };
 
   int a[2] = { };
-  test_range<int, bidirectional_iterator_wrapper> r(a);
+  R4 r(a);
   VERIFY( std::ranges::rend(r) == std::make_reverse_iterator(std::ranges::begin(r)) );
 }
 
@@ -108,4 +134,5 @@ main()
   test01();
   test02();
   test03();
+  test04();
 }
diff --git a/libstdc++-v3/testsuite/std/ranges/range.cc b/libstdc++-v3/testsuite/std/ranges/range.cc
index fabbcf9..cf349de 100644
--- a/libstdc++-v3/testsuite/std/ranges/range.cc
+++ b/libstdc++-v3/testsuite/std/ranges/range.cc
@@ -66,7 +66,7 @@ static_assert( same_as<std::ranges::iterator_t<O>,
 		       decltype(std::declval<O&>().begin())> );
 
 static_assert( same_as<std::ranges::sentinel_t<C>,
-		       contiguous_iterator_wrapper<char>> );
+		       decltype(std::declval<C&>().end())> );
 static_assert( same_as<std::ranges::sentinel_t<O>,
 		       decltype(std::declval<O&>().end())> );
 
diff --git a/libstdc++-v3/testsuite/util/testsuite_iterators.h b/libstdc++-v3/testsuite/util/testsuite_iterators.h
index eb15257..1c7fbd0 100644
--- a/libstdc++-v3/testsuite/util/testsuite_iterators.h
+++ b/libstdc++-v3/testsuite/util/testsuite_iterators.h
@@ -675,8 +675,16 @@ namespace __gnu_test
 	{
 	  T* end;
 
-	  friend bool operator==(const sentinel& s, const I& i)
+	  friend bool operator==(const sentinel& s, const I& i) noexcept
 	  { return s.end == i.ptr; }
+
+	  friend auto operator-(const sentinel& s, const I& i) noexcept
+	    requires std::random_access_iterator<I>
+	  { return s.end - i.ptr; }
+
+	  friend auto operator-(const I& i, const sentinel& s) noexcept
+	    requires std::random_access_iterator<I>
+	  { return i.ptr - s.end; }
 	};
 
       auto



More information about the Libstdc++-cvs mailing list