As suggested by Jason, this makes all __normal_iterator operators into
friends so they can be found by ADL and don't need to be separately
exported in module std.

The operator<=> comparing two iterators of the same type is removed
entirely, instead of being made a hidden friend. That overload was added
by r12-5882-g2c7fb16b5283cf to deal with unconstrained operator
overloads found by ADL, as defined in the testsuite_greedy_ops.h header.
We don't actually test that case as there's no unconstrained <=> in that
header, and it doesn't seem reasonable for anybody to define such an
operator<=> in C++20 when they should constrain their overloads properly
(e.g. using a requires-clause). The heterogeneous operator<=> overloads
added for reverse_iterator and move_iterator could also be removed, but
that's not part of this commit.

I also had to reorder the __attribute__((always_inline)) and
[[nodiscard]] attributes, which have to be in a particular order when
used on friend functions.

libstdc++-v3/ChangeLog:

        * include/bits/stl_iterator.h (__normal_iterator): Make all
        non-member operators hidden friends, except ...
        (operator<=>(__normal_iterator<I,C>, __normal_iterator<I,C>)):
        Remove.
        * src/c++11/string-inst.cc: Remove explicit instantiations of
        operators that are no longer templates.
        * src/c++23/std.cc.in (__gnu_cxx): Do not export operators for
        __normal_iterator.
---

v2: removed the unnecessary operator<=>, removed std.cc exports, fixed
other minor issues noticed by Patrick.

Tested x86_64-linux.

 libstdc++-v3/include/bits/stl_iterator.h | 327 ++++++++++++-----------
 libstdc++-v3/src/c++11/string-inst.cc    |  11 -
 libstdc++-v3/src/c++23/std.cc.in         |   9 -
 3 files changed, 169 insertions(+), 178 deletions(-)

diff --git a/libstdc++-v3/include/bits/stl_iterator.h 
b/libstdc++-v3/include/bits/stl_iterator.h
index 478a98fe8a4f..a7188f46f6db 100644
--- a/libstdc++-v3/include/bits/stl_iterator.h
+++ b/libstdc++-v3/include/bits/stl_iterator.h
@@ -1164,188 +1164,199 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       const _Iterator&
       base() const _GLIBCXX_NOEXCEPT
       { return _M_current; }
-    };
 
-  // Note: In what follows, the left- and right-hand-side iterators are
-  // allowed to vary in types (conceptually in cv-qualification) so that
-  // comparison between cv-qualified and non-cv-qualified iterators be
-  // valid.  However, the greedy and unfriendly operators in std::rel_ops
-  // will make overload resolution ambiguous (when in scope) if we don't
-  // provide overloads whose operands are of the same type.  Can someone
-  // remind me what generic programming is about? -- Gaby
+    private:
+      // Note: In what follows, the left- and right-hand-side iterators are
+      // allowed to vary in types (conceptually in cv-qualification) so that
+      // comparison between cv-qualified and non-cv-qualified iterators be
+      // valid.  However, the greedy and unfriendly operators in std::rel_ops
+      // will make overload resolution ambiguous (when in scope) if we don't
+      // provide overloads whose operands are of the same type.  Can someone
+      // remind me what generic programming is about? -- Gaby
 
 #ifdef __cpp_lib_three_way_comparison
-  template<typename _IteratorL, typename _IteratorR, typename _Container>
-    [[nodiscard, __gnu__::__always_inline__]]
-    constexpr bool
-    operator==(const __normal_iterator<_IteratorL, _Container>& __lhs,
-              const __normal_iterator<_IteratorR, _Container>& __rhs)
-    noexcept(noexcept(__lhs.base() == __rhs.base()))
-    requires requires {
-      { __lhs.base() == __rhs.base() } -> std::convertible_to<bool>;
-    }
-    { return __lhs.base() == __rhs.base(); }
+      template<typename _Iter>
+       [[nodiscard, __gnu__::__always_inline__]]
+       friend
+       constexpr bool
+       operator==(const __normal_iterator& __lhs,
+                  const __normal_iterator<_Iter, _Container>& __rhs)
+       noexcept(noexcept(__lhs.base() == __rhs.base()))
+       requires requires {
+         { __lhs.base() == __rhs.base() } -> std::convertible_to<bool>;
+       }
+       { return __lhs.base() == __rhs.base(); }
 
-  template<typename _IteratorL, typename _IteratorR, typename _Container>
-    [[nodiscard, __gnu__::__always_inline__]]
-    constexpr std::__detail::__synth3way_t<_IteratorR, _IteratorL>
-    operator<=>(const __normal_iterator<_IteratorL, _Container>& __lhs,
-               const __normal_iterator<_IteratorR, _Container>& __rhs)
-    noexcept(noexcept(std::__detail::__synth3way(__lhs.base(), __rhs.base())))
-    { return std::__detail::__synth3way(__lhs.base(), __rhs.base()); }
+      [[nodiscard, __gnu__::__always_inline__]]
+      friend
+      constexpr bool
+      operator==(const __normal_iterator& __lhs, const __normal_iterator& 
__rhs)
+      noexcept(noexcept(__lhs.base() == __rhs.base()))
+      requires requires {
+       { __lhs.base() == __rhs.base() } -> std::convertible_to<bool>;
+      }
+      { return __lhs.base() == __rhs.base(); }
 
-  template<typename _Iterator, typename _Container>
-    [[nodiscard, __gnu__::__always_inline__]]
-    constexpr bool
-    operator==(const __normal_iterator<_Iterator, _Container>& __lhs,
-              const __normal_iterator<_Iterator, _Container>& __rhs)
-    noexcept(noexcept(__lhs.base() == __rhs.base()))
-    requires requires {
-      { __lhs.base() == __rhs.base() } -> std::convertible_to<bool>;
-    }
-    { return __lhs.base() == __rhs.base(); }
-
-  template<typename _Iterator, typename _Container>
-    [[nodiscard, __gnu__::__always_inline__]]
-    constexpr std::__detail::__synth3way_t<_Iterator>
-    operator<=>(const __normal_iterator<_Iterator, _Container>& __lhs,
-               const __normal_iterator<_Iterator, _Container>& __rhs)
-    noexcept(noexcept(std::__detail::__synth3way(__lhs.base(), __rhs.base())))
-    { return std::__detail::__synth3way(__lhs.base(), __rhs.base()); }
+      template<typename _Iter>
+       [[nodiscard, __gnu__::__always_inline__]]
+       friend
+       constexpr std::__detail::__synth3way_t<_Iterator, _Iter>
+       operator<=>(const __normal_iterator& __lhs,
+                   const __normal_iterator<_Iter, _Container>& __rhs)
+       noexcept(noexcept(std::__detail::__synth3way(__lhs.base(), 
__rhs.base())))
+       requires requires {
+         std::__detail::__synth3way(__lhs.base(), __rhs.base());
+       }
+       { return std::__detail::__synth3way(__lhs.base(), __rhs.base()); }
 #else
-   // Forward iterator requirements
-  template<typename _IteratorL, typename _IteratorR, typename _Container>
-    _GLIBCXX_NODISCARD __attribute__((__always_inline__)) _GLIBCXX_CONSTEXPR
-    inline bool
-    operator==(const __normal_iterator<_IteratorL, _Container>& __lhs,
-              const __normal_iterator<_IteratorR, _Container>& __rhs)
-    _GLIBCXX_NOEXCEPT
-    { return __lhs.base() == __rhs.base(); }
+       // Forward iterator requirements
+      template<typename _Iter>
+       __attribute__((__always_inline__)) _GLIBCXX_NODISCARD
+       friend
+       _GLIBCXX_CONSTEXPR
+       bool
+       operator==(const __normal_iterator& __lhs,
+                  const __normal_iterator<_Iter, _Container>& __rhs)
+       _GLIBCXX_NOEXCEPT
+       { return __lhs.base() == __rhs.base(); }
 
-  template<typename _Iterator, typename _Container>
-    _GLIBCXX_NODISCARD __attribute__((__always_inline__)) _GLIBCXX_CONSTEXPR
-    inline bool
-    operator==(const __normal_iterator<_Iterator, _Container>& __lhs,
-              const __normal_iterator<_Iterator, _Container>& __rhs)
-    _GLIBCXX_NOEXCEPT
-    { return __lhs.base() == __rhs.base(); }
+      __attribute__((__always_inline__)) _GLIBCXX_NODISCARD
+      friend
+      _GLIBCXX_CONSTEXPR
+      bool
+      operator==(const __normal_iterator& __lhs, const __normal_iterator& 
__rhs)
+      _GLIBCXX_NOEXCEPT
+      { return __lhs.base() == __rhs.base(); }
 
-  template<typename _IteratorL, typename _IteratorR, typename _Container>
-    _GLIBCXX_NODISCARD __attribute__((__always_inline__)) _GLIBCXX_CONSTEXPR
-    inline bool
-    operator!=(const __normal_iterator<_IteratorL, _Container>& __lhs,
-              const __normal_iterator<_IteratorR, _Container>& __rhs)
-    _GLIBCXX_NOEXCEPT
-    { return __lhs.base() != __rhs.base(); }
+      template<typename _Iter>
+       __attribute__((__always_inline__)) _GLIBCXX_NODISCARD
+       friend
+       _GLIBCXX_CONSTEXPR
+       bool
+       operator!=(const __normal_iterator& __lhs,
+                  const __normal_iterator<_Iter, _Container>& __rhs)
+       _GLIBCXX_NOEXCEPT
+       { return __lhs.base() != __rhs.base(); }
 
-  template<typename _Iterator, typename _Container>
-    _GLIBCXX_NODISCARD __attribute__((__always_inline__)) _GLIBCXX_CONSTEXPR
-    inline bool
-    operator!=(const __normal_iterator<_Iterator, _Container>& __lhs,
-              const __normal_iterator<_Iterator, _Container>& __rhs)
-    _GLIBCXX_NOEXCEPT
-    { return __lhs.base() != __rhs.base(); }
+      __attribute__((__always_inline__)) _GLIBCXX_NODISCARD
+      friend
+      _GLIBCXX_CONSTEXPR
+      bool
+      operator!=(const __normal_iterator& __lhs, const __normal_iterator& 
__rhs)
+      _GLIBCXX_NOEXCEPT
+      { return __lhs.base() != __rhs.base(); }
 
-  // Random access iterator requirements
-  template<typename _IteratorL, typename _IteratorR, typename _Container>
-    _GLIBCXX_NODISCARD __attribute__((__always_inline__)) _GLIBCXX_CONSTEXPR
-    inline bool
-    operator<(const __normal_iterator<_IteratorL, _Container>& __lhs,
-             const __normal_iterator<_IteratorR, _Container>& __rhs)
-    _GLIBCXX_NOEXCEPT
-    { return __lhs.base() < __rhs.base(); }
+      // Random access iterator requirements
+      template<typename _Iter>
+       friend
+       __attribute__((__always_inline__)) _GLIBCXX_NODISCARD _GLIBCXX_CONSTEXPR
+       inline bool
+       operator<(const __normal_iterator& __lhs,
+                 const __normal_iterator<_Iter, _Container>& __rhs)
+       _GLIBCXX_NOEXCEPT
+       { return __lhs.base() < __rhs.base(); }
 
-  template<typename _Iterator, typename _Container>
-    _GLIBCXX_NODISCARD __attribute__((__always_inline__)) _GLIBCXX20_CONSTEXPR
-    inline bool
-    operator<(const __normal_iterator<_Iterator, _Container>& __lhs,
-             const __normal_iterator<_Iterator, _Container>& __rhs)
-    _GLIBCXX_NOEXCEPT
-    { return __lhs.base() < __rhs.base(); }
+      __attribute__((__always_inline__)) _GLIBCXX_NODISCARD
+      friend
+      _GLIBCXX20_CONSTEXPR
+      bool
+      operator<(const __normal_iterator& __lhs, const __normal_iterator& __rhs)
+      _GLIBCXX_NOEXCEPT
+      { return __lhs.base() < __rhs.base(); }
 
-  template<typename _IteratorL, typename _IteratorR, typename _Container>
-    _GLIBCXX_NODISCARD __attribute__((__always_inline__)) _GLIBCXX_CONSTEXPR
-    inline bool
-    operator>(const __normal_iterator<_IteratorL, _Container>& __lhs,
-             const __normal_iterator<_IteratorR, _Container>& __rhs)
-    _GLIBCXX_NOEXCEPT
-    { return __lhs.base() > __rhs.base(); }
+      template<typename _Iter>
+       friend
+       __attribute__((__always_inline__)) _GLIBCXX_NODISCARD _GLIBCXX_CONSTEXPR
+       bool
+       operator>(const __normal_iterator& __lhs,
+                 const __normal_iterator<_Iter, _Container>& __rhs)
+       _GLIBCXX_NOEXCEPT
+       { return __lhs.base() > __rhs.base(); }
 
-  template<typename _Iterator, typename _Container>
-    _GLIBCXX_NODISCARD __attribute__((__always_inline__)) _GLIBCXX_CONSTEXPR
-    inline bool
-    operator>(const __normal_iterator<_Iterator, _Container>& __lhs,
-             const __normal_iterator<_Iterator, _Container>& __rhs)
-    _GLIBCXX_NOEXCEPT
-    { return __lhs.base() > __rhs.base(); }
+      __attribute__((__always_inline__)) _GLIBCXX_NODISCARD
+      friend
+      _GLIBCXX_CONSTEXPR
+      bool
+      operator>(const __normal_iterator& __lhs, const __normal_iterator& __rhs)
+      _GLIBCXX_NOEXCEPT
+      { return __lhs.base() > __rhs.base(); }
 
-  template<typename _IteratorL, typename _IteratorR, typename _Container>
-    _GLIBCXX_NODISCARD __attribute__((__always_inline__)) _GLIBCXX_CONSTEXPR
-    inline bool
-    operator<=(const __normal_iterator<_IteratorL, _Container>& __lhs,
-              const __normal_iterator<_IteratorR, _Container>& __rhs)
-    _GLIBCXX_NOEXCEPT
-    { return __lhs.base() <= __rhs.base(); }
+      template<typename _Iter>
+       __attribute__((__always_inline__)) _GLIBCXX_NODISCARD
+       friend
+       _GLIBCXX_CONSTEXPR
+       bool
+       operator<=(const __normal_iterator& __lhs,
+                  const __normal_iterator<_Iter, _Container>& __rhs)
+       _GLIBCXX_NOEXCEPT
+       { return __lhs.base() <= __rhs.base(); }
 
-  template<typename _Iterator, typename _Container>
-    _GLIBCXX_NODISCARD __attribute__((__always_inline__)) _GLIBCXX_CONSTEXPR
-    inline bool
-    operator<=(const __normal_iterator<_Iterator, _Container>& __lhs,
-              const __normal_iterator<_Iterator, _Container>& __rhs)
-    _GLIBCXX_NOEXCEPT
-    { return __lhs.base() <= __rhs.base(); }
+      __attribute__((__always_inline__)) _GLIBCXX_NODISCARD
+      friend
+      _GLIBCXX_CONSTEXPR
+      bool
+      operator<=(const __normal_iterator& __lhs, const __normal_iterator& 
__rhs)
+      _GLIBCXX_NOEXCEPT
+      { return __lhs.base() <= __rhs.base(); }
 
-  template<typename _IteratorL, typename _IteratorR, typename _Container>
-    _GLIBCXX_NODISCARD __attribute__((__always_inline__)) _GLIBCXX_CONSTEXPR
-    inline bool
-    operator>=(const __normal_iterator<_IteratorL, _Container>& __lhs,
-              const __normal_iterator<_IteratorR, _Container>& __rhs)
-    _GLIBCXX_NOEXCEPT
-    { return __lhs.base() >= __rhs.base(); }
+      template<typename _Iter>
+       __attribute__((__always_inline__)) _GLIBCXX_NODISCARD
+       friend
+       _GLIBCXX_CONSTEXPR
+       bool
+       operator>=(const __normal_iterator& __lhs,
+                  const __normal_iterator<_Iter, _Container>& __rhs)
+       _GLIBCXX_NOEXCEPT
+       { return __lhs.base() >= __rhs.base(); }
 
-  template<typename _Iterator, typename _Container>
-    _GLIBCXX_NODISCARD __attribute__((__always_inline__)) _GLIBCXX_CONSTEXPR
-    inline bool
-    operator>=(const __normal_iterator<_Iterator, _Container>& __lhs,
-              const __normal_iterator<_Iterator, _Container>& __rhs)
-    _GLIBCXX_NOEXCEPT
-    { return __lhs.base() >= __rhs.base(); }
+      __attribute__((__always_inline__)) _GLIBCXX_NODISCARD
+      friend
+      _GLIBCXX_CONSTEXPR
+      bool
+      operator>=(const __normal_iterator& __lhs, const __normal_iterator& 
__rhs)
+      _GLIBCXX_NOEXCEPT
+      { return __lhs.base() >= __rhs.base(); }
 #endif // three-way comparison
 
-  // _GLIBCXX_RESOLVE_LIB_DEFECTS
-  // According to the resolution of DR179 not only the various comparison
-  // operators but also operator- must accept mixed iterator/const_iterator
-  // parameters.
-  template<typename _IteratorL, typename _IteratorR, typename _Container>
+      // _GLIBCXX_RESOLVE_LIB_DEFECTS
+      // 179. Comparison of const_iterators to iterators doesn't work
+      // According to the resolution of DR179 not only the various comparison
+      // operators but also operator- must accept mixed iterator/const_iterator
+      // parameters.
+      template<typename _Iter>
 #if __cplusplus >= 201103L
-    // DR 685.
-    [[__nodiscard__, __gnu__::__always_inline__]]
-    constexpr auto
-    operator-(const __normal_iterator<_IteratorL, _Container>& __lhs,
-             const __normal_iterator<_IteratorR, _Container>& __rhs) noexcept
-    -> decltype(__lhs.base() - __rhs.base())
+       [[__nodiscard__, __gnu__::__always_inline__]]
+       friend
+       // _GLIBCXX_RESOLVE_LIB_DEFECTS
+       // 685. reverse_iterator/move_iterator difference has invalid signatures
+       constexpr auto
+       operator-(const __normal_iterator& __lhs,
+                 const __normal_iterator<_Iter, _Container>& __rhs) noexcept
+       -> decltype(__lhs.base() - __rhs.base())
 #else
-    inline typename __normal_iterator<_IteratorL, _Container>::difference_type
-    operator-(const __normal_iterator<_IteratorL, _Container>& __lhs,
-             const __normal_iterator<_IteratorR, _Container>& __rhs)
+       friend
+       difference_type
+       operator-(const __normal_iterator& __lhs,
+                 const __normal_iterator<_Iter, _Container>& __rhs)
 #endif
-    { return __lhs.base() - __rhs.base(); }
+       { return __lhs.base() - __rhs.base(); }
 
-  template<typename _Iterator, typename _Container>
-    _GLIBCXX_NODISCARD __attribute__((__always_inline__)) _GLIBCXX_CONSTEXPR
-    inline typename __normal_iterator<_Iterator, _Container>::difference_type
-    operator-(const __normal_iterator<_Iterator, _Container>& __lhs,
-             const __normal_iterator<_Iterator, _Container>& __rhs)
-    _GLIBCXX_NOEXCEPT
-    { return __lhs.base() - __rhs.base(); }
+      __attribute__((__always_inline__)) _GLIBCXX_NODISCARD
+      friend
+      _GLIBCXX_CONSTEXPR
+      difference_type
+      operator-(const __normal_iterator& __lhs, const __normal_iterator& __rhs)
+       _GLIBCXX_NOEXCEPT
+      { return __lhs.base() - __rhs.base(); }
 
-  template<typename _Iterator, typename _Container>
-    _GLIBCXX_NODISCARD __attribute__((__always_inline__)) _GLIBCXX_CONSTEXPR
-    inline __normal_iterator<_Iterator, _Container>
-    operator+(typename __normal_iterator<_Iterator, 
_Container>::difference_type
-             __n, const __normal_iterator<_Iterator, _Container>& __i)
-    _GLIBCXX_NOEXCEPT
-    { return __normal_iterator<_Iterator, _Container>(__i.base() + __n); }
+      __attribute__((__always_inline__)) _GLIBCXX_NODISCARD
+      friend
+      _GLIBCXX_CONSTEXPR
+      __normal_iterator
+      operator+(difference_type __n, const __normal_iterator& __i)
+       _GLIBCXX_NOEXCEPT
+      { return __normal_iterator(__i.base() + __n); }
+    };
 
 _GLIBCXX_END_NAMESPACE_VERSION
 } // namespace __gnu_cxx
diff --git a/libstdc++-v3/src/c++11/string-inst.cc 
b/libstdc++-v3/src/c++11/string-inst.cc
index 34df909b31a2..1056e646b12c 100644
--- a/libstdc++-v3/src/c++11/string-inst.cc
+++ b/libstdc++-v3/src/c++11/string-inst.cc
@@ -119,14 +119,3 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
 _GLIBCXX_END_NAMESPACE_VERSION
 } // namespace
-
-namespace __gnu_cxx _GLIBCXX_VISIBILITY(default)
-{
-_GLIBCXX_BEGIN_NAMESPACE_VERSION
-
-  using std::S;
-  template bool operator==(const S::iterator&, const S::iterator&);
-  template bool operator==(const S::const_iterator&, const S::const_iterator&);
-
-_GLIBCXX_END_NAMESPACE_VERSION
-} // namespace
diff --git a/libstdc++-v3/src/c++23/std.cc.in b/libstdc++-v3/src/c++23/std.cc.in
index 4cd3e52c8bbf..f1c3e2e4b284 100644
--- a/libstdc++-v3/src/c++23/std.cc.in
+++ b/libstdc++-v3/src/c++23/std.cc.in
@@ -1729,15 +1729,6 @@ export namespace std
   using std::make_const_sentinel;
 #endif
 }
-// FIXME these should be friends of __normal_iterator to avoid exporting
-// __gnu_cxx.
-export namespace __gnu_cxx
-{
-  using __gnu_cxx::operator==;
-  using __gnu_cxx::operator<=>;
-  using __gnu_cxx::operator+;
-  using __gnu_cxx::operator-;
-}
 
 // <latch>
 export namespace std
-- 
2.49.0

Reply via email to