Re: [PATCH] libstdc++: Add missing friend declarations in some range adaptors

2020-02-27 Thread Jonathan Wakely

On 27/02/20 11:27 -0500, Patrick Palka wrote:

Some of the range adaptors have distinct constant and non-constant
iterator/sentinel types, along with converting constructors that can convert a
non-constant iterator/sentinel to a constant iterator/sentinel.  This patch adds
the missing appropriate friend declarations in order to make these converting
constructors well formed.

Strictly speaking it seems the friendship relation doesn't need to go both ways
-- we could get away with declaring e.g. friend _Iterator; instead of
friend _Iterator; but the spec and the reference implementations all
seem to use the latter symmetric form anyway.


I think at least one of those friend declarations in the spec was
recently removed, because the class it was in is presented for
exposition only, so doesn't actually need to declare other
non-existent classes as friends. But it's certainly not a problem to
use _Iterator rather than _Iterator.

OK for master, thanks.




[PATCH] libstdc++: Add missing friend declarations in some range adaptors

2020-02-27 Thread Patrick Palka
Some of the range adaptors have distinct constant and non-constant
iterator/sentinel types, along with converting constructors that can convert a
non-constant iterator/sentinel to a constant iterator/sentinel.  This patch adds
the missing appropriate friend declarations in order to make these converting
constructors well formed.

Strictly speaking it seems the friendship relation doesn't need to go both ways
-- we could get away with declaring e.g. friend _Iterator; instead of
friend _Iterator; but the spec and the reference implementations all
seem to use the latter symmetric form anyway.

libstdc++-v3/ChangeLog:

* include/std/ranges (transform_view::_Iterator<_Const>): Befriend
_Iterator.
(transform_view::_Sentinel<_Const>): Befriend _Sentinel.
(take_view::_Sentinel<_Const>): Likewise.
(take_while_view::_Sentinel<_Const>): Likewise.
(split_view::_OuterIter<_Const>): Befriend _OuterIter.
* std/ranges/adaptors/split.cc: Augment test.
* std/ranges/adaptors/take.cc: Augment test.
* std/ranges/adaptors/take_while.cc: Augment test.
* std/ranges/adaptors/transform.cc: Augment test.
---
 libstdc++-v3/include/std/ranges   |  8 +++
 .../testsuite/std/ranges/adaptors/split.cc| 14 +++
 .../testsuite/std/ranges/adaptors/take.cc | 16 +
 .../std/ranges/adaptors/take_while.cc | 17 ++
 .../std/ranges/adaptors/transform.cc  | 23 +++
 5 files changed, 78 insertions(+)

diff --git a/libstdc++-v3/include/std/ranges b/libstdc++-v3/include/std/ranges
index 2e3e298adcc..2f08cfd7f16 100644
--- a/libstdc++-v3/include/std/ranges
+++ b/libstdc++-v3/include/std/ranges
@@ -1844,6 +1844,7 @@ namespace views
requires indirectly_swappable<_Base_iter>
  { return ranges::iter_swap(__x._M_current, __y._M_current); }
 
+ friend _Iterator;
  friend _Sentinel<_Const>;
};
 
@@ -1896,6 +1897,8 @@ namespace views
  operator-(const _Sentinel& __y, const _Iterator<_Const>& __x)
requires sized_sentinel_for, iterator_t<_Base>>
  { return __y.__distance_from(__x); }
+
+ friend _Sentinel;
};
 
   _Vp _M_base = _Vp();
@@ -2001,6 +2004,8 @@ namespace views
 
  friend constexpr bool operator==(const _CI& __y, const _Sentinel& __x)
  { return __y.count() == 0 || __y.base() == __x._M_end; }
+
+ friend _Sentinel;
};
 
   _Vp _M_base = _Vp();
@@ -2140,6 +2145,8 @@ namespace views
  friend constexpr bool
  operator==(const iterator_t<_Base>& __x, const _Sentinel& __y)
  { return __y._M_end == __x || !std::__invoke(*__y._M_pred, *__x); }
+
+ friend _Sentinel;
};
 
   _Vp _M_base = _Vp();
@@ -2831,6 +2838,7 @@ namespace views
  operator==(const _OuterIter& __x, default_sentinel_t)
  { return __x.__at_end(); };
 
+ friend _OuterIter;
  friend _InnerIter<_Const>;
};
 
diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/split.cc 
b/libstdc++-v3/testsuite/std/ranges/adaptors/split.cc
index 52b015cf0c6..e7556725e4f 100644
--- a/libstdc++-v3/testsuite/std/ranges/adaptors/split.cc
+++ b/libstdc++-v3/testsuite/std/ranges/adaptors/split.cc
@@ -108,6 +108,19 @@ test05()
str | views::filter(not_space_p)) );
 }
 
+void
+test06()
+{
+  std::string str = "hello world";
+  auto v = str | views::transform(std::identity{}) | views::split(' ');
+
+  // Verify that _Iterator is implicitly convertible to _Iterator.
+  static_assert(!std::same_as);
+  auto b = ranges::cbegin(v);
+  b = ranges::begin(v);
+}
+
 int
 main()
 {
@@ -116,4 +129,5 @@ main()
   test03();
   test04();
   test05();
+  test06();
 }
diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/take.cc 
b/libstdc++-v3/testsuite/std/ranges/adaptors/take.cc
index e2d2edbe0a8..c42505b44cb 100644
--- a/libstdc++-v3/testsuite/std/ranges/adaptors/take.cc
+++ b/libstdc++-v3/testsuite/std/ranges/adaptors/take.cc
@@ -19,6 +19,7 @@
 // { dg-do run { target c++2a } }
 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -85,6 +86,20 @@ test04()
   VERIFY( ranges::equal(v | views::take(5), (int[]){1,2,3}) );
 }
 
+void
+test05()
+{
+  std::forward_list x = {1,2,3,4,5};
+  auto v = x | views::transform(std::negate{}) | views::take(4);
+
+  // Verify that _Sentinel is implicitly convertible to _Sentinel.
+  static_assert(!ranges::common_range);
+  static_assert(!std::same_as);
+  auto b = ranges::cend(v);
+  b = ranges::end(v);
+}
+
 int
 main()
 {
@@ -92,4 +107,5 @@ main()
   test02();
   test03();
   test04();
+  test05();
 }
diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/take_while.cc 
b/libstdc++-v3/testsuite/std/ranges/adaptors/take_while.cc
index b261ffd1aae..d587127b97e 100644
--- a/libstdc++-v3/testsuite/std/ranges/adaptors/take_while.cc
+++ b/libstdc++-v3/testsuite/std/ranges/adaptors/take_while.cc
@@