public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [committed 1/3] libstdc++: Implement C++20 changes to insert iterators
@ 2020-03-27 23:28 Jonathan Wakely
  2020-03-27 23:29 ` [committed 2/3] libstdc++: Add remaining C++20 changes to iterator adaptors Jonathan Wakely
  0 siblings, 1 reply; 5+ messages in thread
From: Jonathan Wakely @ 2020-03-27 23:28 UTC (permalink / raw)
  To: libstdc++, gcc-patches

[-- Attachment #1: Type: text/plain, Size: 1745 bytes --]

std::insert_iterator and std::inserter need to be adjusted for C++20, so
that they use ranges::iterator_t. That alias template requires
ranges::begin to be defined. Rather than moving the whole of
ranges::begin (and related details like ranges::enable_borrowed_range)
into <iterator>, this defines a new, simpler version of ranges::begin
that is sufficient for ranges::iterator_t to be defined. This works
because ranges::iterator_t uses an lvalue reference type, so the logic
in ranges::begin for non-lvalue ranges (i.e. borrowed ranges) isn't
needed.

This also adds the missing constexpr specifiers to the other insert
iterators.

	* include/bits/iterator_concepts.h (__detail::__decay_copy)
	(__detail::__member_begin, __detail::__adl_begin): Move here from
	<bits/range_access.h>.
	(__detail::__ranges_begin, __detail::__range_iter_t): Define.
	* bits/range_access.h (__cust_access::__decay_copy)
	(__cust_access::__member_begin, __cust_access::__adl_begin): Move to
	<bits/iterator_concepts.h>.
	(ranges::iterator_t): Use __detail::__range_iter_t.
	* include/bits/stl_iterator.h (back_insert_iterator): Simplify
	conditional compilation. Add _GLIBCXX20_CONSTEXPR to all members.
	(front_insert_iterator): Likewise.
	(insert_iterator): Implement changes from P0896R4 for C++20.
	* testsuite/24_iterators/back_insert_iterator/constexpr.cc: New test.
	* testsuite/24_iterators/front_insert_iterator/constexpr.cc: New test.
	* testsuite/24_iterators/headers/iterator/synopsis_c++17.cc: Adjust
	for inclusion in synopsis_c++20.cc which expects different signatures
	for some function templates.
	* testsuite/24_iterators/insert_iterator/constexpr.cc: New test.

Tested powerpc64le-linux, committed to master.


[-- Attachment #2: patch.txt --]
[-- Type: text/plain, Size: 21329 bytes --]

commit ae6076b5bc1e0b689eaa8521571b0516de336553
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Fri Mar 27 23:21:58 2020 +0000

    libstdc++: Implement C++20 changes to insert iterators
    
    std::insert_iterator and std::inserter need to be adjusted for C++20, so
    that they use ranges::iterator_t. That alias template requires
    ranges::begin to be defined. Rather than moving the whole of
    ranges::begin (and related details like ranges::enable_borrowed_range)
    into <iterator>, this defines a new, simpler version of ranges::begin
    that is sufficient for ranges::iterator_t to be defined. This works
    because ranges::iterator_t uses an lvalue reference type, so the logic
    in ranges::begin for non-lvalue ranges (i.e. borrowed ranges) isn't
    needed.
    
    This also adds the missing constexpr specifiers to the other insert
    iterators.
    
            * include/bits/iterator_concepts.h (__detail::__decay_copy)
            (__detail::__member_begin, __detail::__adl_begin): Move here from
            <bits/range_access.h>.
            (__detail::__ranges_begin, __detail::__range_iter_t): Define.
            * bits/range_access.h (__cust_access::__decay_copy)
            (__cust_access::__member_begin, __cust_access::__adl_begin): Move to
            <bits/iterator_concepts.h>.
            (ranges::iterator_t): Use __detail::__range_iter_t.
            * include/bits/stl_iterator.h (back_insert_iterator): Simplify
            conditional compilation. Add _GLIBCXX20_CONSTEXPR to all members.
            (front_insert_iterator): Likewise.
            (insert_iterator): Implement changes from P0896R4 for C++20.
            * testsuite/24_iterators/back_insert_iterator/constexpr.cc: New test.
            * testsuite/24_iterators/front_insert_iterator/constexpr.cc: New test.
            * testsuite/24_iterators/headers/iterator/synopsis_c++17.cc: Adjust
            for inclusion in synopsis_c++20.cc which expects different signatures
            for some function templates.
            * testsuite/24_iterators/insert_iterator/constexpr.cc: New test.

diff --git a/libstdc++-v3/include/bits/iterator_concepts.h b/libstdc++-v3/include/bits/iterator_concepts.h
index 08e622259b4..b598532089e 100644
--- a/libstdc++-v3/include/bits/iterator_concepts.h
+++ b/libstdc++-v3/include/bits/iterator_concepts.h
@@ -835,6 +835,56 @@ namespace ranges
   struct default_sentinel_t { };
   inline constexpr default_sentinel_t default_sentinel{};
 
+  namespace __detail
+  {
+    template<typename _Tp>
+      constexpr decay_t<_Tp>
+      __decay_copy(_Tp&& __t)
+      noexcept(is_nothrow_convertible_v<_Tp, decay_t<_Tp>>)
+      { return std::forward<_Tp>(__t); }
+
+    template<typename _Tp>
+      concept __member_begin = requires(_Tp& __t)
+	{
+	  { __detail::__decay_copy(__t.begin()) } -> input_or_output_iterator;
+	};
+
+    void begin(auto&) = delete;
+    void begin(const auto&) = delete;
+
+    template<typename _Tp>
+      concept __adl_begin = __class_or_enum<remove_reference_t<_Tp>>
+	&& requires(_Tp& __t)
+	{
+	  { __detail::__decay_copy(begin(__t)) } -> input_or_output_iterator;
+	};
+
+    // Simplified version of std::ranges::begin that only supports lvalues,
+    // for use by __range_iter_t below.
+    template<typename _Tp>
+      requires is_array_v<_Tp> || __member_begin<_Tp&> || __adl_begin<_Tp&>
+      auto
+      __ranges_begin(_Tp& __t)
+      {
+	if constexpr (is_array_v<_Tp>)
+	  {
+	    static_assert(sizeof(remove_all_extents_t<_Tp>) != 0,
+			  "not array of incomplete type");
+	    return __t + 0;
+	  }
+	else if constexpr (__member_begin<_Tp&>)
+	  return __t.begin();
+	else
+	  return begin(__t);
+      }
+
+    // Implementation of std::ranges::iterator_t, without using ranges::begin.
+    template<typename _Tp>
+      using __range_iter_t
+	= decltype(__detail::__ranges_begin(std::declval<_Tp&>()));
+
+  } // namespace __detail
+
 _GLIBCXX_END_NAMESPACE_VERSION
 } // namespace std
 #endif // C++20 library concepts
diff --git a/libstdc++-v3/include/bits/range_access.h b/libstdc++-v3/include/bits/range_access.h
index 4dd48bbc6df..acd701e1385 100644
--- a/libstdc++-v3/include/bits/range_access.h
+++ b/libstdc++-v3/include/bits/range_access.h
@@ -372,28 +372,9 @@ namespace ranges
   {
     using std::ranges::__detail::__maybe_borrowed_range;
     using std::__detail::__class_or_enum;
-
-    template<typename _Tp>
-      constexpr decay_t<_Tp>
-      __decay_copy(_Tp&& __t)
-      noexcept(is_nothrow_convertible_v<_Tp, decay_t<_Tp>>)
-      { return std::forward<_Tp>(__t); }
-
-    template<typename _Tp>
-      concept __member_begin = requires(_Tp& __t)
-	{
-	  { __decay_copy(__t.begin()) } -> input_or_output_iterator;
-	};
-
-    void begin(auto&) = delete;
-    void begin(const auto&) = delete;
-
-    template<typename _Tp>
-      concept __adl_begin = __class_or_enum<remove_reference_t<_Tp>>
-	&& requires(_Tp& __t)
-	{
-	  { __decay_copy(begin(__t)) } -> input_or_output_iterator;
-	};
+    using std::__detail::__decay_copy;
+    using std::__detail::__member_begin;
+    using std::__detail::__adl_begin;
 
     struct _Begin
     {
@@ -889,7 +870,7 @@ namespace ranges
       = range<_Tp> && __detail::__maybe_borrowed_range<_Tp>;
 
   template<typename _Tp>
-    using iterator_t = decltype(ranges::begin(std::declval<_Tp&>()));
+    using iterator_t = std::__detail::__range_iter_t<_Tp>;
 
   template<range _Range>
     using sentinel_t = decltype(ranges::end(std::declval<_Range&>()));
diff --git a/libstdc++-v3/include/bits/stl_iterator.h b/libstdc++-v3/include/bits/stl_iterator.h
index caaa8c483b8..d10c30cbfcc 100644
--- a/libstdc++-v3/include/bits/stl_iterator.h
+++ b/libstdc++-v3/include/bits/stl_iterator.h
@@ -76,6 +76,7 @@
 #if __cplusplus > 201703L
 # include <compare>
 # include <new>
+# include <bits/iterator_concepts.h>
 #endif
 
 namespace std _GLIBCXX_VISIBILITY(default)
@@ -496,25 +497,19 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     : public iterator<output_iterator_tag, void, void, void, void>
     {
     protected:
-#if __cplusplus <= 201703L
       _Container* container;
-#else
-      _Container* container = nullptr;
-#endif
 
     public:
       /// A nested typedef for the type of whatever container you used.
       typedef _Container          container_type;
 #if __cplusplus > 201703L
       using difference_type = ptrdiff_t;
-#endif
 
-#if __cplusplus > 201703L
-      constexpr back_insert_iterator() noexcept = default;
+      constexpr back_insert_iterator() noexcept : container(nullptr) { }
 #endif
 
       /// The only way to create this %iterator is with a container.
-      explicit
+      explicit _GLIBCXX20_CONSTEXPR
       back_insert_iterator(_Container& __x)
       : container(std::__addressof(__x)) { }
 
@@ -537,6 +532,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	return *this;
       }
 #else
+      _GLIBCXX20_CONSTEXPR
       back_insert_iterator&
       operator=(const typename _Container::value_type& __value)
       {
@@ -544,6 +540,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	return *this;
       }
 
+      _GLIBCXX20_CONSTEXPR
       back_insert_iterator&
       operator=(typename _Container::value_type&& __value)
       {
@@ -553,16 +550,19 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #endif
 
       /// Simply returns *this.
+      _GLIBCXX20_CONSTEXPR
       back_insert_iterator&
       operator*()
       { return *this; }
 
       /// Simply returns *this.  (This %iterator does not @a move.)
+      _GLIBCXX20_CONSTEXPR
       back_insert_iterator&
       operator++()
       { return *this; }
 
       /// Simply returns *this.  (This %iterator does not @a move.)
+      _GLIBCXX20_CONSTEXPR
       back_insert_iterator
       operator++(int)
       { return *this; }
@@ -580,6 +580,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
    *  types for you.
   */
   template<typename _Container>
+    _GLIBCXX20_CONSTEXPR
     inline back_insert_iterator<_Container>
     back_inserter(_Container& __x)
     { return back_insert_iterator<_Container>(__x); }
@@ -599,25 +600,20 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     : public iterator<output_iterator_tag, void, void, void, void>
     {
     protected:
-#if __cplusplus <= 201703L
       _Container* container;
-#else
-      _Container* container = nullptr;
-#endif
 
     public:
       /// A nested typedef for the type of whatever container you used.
       typedef _Container          container_type;
 #if __cplusplus > 201703L
       using difference_type = ptrdiff_t;
-#endif
 
-#if __cplusplus > 201703L
-      constexpr front_insert_iterator() noexcept = default;
+      constexpr front_insert_iterator() noexcept : container(nullptr) { }
 #endif
 
       /// The only way to create this %iterator is with a container.
-      explicit front_insert_iterator(_Container& __x)
+      explicit _GLIBCXX20_CONSTEXPR
+      front_insert_iterator(_Container& __x)
       : container(std::__addressof(__x)) { }
 
       /**
@@ -639,6 +635,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	return *this;
       }
 #else
+      _GLIBCXX20_CONSTEXPR
       front_insert_iterator&
       operator=(const typename _Container::value_type& __value)
       {
@@ -646,6 +643,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	return *this;
       }
 
+      _GLIBCXX20_CONSTEXPR
       front_insert_iterator&
       operator=(typename _Container::value_type&& __value)
       {
@@ -655,16 +653,19 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #endif
 
       /// Simply returns *this.
+      _GLIBCXX20_CONSTEXPR
       front_insert_iterator&
       operator*()
       { return *this; }
 
       /// Simply returns *this.  (This %iterator does not @a move.)
+      _GLIBCXX20_CONSTEXPR
       front_insert_iterator&
       operator++()
       { return *this; }
 
       /// Simply returns *this.  (This %iterator does not @a move.)
+      _GLIBCXX20_CONSTEXPR
       front_insert_iterator
       operator++(int)
       { return *this; }
@@ -682,6 +683,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
    *  types for you.
   */
   template<typename _Container>
+    _GLIBCXX20_CONSTEXPR
     inline front_insert_iterator<_Container>
     front_inserter(_Container& __x)
     { return front_insert_iterator<_Container>(__x); }
@@ -704,19 +706,36 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     class insert_iterator
     : public iterator<output_iterator_tag, void, void, void, void>
     {
+#if __cplusplus > 201703L && defined __cpp_lib_concepts
+      using _Iter = std::__detail::__range_iter_t<_Container>;
+
+    protected:
+      _Container* container = nullptr;
+      _Iter iter = _Iter();
+#else
+      typedef typename _Container::iterator		_Iter;
+
     protected:
       _Container* container;
-      typename _Container::iterator iter;
+      _Iter iter;
+#endif
 
     public:
       /// A nested typedef for the type of whatever container you used.
       typedef _Container          container_type;
 
+#if __cplusplus > 201703L && defined __cpp_lib_concepts
+      using difference_type = ptrdiff_t;
+
+      insert_iterator() = default;
+#endif
+
       /**
        *  The only way to create this %iterator is with a container and an
        *  initial position (a normal %iterator into the container).
       */
-      insert_iterator(_Container& __x, typename _Container::iterator __i)
+      _GLIBCXX20_CONSTEXPR
+      insert_iterator(_Container& __x, _Iter __i)
       : container(std::__addressof(__x)), iter(__i) {}
 
       /**
@@ -751,6 +770,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	return *this;
       }
 #else
+      _GLIBCXX20_CONSTEXPR
       insert_iterator&
       operator=(const typename _Container::value_type& __value)
       {
@@ -759,6 +779,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	return *this;
       }
 
+      _GLIBCXX20_CONSTEXPR
       insert_iterator&
       operator=(typename _Container::value_type&& __value)
       {
@@ -769,16 +790,19 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #endif
 
       /// Simply returns *this.
+      _GLIBCXX20_CONSTEXPR
       insert_iterator&
       operator*()
       { return *this; }
 
       /// Simply returns *this.  (This %iterator does not @a move.)
+      _GLIBCXX20_CONSTEXPR
       insert_iterator&
       operator++()
       { return *this; }
 
       /// Simply returns *this.  (This %iterator does not @a move.)
+      _GLIBCXX20_CONSTEXPR
       insert_iterator&
       operator++(int)
       { return *this; }
@@ -796,6 +820,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
    *  template parameter deduction, making the compiler match the correct
    *  types for you.
   */
+#if __cplusplus > 201703L && defined __cpp_lib_concepts
+  template<typename _Container>
+    constexpr insert_iterator<_Container>
+    inserter(_Container& __x, std::__detail::__range_iter_t<_Container> __i)
+    { return insert_iterator<_Container>(__x, __i); }
+#else
   template<typename _Container, typename _Iterator>
     inline insert_iterator<_Container>
     inserter(_Container& __x, _Iterator __i)
@@ -803,6 +833,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       return insert_iterator<_Container>(__x,
 					 typename _Container::iterator(__i));
     }
+#endif
 
   // @} group iterators
 
diff --git a/libstdc++-v3/testsuite/24_iterators/back_insert_iterator/constexpr.cc b/libstdc++-v3/testsuite/24_iterators/back_insert_iterator/constexpr.cc
new file mode 100644
index 00000000000..63b7854a0c9
--- /dev/null
+++ b/libstdc++-v3/testsuite/24_iterators/back_insert_iterator/constexpr.cc
@@ -0,0 +1,54 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+
+#include <iterator>
+
+struct container
+{
+  using value_type = int;
+
+  constexpr int* begin() { return std::begin(data); }
+  constexpr int* end() { return next; }
+
+  constexpr void push_back(int val)
+  {
+    if (next == std::end(data))
+      throw val;
+    *next++ = val;
+  }
+
+  int data[3];
+  int* next = std::begin(data);
+};
+
+constexpr bool
+test01()
+{
+  container c;
+  std::back_insert_iterator<container> iter;
+  iter = std::back_inserter(c);
+  *iter++ = 1;
+  int i = 2;
+  *iter = i;
+  *++iter = 3;
+  return c.data[0] == 1 && c.data[1] == 2 && c.data[2] == 3;
+}
+
+static_assert( test01() );
diff --git a/libstdc++-v3/testsuite/24_iterators/front_insert_iterator/constexpr.cc b/libstdc++-v3/testsuite/24_iterators/front_insert_iterator/constexpr.cc
new file mode 100644
index 00000000000..62bddad9f7c
--- /dev/null
+++ b/libstdc++-v3/testsuite/24_iterators/front_insert_iterator/constexpr.cc
@@ -0,0 +1,54 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+
+#include <iterator>
+
+struct container
+{
+  using value_type = int;
+
+  constexpr int* begin() { return next; }
+  constexpr int* end() { return std::end(data); }
+
+  constexpr void push_front(int val)
+  {
+    if (next == std::begin(data))
+      throw val;
+    *--next = val;
+  }
+
+  int data[3];
+  int* next = std::end(data);
+};
+
+constexpr bool
+test01()
+{
+  container c;
+  std::front_insert_iterator<container> iter;
+  iter = std::front_inserter(c);
+  *iter++ = 1;
+  int i = 2;
+  *iter = i;
+  *++iter = 3;
+  return c.data[0] == 3 && c.data[1] == 2 && c.data[2] == 1;
+}
+
+static_assert( test01() );
diff --git a/libstdc++-v3/testsuite/24_iterators/headers/iterator/synopsis_c++17.cc b/libstdc++-v3/testsuite/24_iterators/headers/iterator/synopsis_c++17.cc
index 0cbf5c3ecd9..590f3050efc 100644
--- a/libstdc++-v3/testsuite/24_iterators/headers/iterator/synopsis_c++17.cc
+++ b/libstdc++-v3/testsuite/24_iterators/headers/iterator/synopsis_c++17.cc
@@ -45,6 +45,10 @@ namespace std {
   // C++17 24.5, iterator adaptors:
   template <class Iterator> class reverse_iterator;
 
+#if __cplusplus == 201703L
+  // These operators are constrained in C++20 mode and so don't match
+  // these signatures.
+
   template <class Iterator1, class Iterator2>
   constexpr
   bool operator==(const reverse_iterator<Iterator1>& x,
@@ -74,6 +78,7 @@ namespace std {
   constexpr
   bool operator<=(const reverse_iterator<Iterator1>& x,
 		  const reverse_iterator<Iterator2>& y);
+#endif // C++17
 
   template <class Iterator1, class Iterator2>
   constexpr auto
@@ -92,18 +97,30 @@ namespace std {
   template <class Container> class back_insert_iterator;
 
   template <class Container>
+#if __cplusplus > 201703L
+  constexpr
+#endif
   back_insert_iterator<Container> back_inserter(Container& x);
 
   template <class Container> class front_insert_iterator;
 
   template <class Container>
+#if __cplusplus > 201703L
+  constexpr
+#endif
   front_insert_iterator<Container> front_inserter(Container& x);
 
   template <class Container> class insert_iterator;
 
+#if __cplusplus == 201703L
+  // This function template is defined differently  in C++20 mode and so
+  // doesn't match this signature.
   template <class Container, class Iterator>
   insert_iterator<Container> inserter(Container& x, Iterator i);
 
+  // These operators are constrained in C++20 mode and so don't match
+  // these signatures.
+
   template <class Iterator> class move_iterator;
 
   template <class Iterator1, class Iterator2>
@@ -135,6 +152,7 @@ namespace std {
   constexpr
   bool operator>=(const move_iterator<Iterator1>& x,
 		  const move_iterator<Iterator2>& y);
+#endif // C++17
 
   template <class Iterator1, class Iterator2>
   constexpr
diff --git a/libstdc++-v3/testsuite/24_iterators/insert_iterator/constexpr.cc b/libstdc++-v3/testsuite/24_iterators/insert_iterator/constexpr.cc
new file mode 100644
index 00000000000..b4fc1b5e4e7
--- /dev/null
+++ b/libstdc++-v3/testsuite/24_iterators/insert_iterator/constexpr.cc
@@ -0,0 +1,57 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+
+#include <iterator>
+
+struct container
+{
+  using value_type = int;
+
+  constexpr int* begin() { return std::begin(data); }
+  constexpr int* end() { return last; }
+
+  constexpr int* insert(int* pos, int val)
+  {
+    if (last == std::end(data))
+      throw val;
+    for (int* i = last++; i != pos; --i)
+      i[1] = i[0];
+    *pos = val;
+    return pos;
+  }
+
+  int data[3];
+  int* last = std::begin(data);
+};
+
+constexpr bool
+test01()
+{
+  container c;
+  std::insert_iterator<container> iter;
+  iter = std::inserter(c, c.begin());
+  *iter++ = 1;
+  int i = 2;
+  *iter = i;
+  *++iter = 3;
+  return c.data[0] == 1 && c.data[1] == 2 && c.data[2] == 3;
+}
+
+static_assert( test01() );

^ permalink raw reply	[flat|nested] 5+ messages in thread

* [committed 2/3] libstdc++: Add remaining C++20 changes to iterator adaptors
  2020-03-27 23:28 [committed 1/3] libstdc++: Implement C++20 changes to insert iterators Jonathan Wakely
@ 2020-03-27 23:29 ` Jonathan Wakely
  2020-03-27 23:30   ` [committed 3/3] libstdc++: Define __cpp_lib_ranges macro for C++20 Jonathan Wakely
  2020-03-28  0:16   ` [committed 2/3] libstdc++: Add remaining C++20 changes to iterator adaptors Jonathan Wakely
  0 siblings, 2 replies; 5+ messages in thread
From: Jonathan Wakely @ 2020-03-27 23:29 UTC (permalink / raw)
  To: libstdc++, gcc-patches

[-- Attachment #1: Type: text/plain, Size: 1174 bytes --]

This adds the missing parts of P0896R4 to reverse_iterator and
move_iterator, so that they meet the C++20 requirements. This should be
the last piece of P0896R4, meaning ranges support is now complete.

The PR 94354 bug with reverse_iterator's comparisons is fixed for C++20
only, but that change should be extended to C++11, C++14 and C++17 modes
in stage 1.

	* include/bits/stl_iterator.h (reverse_iterator::iterator_concept)
	(reverse_iterator::iterator_category): Define for C++20.
	(reverse_iterator): Define comparison operators correctly for C++20.
	(__normal_iterator): Add constraints to comparison operators for C++20.
	(move_iterator::operator++(int)) [__cpp_lib_concepts]: Define new
	overload for input iterators.
	(move_iterator): Add constraints to comparison operators for C++20.
	Define operator<=> for C++20.
	* testsuite/24_iterators/move_iterator/input_iterator.cc: New test.
	* testsuite/24_iterators/move_iterator/move_only.cc: New test.
	* testsuite/24_iterators/move_iterator/rel_ops_c++20.cc: New test.
	* testsuite/24_iterators/reverse_iterator/rel_ops_c++20.cc: New test.

Tested powerpc64le-linux, committed to master.



[-- Attachment #2: patch.txt --]
[-- Type: text/x-patch, Size: 24912 bytes --]

commit 81a8d137c22953df2ea046466c62cd26c0dba103
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Fri Mar 27 23:21:58 2020 +0000

    libstdc++: Add remaining C++20 changes to iterator adaptors
    
    This adds the missing parts of P0896R4 to reverse_iterator and
    move_iterator, so that they meet the C++20 requirements. This should be
    the last piece of P0896R4, meaning ranges support is now complete.
    
    The PR 94354 bug with reverse_iterator's comparisons is fixed for C++20
    only, but that change should be extended to C++11, C++14 and C++17 modes
    in stage 1.
    
            * include/bits/stl_iterator.h (reverse_iterator::iterator_concept)
            (reverse_iterator::iterator_category): Define for C++20.
            (reverse_iterator): Define comparison operators correctly for C++20.
            (__normal_iterator): Add constraints to comparison operators for C++20.
            (move_iterator::operator++(int)) [__cpp_lib_concepts]: Define new
            overload for input iterators.
            (move_iterator): Add constraints to comparison operators for C++20.
            Define operator<=> for C++20.
            * testsuite/24_iterators/move_iterator/input_iterator.cc: New test.
            * testsuite/24_iterators/move_iterator/move_only.cc: New test.
            * testsuite/24_iterators/move_iterator/rel_ops_c++20.cc: New test.
            * testsuite/24_iterators/reverse_iterator/rel_ops_c++20.cc: New test.

diff --git a/libstdc++-v3/include/bits/stl_iterator.h b/libstdc++-v3/include/bits/stl_iterator.h
index d10c30cbfcc..26eb599993d 100644
--- a/libstdc++-v3/include/bits/stl_iterator.h
+++ b/libstdc++-v3/include/bits/stl_iterator.h
@@ -88,6 +88,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
    * @{
    */
 
+#if __cplusplus > 201703L && __cpp_lib_concepts
+  namespace __detail
+  {
+    // Weaken iterator_category _Cat to _Limit if it is derived from that,
+    // otherwise use _Otherwise.
+    template<typename _Cat, typename _Limit, typename _Otherwise = _Cat>
+      using __clamp_iter_cat
+	= conditional_t<derived_from<_Cat, _Limit>, _Limit, _Otherwise>;
+  }
+#endif
+
   // 24.4.1 Reverse iterators
   /**
    *  Bidirectional and random access iterators have corresponding reverse
@@ -126,6 +137,16 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       typedef typename __traits_type::pointer		pointer;
       typedef typename __traits_type::reference		reference;
 
+#if __cplusplus > 201703L && __cpp_lib_concepts
+      using iterator_concept
+	= conditional_t<random_access_iterator<_Iterator>,
+			random_access_iterator_tag,
+			bidirectional_iterator_tag>;
+      using iterator_category
+	= __detail::__clamp_iter_cat<typename __traits_type::iterator_category,
+				     random_access_iterator_tag>;
+#endif
+
       /**
        *  The default constructor value-initializes member @p current.
        *  If it is a pointer, that means it is zero-initialized.
@@ -320,16 +341,20 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
         { return __t.operator->(); }
     };
 
+  // Used in unevaluated expressions to test for implicit conversion to bool.
+  namespace __detail { bool __convbool(bool); }
+
   //@{
   /**
    *  @param  __x  A %reverse_iterator.
    *  @param  __y  A %reverse_iterator.
    *  @return  A simple bool.
    *
-   *  Reverse iterators forward many operations to their underlying base()
-   *  iterators.  Others are implemented in terms of one another.
+   *  Reverse iterators forward comparisons to their underlying base()
+   *  iterators.
    *
   */
+#if __cplusplus <= 201703L
   template<typename _Iterator>
     inline _GLIBCXX17_CONSTEXPR bool
     operator==(const reverse_iterator<_Iterator>& __x,
@@ -403,6 +428,49 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     operator>=(const reverse_iterator<_IteratorL>& __x,
 	       const reverse_iterator<_IteratorR>& __y)
     { return !(__x < __y); }
+#else // C++20
+  template<typename _IteratorL, typename _IteratorR>
+    constexpr auto
+    operator==(const reverse_iterator<_IteratorL>& __x,
+	       const reverse_iterator<_IteratorR>& __y)
+    -> decltype(__detail::__convbool(__x.base() == __y.base()))
+    { return __x.base() == __y.base(); }
+
+  template<typename _IteratorL, typename _IteratorR>
+    constexpr auto
+    operator!=(const reverse_iterator<_IteratorL>& __x,
+	       const reverse_iterator<_IteratorR>& __y)
+    -> decltype(__detail::__convbool(__x.base() != __y.base()))
+    { return __x.base() != __y.base(); }
+
+  template<typename _IteratorL, typename _IteratorR>
+    constexpr auto
+    operator<(const reverse_iterator<_IteratorL>& __x,
+	      const reverse_iterator<_IteratorR>& __y)
+    -> decltype(__detail::__convbool(__x.base() < __y.base()))
+    { return __x.base() < __y.base(); }
+
+  template<typename _IteratorL, typename _IteratorR>
+    constexpr auto
+    operator>(const reverse_iterator<_IteratorL>& __x,
+	      const reverse_iterator<_IteratorR>& __y)
+    -> decltype(__detail::__convbool(__x.base() > __y.base()))
+    { return __x.base() > __y.base(); }
+
+  template<typename _IteratorL, typename _IteratorR>
+    constexpr auto
+    operator<=(const reverse_iterator<_IteratorL>& __x,
+	       const reverse_iterator<_IteratorR>& __y)
+    -> decltype(__detail::__convbool(__x.base() <= __y.base()))
+    { return __x.base() <= __y.base(); }
+
+  template<typename _IteratorL, typename _IteratorR>
+    constexpr auto
+    operator>=(const reverse_iterator<_IteratorL>& __x,
+	       const reverse_iterator<_IteratorR>& __y)
+    -> decltype(__detail::__convbool(__x.base() >= __y.base()))
+    { return __x.base() >= __y.base(); }
+#endif // C++20
   //@}
 
 #if __cplusplus < 201103L
@@ -1000,8 +1068,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
   // Random access iterator requirements
   template<typename _IteratorL, typename _IteratorR, typename _Container>
-    _GLIBCXX20_CONSTEXPR
+#if __cplusplus > 201703L
+    constexpr auto
+#else
     inline bool
+#endif
     operator<(const __normal_iterator<_IteratorL, _Container>& __lhs,
 	      const __normal_iterator<_IteratorR, _Container>& __rhs)
     _GLIBCXX_NOEXCEPT
@@ -1016,8 +1087,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     { return __lhs.base() < __rhs.base(); }
 
   template<typename _IteratorL, typename _IteratorR, typename _Container>
-    _GLIBCXX20_CONSTEXPR
+#if __cplusplus > 201703L
+    constexpr auto
+#else
     inline bool
+#endif
     operator>(const __normal_iterator<_IteratorL, _Container>& __lhs,
 	      const __normal_iterator<_IteratorR, _Container>& __rhs)
     _GLIBCXX_NOEXCEPT
@@ -1032,8 +1106,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     { return __lhs.base() > __rhs.base(); }
 
   template<typename _IteratorL, typename _IteratorR, typename _Container>
-    _GLIBCXX20_CONSTEXPR
+#if __cplusplus > 201703L
+    constexpr auto
+#else
     inline bool
+#endif
     operator<=(const __normal_iterator<_IteratorL, _Container>& __lhs,
 	       const __normal_iterator<_IteratorR, _Container>& __rhs)
     _GLIBCXX_NOEXCEPT
@@ -1048,8 +1125,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     { return __lhs.base() <= __rhs.base(); }
 
   template<typename _IteratorL, typename _IteratorR, typename _Container>
-    _GLIBCXX20_CONSTEXPR
+#if __cplusplus > 201703L
+    constexpr auto
+#else
     inline bool
+#endif
     operator>=(const __normal_iterator<_IteratorL, _Container>& __lhs,
 	       const __normal_iterator<_IteratorR, _Container>& __rhs)
     _GLIBCXX_NOEXCEPT
@@ -1157,15 +1237,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     private:
       _Sent _M_last;
     };
-
-  namespace __detail
-  {
-    // Weaken iterator_category _Cat to _Limit if it is derived from that,
-    // otherwise use _Otherwise.
-    template<typename _Cat, typename _Limit, typename _Otherwise = _Cat>
-      using __clamp_iter_cat
-	= conditional_t<derived_from<_Cat, _Limit>, _Limit, _Otherwise>;
-  }
 #endif // C++20
 
   // 24.4.3  Move iterators
@@ -1266,6 +1337,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	return __tmp;
       }
 
+#if __cpp_lib_concepts
+      constexpr void
+      operator++(int) requires (!forward_iterator<_Iterator>)
+      { ++_M_current; }
+#endif
+
       _GLIBCXX17_CONSTEXPR move_iterator&
       operator--()
       {
@@ -1343,6 +1420,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     inline _GLIBCXX17_CONSTEXPR bool
     operator==(const move_iterator<_IteratorL>& __x,
 	       const move_iterator<_IteratorR>& __y)
+#if __cplusplus > 201703L && __cpp_lib_concepts
+    requires requires { __detail::__convbool(__x.base() == __y.base()); }
+#endif
     { return __x.base() == __y.base(); }
 
   template<typename _Iterator>
@@ -1351,6 +1431,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	       const move_iterator<_Iterator>& __y)
     { return __x.base() == __y.base(); }
 
+#if __cpp_lib_three_way_comparison
+  template<typename _IteratorL,
+	   three_way_comparable_with<_IteratorL> _IteratorR>
+    constexpr compare_three_way_result_t<_IteratorL, _IteratorR>
+    operator<=>(const move_iterator<_IteratorL>& __x,
+		const move_iterator<_IteratorR>& __y)
+    { return __x.base() <=> __y.base(); }
+#else
   template<typename _IteratorL, typename _IteratorR>
     inline _GLIBCXX17_CONSTEXPR bool
     operator!=(const move_iterator<_IteratorL>& __x,
@@ -1362,11 +1450,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     operator!=(const move_iterator<_Iterator>& __x,
 	       const move_iterator<_Iterator>& __y)
     { return !(__x == __y); }
+#endif
 
   template<typename _IteratorL, typename _IteratorR>
     inline _GLIBCXX17_CONSTEXPR bool
     operator<(const move_iterator<_IteratorL>& __x,
 	      const move_iterator<_IteratorR>& __y)
+#if __cplusplus > 201703L && __cpp_lib_concepts
+    requires requires { __detail::__convbool(__x.base() < __y.base()); }
+#endif
     { return __x.base() < __y.base(); }
 
   template<typename _Iterator>
@@ -1379,6 +1471,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     inline _GLIBCXX17_CONSTEXPR bool
     operator<=(const move_iterator<_IteratorL>& __x,
 	       const move_iterator<_IteratorR>& __y)
+#if __cplusplus > 201703L && __cpp_lib_concepts
+    requires requires { __detail::__convbool(__y.base() < __x.base()); }
+#endif
     { return !(__y < __x); }
 
   template<typename _Iterator>
@@ -1391,6 +1486,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     inline _GLIBCXX17_CONSTEXPR bool
     operator>(const move_iterator<_IteratorL>& __x,
 	      const move_iterator<_IteratorR>& __y)
+#if __cplusplus > 201703L && __cpp_lib_concepts
+    requires requires { __detail::__convbool(__y.base() < __x.base()); }
+#endif
     { return __y < __x; }
 
   template<typename _Iterator>
@@ -1403,6 +1501,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     inline _GLIBCXX17_CONSTEXPR bool
     operator>=(const move_iterator<_IteratorL>& __x,
 	       const move_iterator<_IteratorR>& __y)
+#if __cplusplus > 201703L && __cpp_lib_concepts
+    requires requires { __detail::__convbool(__x.base() < __y.base()); }
+#endif
     { return !(__x < __y); }
 
   template<typename _Iterator>
diff --git a/libstdc++-v3/testsuite/24_iterators/move_iterator/input_iterator.cc b/libstdc++-v3/testsuite/24_iterators/move_iterator/input_iterator.cc
new file mode 100644
index 00000000000..32cf55ca932
--- /dev/null
+++ b/libstdc++-v3/testsuite/24_iterators/move_iterator/input_iterator.cc
@@ -0,0 +1,42 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do run { target c++2a } }
+
+#include <iterator>
+#include <testsuite_hooks.h>
+#include <testsuite_iterators.h>
+
+void
+test01()
+{
+  int a[2] = { 1, 2 };
+  __gnu_test::test_container<int, __gnu_test::input_iterator_wrapper> c(a);
+  auto miter = std::make_move_iterator(c.begin());
+  VERIFY( *miter == 1 );
+  miter++;
+  VERIFY( *miter == 2 );
+
+  static_assert( std::is_void_v<decltype(miter++)> );
+}
+
+int
+main()
+{
+  test01();
+}
diff --git a/libstdc++-v3/testsuite/24_iterators/move_iterator/move_only.cc b/libstdc++-v3/testsuite/24_iterators/move_iterator/move_only.cc
new file mode 100644
index 00000000000..d64e61e4448
--- /dev/null
+++ b/libstdc++-v3/testsuite/24_iterators/move_iterator/move_only.cc
@@ -0,0 +1,60 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+
+#include <iterator>
+
+struct move_only_iterator
+{
+  move_only_iterator() = default;
+  move_only_iterator(move_only_iterator&&) = default;
+  move_only_iterator& operator=(move_only_iterator&&) = default;
+
+  move_only_iterator& operator++();
+  move_only_iterator operator++(int);
+  int& operator*() const;
+
+  bool operator==(const move_only_iterator&) const;
+};
+
+template<> struct std::iterator_traits<move_only_iterator>
+{
+  using value_type = int;
+  using difference_type = std::ptrdiff_t;
+  using iterator_category = std::input_iterator_tag;
+};
+
+static_assert(std::input_iterator<move_only_iterator>);
+
+template<typename T>
+  concept has_member_base = requires (T t) { std::forward<T>(t).base(); };
+
+static_assert( ! has_member_base<std::move_iterator<move_iterator>&> );
+static_assert( ! has_member_base<const std::move_iterator<move_iterator>&> );
+static_assert( has_member_base<std::move_iterator<move_iterator>> );
+static_assert( ! has_member_base<const std::move_iterator<move_iterator>> );
+
+void
+test01()
+{
+  std::move_iterator<move_only_iterator> m1, m2;
+  m1 = std::make_move_iterator(move_only_iterator{});
+  m2 = std::move(m1);
+  m1.swap(m2);
+}
diff --git a/libstdc++-v3/testsuite/24_iterators/move_iterator/rel_ops_c++20.cc b/libstdc++-v3/testsuite/24_iterators/move_iterator/rel_ops_c++20.cc
new file mode 100644
index 00000000000..8f2d73c520f
--- /dev/null
+++ b/libstdc++-v3/testsuite/24_iterators/move_iterator/rel_ops_c++20.cc
@@ -0,0 +1,134 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+
+#include <iterator>
+
+template<int>
+struct Iter
+{
+  using iterator_category = std::random_access_iterator_tag;
+  using value_type = int;
+  using pointer = int*;
+  using reference = int&;
+  using difference_type = std::ptrdiff_t;
+
+  Iter();
+
+  Iter& operator++();
+  Iter operator++(int);
+  Iter& operator--();
+  Iter operator--(int);
+  int& operator*() const;
+  int* operator->() const;
+
+  int& operator[](difference_type) const;
+
+  Iter& operator+=(difference_type);
+  Iter& operator-=(difference_type);
+
+  template<int N> friend Iter operator+(Iter<N>, difference_type);
+  template<int N> friend Iter operator+(difference_type, Iter<N>);
+  template<int N> friend Iter operator-(Iter<N>, difference_type);
+  template<int N> friend difference_type operator-(Iter<N>, Iter<N>);
+
+  // Define the full set of operators for same-type comparisons
+  template<int N> friend bool operator==(Iter<N>, Iter<N>); // synthesizes !=
+  template<int N> friend bool operator<(Iter<N>, Iter<N>);
+  template<int N> friend bool operator>(Iter<N>, Iter<N>);
+  template<int N> friend bool operator<=(Iter<N>, Iter<N>);
+  template<int N> friend bool operator>=(Iter<N>, Iter<N>);
+};
+
+
+static_assert( std::random_access_iterator<Iter<0>> );
+
+int   operator==(Iter<0>, long*);
+void* operator< (Iter<1>, long*);
+bool& operator< (long*, Iter<2>);
+
+using std::move_iterator;
+
+static_assert( std::three_way_comparable<move_iterator<Iter<0>>> );
+
+move_iterator<Iter<0>> l0{Iter<0>()};
+move_iterator<Iter<1>> l1{Iter<1>()};
+move_iterator<Iter<2>> l2{Iter<2>()};
+move_iterator<long*> r{nullptr};
+
+bool b0 = l0 == r;
+bool b1 = l0 != r;
+bool b2 = l1 < r;
+bool b3 = l2 > r;
+bool b4 = l2 <= r;
+bool b5 = l1 >= r;
+
+template<int N>
+  concept has_eq
+    = requires (move_iterator<Iter<N>> l, move_iterator<long*> r)
+      { l == r; };
+
+template<int N>
+  concept has_ne
+    = requires (move_iterator<Iter<N>> l, move_iterator<long*> r)
+      { l != r; };
+
+template<int N>
+  concept has_lt
+    = requires (move_iterator<Iter<N>> l, move_iterator<long*> r)
+      { l < r; };
+
+template<int N>
+  concept has_gt
+    = requires (move_iterator<Iter<N>> l, move_iterator<long*> r)
+      { l > r; };
+
+template<int N>
+  concept has_le
+    = requires (move_iterator<Iter<N>> l, move_iterator<long*> r)
+      { l <= r; };
+
+template<int N>
+  concept has_ge
+    = requires (move_iterator<Iter<N>> l, move_iterator<long*> r)
+      { l >= r; };
+
+static_assert( has_eq<0> );
+static_assert( ! has_eq<1> );
+static_assert( ! has_eq<2> );
+
+static_assert( has_ne<0> ); // uses synthesized operator!=
+static_assert( ! has_ne<1> );
+static_assert( ! has_ne<2> );
+
+static_assert( ! has_lt<0> );
+static_assert( has_lt<1> );
+static_assert( ! has_lt<2> );
+
+static_assert( ! has_gt<0> );
+static_assert( ! has_gt<1> );
+static_assert( has_gt<2> );
+
+static_assert( ! has_le<0> );
+static_assert( ! has_le<1> );
+static_assert( has_le<2> );
+
+static_assert( ! has_ge<0> );
+static_assert( has_ge<1> );
+static_assert( ! has_ge<2> );
diff --git a/libstdc++-v3/testsuite/24_iterators/reverse_iterator/rel_ops_c++20.cc b/libstdc++-v3/testsuite/24_iterators/reverse_iterator/rel_ops_c++20.cc
new file mode 100644
index 00000000000..3e91a0396fe
--- /dev/null
+++ b/libstdc++-v3/testsuite/24_iterators/reverse_iterator/rel_ops_c++20.cc
@@ -0,0 +1,156 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+
+#include <iterator>
+
+template<int>
+struct Iter
+{
+  using iterator_category = std::random_access_iterator_tag;
+  using value_type = int;
+  using pointer = int*;
+  using reference = int&;
+  using difference_type = std::ptrdiff_t;
+
+  Iter();
+
+  Iter& operator++();
+  Iter operator++(int);
+  Iter& operator--();
+  Iter operator--(int);
+  int& operator*() const;
+  int* operator->() const;
+
+  int& operator[](difference_type) const;
+
+  Iter& operator+=(difference_type);
+  Iter& operator-=(difference_type);
+
+  template<int N> friend Iter operator+(Iter<N>, difference_type);
+  template<int N> friend Iter operator+(difference_type, Iter<N>);
+  template<int N> friend Iter operator-(Iter<N>, difference_type);
+  template<int N> friend difference_type operator-(Iter<N>, Iter<N>);
+
+  // Define the full set of operators for same-type comparisons
+  template<int N> friend bool operator==(Iter<N>, Iter<N>); // synthesizes !=
+  template<int N> friend bool operator<(Iter<N>, Iter<N>);
+  template<int N> friend bool operator>(Iter<N>, Iter<N>);
+  template<int N> friend bool operator<=(Iter<N>, Iter<N>);
+  template<int N> friend bool operator>=(Iter<N>, Iter<N>);
+};
+
+static_assert( std::random_access_iterator<Iter<0>> );
+
+// Define a single kind of mixed-type comparison for each specialization.
+int   operator==(Iter<0>, long*);
+void* operator!=(Iter<1>, long*);
+bool& operator< (Iter<2>, long*);
+int   operator> (Iter<3>, long*);
+void* operator<=(Iter<4>, long*);
+bool& operator>=(Iter<5>, long*);
+
+using std::reverse_iterator;
+
+reverse_iterator<Iter<0>> l0{Iter<0>()};
+reverse_iterator<Iter<1>> l1{Iter<1>()};
+reverse_iterator<Iter<2>> l2{Iter<2>()};
+reverse_iterator<Iter<3>> l3{Iter<3>()};
+reverse_iterator<Iter<4>> l4{Iter<4>()};
+reverse_iterator<Iter<5>> l5{Iter<5>()};
+reverse_iterator<long*> r{nullptr};
+
+bool b0 = l0 == r;
+bool b1 = l1 != r;
+bool b2 = l2 < r;
+bool b3 = l3 > r;
+bool b4 = l4 <= r;
+bool b5 = l5 >= r;
+
+template<int N>
+  concept has_eq
+    = requires (reverse_iterator<Iter<N>> l, reverse_iterator<long*> r)
+      { l == r; };
+
+template<int N>
+  concept has_ne
+    = requires (reverse_iterator<Iter<N>> l, reverse_iterator<long*> r)
+      { l != r; };
+
+template<int N>
+  concept has_lt
+    = requires (reverse_iterator<Iter<N>> l, reverse_iterator<long*> r)
+      { l < r; };
+
+template<int N>
+  concept has_gt
+    = requires (reverse_iterator<Iter<N>> l, reverse_iterator<long*> r)
+      { l > r; };
+
+template<int N>
+  concept has_le
+    = requires (reverse_iterator<Iter<N>> l, reverse_iterator<long*> r)
+      { l <= r; };
+
+template<int N>
+  concept has_ge
+    = requires (reverse_iterator<Iter<N>> l, reverse_iterator<long*> r)
+      { l >= r; };
+
+static_assert( has_eq<0> );
+static_assert( ! has_eq<1> );
+static_assert( ! has_eq<2> );
+static_assert( ! has_eq<3> );
+static_assert( ! has_eq<4> );
+static_assert( ! has_eq<5> );
+
+static_assert( has_ne<0> ); // uses synthesized operator!=
+static_assert( has_ne<1> );
+static_assert( ! has_ne<2> );
+static_assert( ! has_ne<3> );
+static_assert( ! has_ne<4> );
+static_assert( ! has_ne<5> );
+
+static_assert( ! has_lt<0> );
+static_assert( ! has_lt<1> );
+static_assert( has_lt<2> );
+static_assert( ! has_lt<3> );
+static_assert( ! has_lt<4> );
+static_assert( ! has_lt<5> );
+
+static_assert( ! has_gt<0> );
+static_assert( ! has_gt<1> );
+static_assert( ! has_gt<2> );
+static_assert( has_gt<3> );
+static_assert( ! has_gt<4> );
+static_assert( ! has_gt<5> );
+
+static_assert( ! has_le<0> );
+static_assert( ! has_le<1> );
+static_assert( ! has_le<2> );
+static_assert( ! has_le<3> );
+static_assert( has_le<4> );
+static_assert( ! has_le<5> );
+
+static_assert( ! has_ge<0> );
+static_assert( ! has_ge<1> );
+static_assert( ! has_ge<2> );
+static_assert( ! has_ge<3> );
+static_assert( ! has_ge<4> );
+static_assert( has_ge<5> );

^ permalink raw reply	[flat|nested] 5+ messages in thread

* [committed 3/3] libstdc++: Define __cpp_lib_ranges macro for C++20
  2020-03-27 23:29 ` [committed 2/3] libstdc++: Add remaining C++20 changes to iterator adaptors Jonathan Wakely
@ 2020-03-27 23:30   ` Jonathan Wakely
  2020-03-28  0:16   ` [committed 2/3] libstdc++: Add remaining C++20 changes to iterator adaptors Jonathan Wakely
  1 sibling, 0 replies; 5+ messages in thread
From: Jonathan Wakely @ 2020-03-27 23:30 UTC (permalink / raw)
  To: libstdc++, gcc-patches

[-- Attachment #1: Type: text/plain, Size: 810 bytes --]

Define the feature test macro now that ranges support is complete.

This also changes the preprocessor checks for the __cpp_concepts macro
so that library components depending on concepts are only enabled when
C++20 concepts are supported, and not just for the Concepts TS (which
uses different syntax in places).
     
         * include/bits/range_cmp.h (__cpp_lib_ranges): Define.
         * include/bits/stl_iterator.h: Check value of __cpp_concepts so that
         C++20 concepts are required.
         * include/bits/stl_iterator_base_types.h: Likewise.
         * include/std/concepts: Likewise.
         * include/std/version: Likewise.
         * testsuite/std/ranges/headers/ranges/synopsis.cc: Check feature test
         macro.


Tested powerpc64le-linux, committed to master.


[-- Attachment #2: patch.txt --]
[-- Type: text/x-patch, Size: 7941 bytes --]

commit b8a28a06eafafae47ee92fe640b334a8d1e4758a
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Fri Mar 27 23:21:58 2020 +0000

    libstdc++: Define __cpp_lib_ranges macro for C++20
    
    Define the feature test macro now that ranges support is complete.
    
    This also changes the preprocessor checks for the __cpp_concepts macro
    so that library components depending on concepts are only enabled when
    C++20 concepts are supported, and not just for the Concepts TS (which
    uses different syntax in places).
    
            * include/bits/range_cmp.h (__cpp_lib_ranges): Define.
            * include/bits/stl_iterator.h: Check value of __cpp_concepts so that
            C++20 concepts are required.
            * include/bits/stl_iterator_base_types.h: Likewise.
            * include/std/concepts: Likewise.
            * include/std/version: Likewise.
            * testsuite/std/ranges/headers/ranges/synopsis.cc: Check feature test
            macro.

diff --git a/libstdc++-v3/include/bits/range_cmp.h b/libstdc++-v3/include/bits/range_cmp.h
index 571ba7f9555..0587c599c4b 100644
--- a/libstdc++-v3/include/bits/range_cmp.h
+++ b/libstdc++-v3/include/bits/range_cmp.h
@@ -55,6 +55,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   };
 
 #ifdef __cpp_lib_concepts
+// Define this here, included by all the headers that need to define it.
+#define __cpp_lib_ranges 201911L
+
 namespace ranges
 {
   namespace __detail
diff --git a/libstdc++-v3/include/bits/stl_iterator.h b/libstdc++-v3/include/bits/stl_iterator.h
index 26eb599993d..e68f66a2b89 100644
--- a/libstdc++-v3/include/bits/stl_iterator.h
+++ b/libstdc++-v3/include/bits/stl_iterator.h
@@ -214,7 +214,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       */
       _GLIBCXX17_CONSTEXPR pointer
       operator->() const
-#if __cplusplus > 201703L && defined __cpp_concepts
+#if __cplusplus > 201703L && __cpp_concepts >= 201907L
       requires is_pointer_v<_Iterator>
 	|| requires(const _Iterator __i) { __i.operator->(); }
 #endif
diff --git a/libstdc++-v3/include/bits/stl_iterator_base_types.h b/libstdc++-v3/include/bits/stl_iterator_base_types.h
index 431bf8a62d6..aa02af59dc6 100644
--- a/libstdc++-v3/include/bits/stl_iterator_base_types.h
+++ b/libstdc++-v3/include/bits/stl_iterator_base_types.h
@@ -67,7 +67,7 @@
 # include <type_traits>  // For __void_t, is_convertible
 #endif
 
-#if __cplusplus > 201703L && __cpp_concepts
+#if __cplusplus > 201703L && __cpp_concepts >= 201907L
 # include <bits/iterator_concepts.h>
 #endif
 
@@ -192,7 +192,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #if __cplusplus > 201703L
   /// Partial specialization for object pointer types.
   template<typename _Tp>
-#if __cpp_concepts
+#if __cpp_concepts >= 201907L
     requires is_object_v<_Tp>
 #endif
     struct iterator_traits<_Tp*>
diff --git a/libstdc++-v3/include/std/concepts b/libstdc++-v3/include/std/concepts
index ba232e953ec..e8ce1adc93a 100644
--- a/libstdc++-v3/include/std/concepts
+++ b/libstdc++-v3/include/std/concepts
@@ -30,7 +30,7 @@
 #ifndef _GLIBCXX_CONCEPTS
 #define _GLIBCXX_CONCEPTS 1
 
-#if __cplusplus > 201703L && __cpp_concepts
+#if __cplusplus > 201703L && __cpp_concepts >= 201907L
 
 #pragma GCC system_header
 
diff --git a/libstdc++-v3/include/std/version b/libstdc++-v3/include/std/version
index c6a202e250d..d9a47ee8e8a 100644
--- a/libstdc++-v3/include/std/version
+++ b/libstdc++-v3/include/std/version
@@ -146,6 +146,7 @@
 #define __cpp_lib_nonmember_container_access 201411
 #define __cpp_lib_not_fn 201603
 #define __cpp_lib_optional 201606L
+#define __cpp_lib_parallel_algorithm 201603L
 #define __cpp_lib_raw_memory_algorithms 201606L
 #define __cpp_lib_sample 201603
 #ifdef _GLIBCXX_HAS_GTHREADS
@@ -158,7 +159,6 @@
 #define __cpp_lib_unordered_map_insertion 201411
 #define __cpp_lib_unordered_map_try_emplace 201411
 #define __cpp_lib_variant 201606L
-#define __cpp_lib_parallel_algorithm 201603L
 #endif
 
 #if __cplusplus > 201703L
@@ -167,7 +167,7 @@
 #define __cpp_lib_atomic_value_initialization 201911L
 #define __cpp_lib_bitops 201907L
 #define __cpp_lib_bounded_array_traits 201902L
-#if __cpp_concepts
+#if __cpp_concepts >= 201907L
 # define __cpp_lib_concepts 201806L
 #endif
 #if __cpp_impl_destroying_delete
@@ -195,6 +195,9 @@
 #endif
 #define __cpp_lib_list_remove_return_type 201806L
 #define __cpp_lib_math_constants 201907L
+#if __cpp_lib_concepts
+# define __cpp_lib_ranges 201911L
+#endif
 #define __cpp_lib_span 202002L
 #if __cpp_impl_three_way_comparison >= 201907L && __cpp_lib_concepts
 # define __cpp_lib_three_way_comparison 201711L
diff --git a/libstdc++-v3/testsuite/24_iterators/move_iterator/move_only.cc b/libstdc++-v3/testsuite/24_iterators/move_iterator/move_only.cc
index d64e61e4448..eaf307ddf60 100644
--- a/libstdc++-v3/testsuite/24_iterators/move_iterator/move_only.cc
+++ b/libstdc++-v3/testsuite/24_iterators/move_iterator/move_only.cc
@@ -45,16 +45,17 @@ static_assert(std::input_iterator<move_only_iterator>);
 template<typename T>
   concept has_member_base = requires (T t) { std::forward<T>(t).base(); };
 
-static_assert( ! has_member_base<std::move_iterator<move_iterator>&> );
-static_assert( ! has_member_base<const std::move_iterator<move_iterator>&> );
-static_assert( has_member_base<std::move_iterator<move_iterator>> );
-static_assert( ! has_member_base<const std::move_iterator<move_iterator>> );
+using move_only_move_iterator = std::move_iterator<move_only_iterator>;
+
+static_assert( ! has_member_base<move_only_move_iterator&> );
+static_assert( ! has_member_base<const move_only_move_iterator&> );
+static_assert( has_member_base<move_only_move_iterator> );
+static_assert( ! has_member_base<const move_only_move_iterator> );
 
 void
 test01()
 {
-  std::move_iterator<move_only_iterator> m1, m2;
-  m1 = std::make_move_iterator(move_only_iterator{});
+  move_only_move_iterator m1 = std::make_move_iterator(move_only_iterator{});
+  move_only_move_iterator m2;
   m2 = std::move(m1);
-  m1.swap(m2);
 }
diff --git a/libstdc++-v3/testsuite/24_iterators/move_iterator/rel_ops_c++20.cc b/libstdc++-v3/testsuite/24_iterators/move_iterator/rel_ops_c++20.cc
index 8f2d73c520f..4e7b9d01e15 100644
--- a/libstdc++-v3/testsuite/24_iterators/move_iterator/rel_ops_c++20.cc
+++ b/libstdc++-v3/testsuite/24_iterators/move_iterator/rel_ops_c++20.cc
@@ -48,15 +48,10 @@ struct Iter
   template<int N> friend Iter operator-(Iter<N>, difference_type);
   template<int N> friend difference_type operator-(Iter<N>, Iter<N>);
 
-  // Define the full set of operators for same-type comparisons
-  template<int N> friend bool operator==(Iter<N>, Iter<N>); // synthesizes !=
-  template<int N> friend bool operator<(Iter<N>, Iter<N>);
-  template<int N> friend bool operator>(Iter<N>, Iter<N>);
-  template<int N> friend bool operator<=(Iter<N>, Iter<N>);
-  template<int N> friend bool operator>=(Iter<N>, Iter<N>);
+  template<int N> friend bool operator==(Iter<N>, Iter<N>);
+  template<int N> friend std::weak_ordering operator<=>(Iter<N>, Iter<N>);
 };
 
-
 static_assert( std::random_access_iterator<Iter<0>> );
 
 int   operator==(Iter<0>, long*);
diff --git a/libstdc++-v3/testsuite/std/ranges/headers/ranges/synopsis.cc b/libstdc++-v3/testsuite/std/ranges/headers/ranges/synopsis.cc
index 10ccb35c9e1..dd24730398f 100644
--- a/libstdc++-v3/testsuite/std/ranges/headers/ranges/synopsis.cc
+++ b/libstdc++-v3/testsuite/std/ranges/headers/ranges/synopsis.cc
@@ -20,6 +20,12 @@
 
 #include <ranges>
 
+#ifndef __cpp_lib_ranges
+# error "Feature test macro for ranges is missing in <ranges>"
+#elif __cpp_lib_ranges < 201911L
+# error "Feature test macro for ranges has wrong value in <ranges>"
+#endif
+
 struct R { };
 template<> constexpr bool std::ranges::disable_sized_range<R> = true;
 

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [committed 2/3] libstdc++: Add remaining C++20 changes to iterator adaptors
  2020-03-27 23:29 ` [committed 2/3] libstdc++: Add remaining C++20 changes to iterator adaptors Jonathan Wakely
  2020-03-27 23:30   ` [committed 3/3] libstdc++: Define __cpp_lib_ranges macro for C++20 Jonathan Wakely
@ 2020-03-28  0:16   ` Jonathan Wakely
  2020-03-28 22:22     ` Jonathan Wakely
  1 sibling, 1 reply; 5+ messages in thread
From: Jonathan Wakely @ 2020-03-28  0:16 UTC (permalink / raw)
  To: libstdc++, gcc-patches

On 27/03/20 23:29 +0000, Jonathan Wakely wrote:
>@@ -403,6 +428,49 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>     operator>=(const reverse_iterator<_IteratorL>& __x,
> 	       const reverse_iterator<_IteratorR>& __y)
>     { return !(__x < __y); }
>+#else // C++20
>+  template<typename _IteratorL, typename _IteratorR>
>+    constexpr auto
>+    operator==(const reverse_iterator<_IteratorL>& __x,
>+	       const reverse_iterator<_IteratorR>& __y)
>+    -> decltype(__detail::__convbool(__x.base() == __y.base()))
>+    { return __x.base() == __y.base(); }
>+
>+  template<typename _IteratorL, typename _IteratorR>
>+    constexpr auto
>+    operator!=(const reverse_iterator<_IteratorL>& __x,
>+	       const reverse_iterator<_IteratorR>& __y)
>+    -> decltype(__detail::__convbool(__x.base() != __y.base()))
>+    { return __x.base() != __y.base(); }
>+
>+  template<typename _IteratorL, typename _IteratorR>
>+    constexpr auto
>+    operator<(const reverse_iterator<_IteratorL>& __x,
>+	      const reverse_iterator<_IteratorR>& __y)
>+    -> decltype(__detail::__convbool(__x.base() < __y.base()))
>+    { return __x.base() < __y.base(); }

Drat, these relational operators use the wrong operator. The sense
needs to be flipped because they're reverse_iterators.

Looks like I lost an edit to this file that I made on another machine,
and committed the wrong version. I'll fix it ASAP.

>+  template<typename _IteratorL, typename _IteratorR>
>+    constexpr auto
>+    operator>(const reverse_iterator<_IteratorL>& __x,
>+	      const reverse_iterator<_IteratorR>& __y)
>+    -> decltype(__detail::__convbool(__x.base() > __y.base()))
>+    { return __x.base() > __y.base(); }
>+
>+  template<typename _IteratorL, typename _IteratorR>
>+    constexpr auto
>+    operator<=(const reverse_iterator<_IteratorL>& __x,
>+	       const reverse_iterator<_IteratorR>& __y)
>+    -> decltype(__detail::__convbool(__x.base() <= __y.base()))
>+    { return __x.base() <= __y.base(); }
>+
>+  template<typename _IteratorL, typename _IteratorR>
>+    constexpr auto
>+    operator>=(const reverse_iterator<_IteratorL>& __x,
>+	       const reverse_iterator<_IteratorR>& __y)
>+    -> decltype(__detail::__convbool(__x.base() >= __y.base()))
>+    { return __x.base() >= __y.base(); }
>+#endif // C++20
>   //@}
> 
> #if __cplusplus < 201103L


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [committed 2/3] libstdc++: Add remaining C++20 changes to iterator adaptors
  2020-03-28  0:16   ` [committed 2/3] libstdc++: Add remaining C++20 changes to iterator adaptors Jonathan Wakely
@ 2020-03-28 22:22     ` Jonathan Wakely
  0 siblings, 0 replies; 5+ messages in thread
From: Jonathan Wakely @ 2020-03-28 22:22 UTC (permalink / raw)
  To: libstdc++, gcc-patches

[-- Attachment #1: Type: text/plain, Size: 1570 bytes --]

On 28/03/20 00:16 +0000, Jonathan Wakely wrote:
>On 27/03/20 23:29 +0000, Jonathan Wakely wrote:
>>@@ -403,6 +428,49 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>>    operator>=(const reverse_iterator<_IteratorL>& __x,
>>	       const reverse_iterator<_IteratorR>& __y)
>>    { return !(__x < __y); }
>>+#else // C++20
>>+  template<typename _IteratorL, typename _IteratorR>
>>+    constexpr auto
>>+    operator==(const reverse_iterator<_IteratorL>& __x,
>>+	       const reverse_iterator<_IteratorR>& __y)
>>+    -> decltype(__detail::__convbool(__x.base() == __y.base()))
>>+    { return __x.base() == __y.base(); }
>>+
>>+  template<typename _IteratorL, typename _IteratorR>
>>+    constexpr auto
>>+    operator!=(const reverse_iterator<_IteratorL>& __x,
>>+	       const reverse_iterator<_IteratorR>& __y)
>>+    -> decltype(__detail::__convbool(__x.base() != __y.base()))
>>+    { return __x.base() != __y.base(); }
>>+
>>+  template<typename _IteratorL, typename _IteratorR>
>>+    constexpr auto
>>+    operator<(const reverse_iterator<_IteratorL>& __x,
>>+	      const reverse_iterator<_IteratorR>& __y)
>>+    -> decltype(__detail::__convbool(__x.base() < __y.base()))
>>+    { return __x.base() < __y.base(); }
>
>Drat, these relational operators use the wrong operator. The sense
>needs to be flipped because they're reverse_iterators.
>
>Looks like I lost an edit to this file that I made on another machine,
>and committed the wrong version. I'll fix it ASAP.

Here's the fix. Tested powerpc64le-linux, committed to master.



[-- Attachment #2: patch.txt --]
[-- Type: text/x-patch, Size: 16814 bytes --]

commit 42cda3ba45fca30e73e1c35d8e19b5ec8af24d98
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Sat Mar 28 21:52:13 2020 +0000

    libstdc++: Fix std::reverse_iterator relational operators
    
    My recent changes to reverse_iterator's comparisons was not the version
    of the code (or tests) that I meant to commit, and broke the relational
    operators. This fixes them to reverse the order of the comparisons on
    the base() iterators.
    
    This also replaces the SFINAE constraints in the return type of the
    reverse_iterator and move_iterator comparisons with a requires-clause.
    This ensures the constrained overloads are preferred to unconstrained
    ones. This means the non-standard same-type overloads can be omitted for
    C++20 because they're not needed to solve the problem with std::rel_ops
    or the testsuite's greedy_ops::X type.
    
            * include/bits/stl_iterator.h (reverse_iterator): Use requires-clause
            to constrain C++20 versions of comparison operators. Fix backwards
            logic of relational operators.
            (move_iterator): Use requires-clause to constrain comparison operators
            in C++20. Do not declare non-standard same-type overloads for C++20.
            * testsuite/24_iterators/move_iterator/rel_ops_c++20.cc: Check result
            of comparisons and check using greedy_ops type.
            * testsuite/24_iterators/reverse_iterator/rel_ops_c++20.cc: Likewise.
            * testsuite/24_iterators/move_iterator/greedy_ops.cc: Remove redundant
            main function from compile-only test.
            * testsuite/24_iterators/reverse_iterator/greedy_ops.cc: Likewise.

diff --git a/libstdc++-v3/include/bits/stl_iterator.h b/libstdc++-v3/include/bits/stl_iterator.h
index e68f66a2b89..d7972b71998 100644
--- a/libstdc++-v3/include/bits/stl_iterator.h
+++ b/libstdc++-v3/include/bits/stl_iterator.h
@@ -341,9 +341,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
         { return __t.operator->(); }
     };
 
-  // Used in unevaluated expressions to test for implicit conversion to bool.
-  namespace __detail { bool __convbool(bool); }
-
   //@{
   /**
    *  @param  __x  A %reverse_iterator.
@@ -354,7 +351,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
    *  iterators.
    *
   */
-#if __cplusplus <= 201703L
+#if __cplusplus <= 201703L || ! defined __cpp_lib_concepts
   template<typename _Iterator>
     inline _GLIBCXX17_CONSTEXPR bool
     operator==(const reverse_iterator<_Iterator>& __x,
@@ -430,46 +427,53 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     { return !(__x < __y); }
 #else // C++20
   template<typename _IteratorL, typename _IteratorR>
-    constexpr auto
+    constexpr bool
     operator==(const reverse_iterator<_IteratorL>& __x,
 	       const reverse_iterator<_IteratorR>& __y)
-    -> decltype(__detail::__convbool(__x.base() == __y.base()))
+    requires requires { { __x.base() == __y.base() } -> convertible_to<bool>; }
     { return __x.base() == __y.base(); }
 
   template<typename _IteratorL, typename _IteratorR>
-    constexpr auto
+    constexpr bool
     operator!=(const reverse_iterator<_IteratorL>& __x,
 	       const reverse_iterator<_IteratorR>& __y)
-    -> decltype(__detail::__convbool(__x.base() != __y.base()))
+    requires requires { { __x.base() != __y.base() } -> convertible_to<bool>; }
     { return __x.base() != __y.base(); }
 
   template<typename _IteratorL, typename _IteratorR>
-    constexpr auto
+    constexpr bool
     operator<(const reverse_iterator<_IteratorL>& __x,
 	      const reverse_iterator<_IteratorR>& __y)
-    -> decltype(__detail::__convbool(__x.base() < __y.base()))
-    { return __x.base() < __y.base(); }
-
-  template<typename _IteratorL, typename _IteratorR>
-    constexpr auto
-    operator>(const reverse_iterator<_IteratorL>& __x,
-	      const reverse_iterator<_IteratorR>& __y)
-    -> decltype(__detail::__convbool(__x.base() > __y.base()))
+    requires requires { { __x.base() > __y.base() } -> convertible_to<bool>; }
     { return __x.base() > __y.base(); }
 
   template<typename _IteratorL, typename _IteratorR>
-    constexpr auto
-    operator<=(const reverse_iterator<_IteratorL>& __x,
-	       const reverse_iterator<_IteratorR>& __y)
-    -> decltype(__detail::__convbool(__x.base() <= __y.base()))
-    { return __x.base() <= __y.base(); }
+    constexpr bool
+    operator>(const reverse_iterator<_IteratorL>& __x,
+	      const reverse_iterator<_IteratorR>& __y)
+    requires requires { { __x.base() < __y.base() } -> convertible_to<bool>; }
+    { return __x.base() < __y.base(); }
 
   template<typename _IteratorL, typename _IteratorR>
-    constexpr auto
+    constexpr bool
+    operator<=(const reverse_iterator<_IteratorL>& __x,
+	       const reverse_iterator<_IteratorR>& __y)
+    requires requires { { __x.base() >= __y.base() } -> convertible_to<bool>; }
+    { return __x.base() >= __y.base(); }
+
+  template<typename _IteratorL, typename _IteratorR>
+    constexpr bool
     operator>=(const reverse_iterator<_IteratorL>& __x,
 	       const reverse_iterator<_IteratorR>& __y)
-    -> decltype(__detail::__convbool(__x.base() >= __y.base()))
-    { return __x.base() >= __y.base(); }
+    requires requires { { __x.base() <= __y.base() } -> convertible_to<bool>; }
+    { return __x.base() <= __y.base(); }
+
+  template<typename _IteratorL,
+	   three_way_comparable_with<_IteratorL> _IteratorR>
+    constexpr compare_three_way_result_t<_IteratorL, _IteratorR>
+    operator<=>(const reverse_iterator<_IteratorL>& __x,
+		const reverse_iterator<_IteratorR>& __y)
+    { return __y.base() <=> __x.base(); }
 #endif // C++20
   //@}
 
@@ -1413,24 +1417,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #endif // C++20
     };
 
-  // Note: See __normal_iterator operators note from Gaby to understand
-  // why there are always 2 versions for most of the move_iterator
-  // operators.
   template<typename _IteratorL, typename _IteratorR>
     inline _GLIBCXX17_CONSTEXPR bool
     operator==(const move_iterator<_IteratorL>& __x,
 	       const move_iterator<_IteratorR>& __y)
 #if __cplusplus > 201703L && __cpp_lib_concepts
-    requires requires { __detail::__convbool(__x.base() == __y.base()); }
+    requires requires { { __x.base() == __y.base() } -> convertible_to<bool>; }
 #endif
     { return __x.base() == __y.base(); }
 
-  template<typename _Iterator>
-    inline _GLIBCXX17_CONSTEXPR bool
-    operator==(const move_iterator<_Iterator>& __x,
-	       const move_iterator<_Iterator>& __y)
-    { return __x.base() == __y.base(); }
-
 #if __cpp_lib_three_way_comparison
   template<typename _IteratorL,
 	   three_way_comparable_with<_IteratorL> _IteratorR>
@@ -1444,12 +1439,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     operator!=(const move_iterator<_IteratorL>& __x,
 	       const move_iterator<_IteratorR>& __y)
     { return !(__x == __y); }
-
-  template<typename _Iterator>
-    inline _GLIBCXX17_CONSTEXPR bool
-    operator!=(const move_iterator<_Iterator>& __x,
-	       const move_iterator<_Iterator>& __y)
-    { return !(__x == __y); }
 #endif
 
   template<typename _IteratorL, typename _IteratorR>
@@ -1457,60 +1446,81 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     operator<(const move_iterator<_IteratorL>& __x,
 	      const move_iterator<_IteratorR>& __y)
 #if __cplusplus > 201703L && __cpp_lib_concepts
-    requires requires { __detail::__convbool(__x.base() < __y.base()); }
+    requires requires { { __x.base() < __y.base() } -> convertible_to<bool>; }
 #endif
     { return __x.base() < __y.base(); }
 
-  template<typename _Iterator>
-    inline _GLIBCXX17_CONSTEXPR bool
-    operator<(const move_iterator<_Iterator>& __x,
-	      const move_iterator<_Iterator>& __y)
-    { return __x.base() < __y.base(); }
-
   template<typename _IteratorL, typename _IteratorR>
     inline _GLIBCXX17_CONSTEXPR bool
     operator<=(const move_iterator<_IteratorL>& __x,
 	       const move_iterator<_IteratorR>& __y)
 #if __cplusplus > 201703L && __cpp_lib_concepts
-    requires requires { __detail::__convbool(__y.base() < __x.base()); }
+    requires requires { { __y.base() < __x.base() } -> convertible_to<bool>; }
 #endif
     { return !(__y < __x); }
 
-  template<typename _Iterator>
-    inline _GLIBCXX17_CONSTEXPR bool
-    operator<=(const move_iterator<_Iterator>& __x,
-	       const move_iterator<_Iterator>& __y)
-    { return !(__y < __x); }
-
   template<typename _IteratorL, typename _IteratorR>
     inline _GLIBCXX17_CONSTEXPR bool
     operator>(const move_iterator<_IteratorL>& __x,
 	      const move_iterator<_IteratorR>& __y)
 #if __cplusplus > 201703L && __cpp_lib_concepts
-    requires requires { __detail::__convbool(__y.base() < __x.base()); }
+    requires requires { { __y.base() < __x.base() } -> convertible_to<bool>; }
 #endif
     { return __y < __x; }
 
-  template<typename _Iterator>
-    inline _GLIBCXX17_CONSTEXPR bool
-    operator>(const move_iterator<_Iterator>& __x,
-	      const move_iterator<_Iterator>& __y)
-    { return __y < __x; }
-
   template<typename _IteratorL, typename _IteratorR>
     inline _GLIBCXX17_CONSTEXPR bool
     operator>=(const move_iterator<_IteratorL>& __x,
 	       const move_iterator<_IteratorR>& __y)
 #if __cplusplus > 201703L && __cpp_lib_concepts
-    requires requires { __detail::__convbool(__x.base() < __y.base()); }
+    requires requires { { __x.base() < __y.base() } -> convertible_to<bool>; }
 #endif
     { return !(__x < __y); }
 
+#if ! (__cplusplus > 201703L && __cpp_lib_concepts)
+  // Note: See __normal_iterator operators note from Gaby to understand
+  // why we have these extra overloads for some move_iterator operators.
+
+  // These extra overloads are not needed in C++20, because the ones above
+  // are constrained with a requires-clause and so overload resolution will
+  // prefer them to greedy unconstrained function templates.
+
+  template<typename _Iterator>
+    inline _GLIBCXX17_CONSTEXPR bool
+    operator==(const move_iterator<_Iterator>& __x,
+	       const move_iterator<_Iterator>& __y)
+    { return __x.base() == __y.base(); }
+
+  template<typename _Iterator>
+    inline _GLIBCXX17_CONSTEXPR bool
+    operator!=(const move_iterator<_Iterator>& __x,
+	       const move_iterator<_Iterator>& __y)
+    { return !(__x == __y); }
+
+  template<typename _Iterator>
+    inline _GLIBCXX17_CONSTEXPR bool
+    operator<(const move_iterator<_Iterator>& __x,
+	      const move_iterator<_Iterator>& __y)
+    { return __x.base() < __y.base(); }
+
+  template<typename _Iterator>
+    inline _GLIBCXX17_CONSTEXPR bool
+    operator<=(const move_iterator<_Iterator>& __x,
+	       const move_iterator<_Iterator>& __y)
+    { return !(__y < __x); }
+
+  template<typename _Iterator>
+    inline _GLIBCXX17_CONSTEXPR bool
+    operator>(const move_iterator<_Iterator>& __x,
+	      const move_iterator<_Iterator>& __y)
+    { return __y < __x; }
+
   template<typename _Iterator>
     inline _GLIBCXX17_CONSTEXPR bool
     operator>=(const move_iterator<_Iterator>& __x,
 	       const move_iterator<_Iterator>& __y)
     { return !(__x < __y); }
+#endif // ! C++20
 
   // DR 685.
   template<typename _IteratorL, typename _IteratorR>
diff --git a/libstdc++-v3/testsuite/24_iterators/move_iterator/greedy_ops.cc b/libstdc++-v3/testsuite/24_iterators/move_iterator/greedy_ops.cc
index 66da0a4cff9..0e6d598cd43 100644
--- a/libstdc++-v3/testsuite/24_iterators/move_iterator/greedy_ops.cc
+++ b/libstdc++-v3/testsuite/24_iterators/move_iterator/greedy_ops.cc
@@ -24,7 +24,7 @@ void test01()
   typedef std::move_iterator<greedy_ops::X*> iterator_type;
 
   iterator_type it(nullptr);
-  
+
   it == it;
   it != it;
   it < it;
@@ -35,9 +35,3 @@ void test01()
   1 + it;
   it + 1;
 }
-
-int main() 
-{ 
-  test01();
-  return 0;
-}
diff --git a/libstdc++-v3/testsuite/24_iterators/move_iterator/rel_ops_c++20.cc b/libstdc++-v3/testsuite/24_iterators/move_iterator/rel_ops_c++20.cc
index 4e7b9d01e15..a530923f8ad 100644
--- a/libstdc++-v3/testsuite/24_iterators/move_iterator/rel_ops_c++20.cc
+++ b/libstdc++-v3/testsuite/24_iterators/move_iterator/rel_ops_c++20.cc
@@ -127,3 +127,37 @@ static_assert( has_le<2> );
 static_assert( ! has_ge<0> );
 static_assert( has_ge<1> );
 static_assert( ! has_ge<2> );
+
+int arr[3] = { 1, 2, 3 };
+constexpr std::move_iterator<int*> beg{std::begin(arr)};
+constexpr std::move_iterator<const int*> cbeg{std::cbegin(arr)};
+static_assert( beg == cbeg );
+static_assert( beg <= cbeg );
+static_assert( beg >= cbeg );
+static_assert( std::is_eq(beg <=> cbeg) );
+constexpr std::move_iterator<const int*> cend{std::cend(arr)};
+static_assert( beg != cend );
+static_assert( beg < cend );
+static_assert( cend > beg );
+static_assert( beg <= cend );
+static_assert( cend >= beg );
+static_assert( std::is_lt(beg <=> cend) );
+
+#include <testsuite_greedy_ops.h>
+
+void test01()
+{
+  typedef std::move_iterator<greedy_ops::X*> iterator_type;
+
+  iterator_type it(nullptr);
+
+  it == it;
+  it != it;
+  it < it;
+  it <= it;
+  it > it;
+  it >= it;
+  // it - it;  // See PR libstdc++/71771
+  1 + it;
+  it + 1;
+}
diff --git a/libstdc++-v3/testsuite/24_iterators/reverse_iterator/greedy_ops.cc b/libstdc++-v3/testsuite/24_iterators/reverse_iterator/greedy_ops.cc
index 60d4611e690..a5ea4524604 100644
--- a/libstdc++-v3/testsuite/24_iterators/reverse_iterator/greedy_ops.cc
+++ b/libstdc++-v3/testsuite/24_iterators/reverse_iterator/greedy_ops.cc
@@ -24,7 +24,7 @@ void test01()
   typedef std::reverse_iterator<greedy_ops::X*> iterator_type;
 
   iterator_type it;
-  
+
   it == it;
   it != it;
   it < it;
@@ -37,9 +37,3 @@ void test01()
   1 + it;
   it + 1;
 }
-
-int main() 
-{ 
-  test01();
-  return 0;
-}
diff --git a/libstdc++-v3/testsuite/24_iterators/reverse_iterator/rel_ops_c++20.cc b/libstdc++-v3/testsuite/24_iterators/reverse_iterator/rel_ops_c++20.cc
index 3e91a0396fe..a382ae52483 100644
--- a/libstdc++-v3/testsuite/24_iterators/reverse_iterator/rel_ops_c++20.cc
+++ b/libstdc++-v3/testsuite/24_iterators/reverse_iterator/rel_ops_c++20.cc
@@ -78,10 +78,10 @@ reverse_iterator<long*> r{nullptr};
 
 bool b0 = l0 == r;
 bool b1 = l1 != r;
-bool b2 = l2 < r;
-bool b3 = l3 > r;
-bool b4 = l4 <= r;
-bool b5 = l5 >= r;
+bool b2 = l2 > r;
+bool b3 = l3 < r;
+bool b4 = l4 >= r;
+bool b5 = l5 <= r;
 
 template<int N>
   concept has_eq
@@ -129,15 +129,15 @@ static_assert( ! has_ne<5> );
 
 static_assert( ! has_lt<0> );
 static_assert( ! has_lt<1> );
-static_assert( has_lt<2> );
-static_assert( ! has_lt<3> );
+static_assert( ! has_lt<2> );
+static_assert( has_lt<3> );
 static_assert( ! has_lt<4> );
 static_assert( ! has_lt<5> );
 
 static_assert( ! has_gt<0> );
 static_assert( ! has_gt<1> );
-static_assert( ! has_gt<2> );
-static_assert( has_gt<3> );
+static_assert( has_gt<2> );
+static_assert( ! has_gt<3> );
 static_assert( ! has_gt<4> );
 static_assert( ! has_gt<5> );
 
@@ -145,12 +145,49 @@ static_assert( ! has_le<0> );
 static_assert( ! has_le<1> );
 static_assert( ! has_le<2> );
 static_assert( ! has_le<3> );
-static_assert( has_le<4> );
-static_assert( ! has_le<5> );
+static_assert( ! has_le<4> );
+static_assert( has_le<5> );
 
 static_assert( ! has_ge<0> );
 static_assert( ! has_ge<1> );
 static_assert( ! has_ge<2> );
 static_assert( ! has_ge<3> );
-static_assert( ! has_ge<4> );
-static_assert( has_ge<5> );
+static_assert( has_ge<4> );
+static_assert( ! has_ge<5> );
+
+int arr[3] = { 1, 2, 3 };
+constexpr std::reverse_iterator<int*> rbeg = std::rbegin(arr);
+constexpr std::reverse_iterator<const int*> crbeg = std::crbegin(arr);
+static_assert( rbeg == crbeg );
+static_assert( rbeg <= crbeg );
+static_assert( rbeg >= crbeg );
+static_assert( std::is_eq(rbeg <=> crbeg) );
+constexpr std::reverse_iterator<const int*> crend = std::crend(arr);
+static_assert( rbeg != crend );
+static_assert( rbeg < crend );
+static_assert( crend > rbeg );
+static_assert( rbeg <= crend );
+static_assert( crend >= rbeg );
+static_assert( std::is_lt(rbeg <=> crend) );
+
+#include <testsuite_greedy_ops.h>
+
+// copied from 24_iterators/reverse_iterator/greedy_ops.cc
+void test01()
+{
+  typedef std::reverse_iterator<greedy_ops::X*> iterator_type;
+
+  iterator_type it;
+
+  it == it;
+  it != it;
+  it < it;
+  it <= it;
+  it > it;
+  it >= it;
+#if __cplusplus < 201103L
+  it - it; // See PR libstdc++/71771
+#endif
+  1 + it;
+  it + 1;
+}

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2020-03-28 22:22 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-03-27 23:28 [committed 1/3] libstdc++: Implement C++20 changes to insert iterators Jonathan Wakely
2020-03-27 23:29 ` [committed 2/3] libstdc++: Add remaining C++20 changes to iterator adaptors Jonathan Wakely
2020-03-27 23:30   ` [committed 3/3] libstdc++: Define __cpp_lib_ranges macro for C++20 Jonathan Wakely
2020-03-28  0:16   ` [committed 2/3] libstdc++: Add remaining C++20 changes to iterator adaptors Jonathan Wakely
2020-03-28 22:22     ` Jonathan Wakely

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).