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.

For the operator<=> comparing two iterators of the same type, I had to
use a deduced return type and add a requires-clause, because it's no
longer a template and so we no longer get substitution failures when
it's considered in oerload resolution.

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.
        * src/c++11/string-inst.cc: Remove explicit instantiations of
        operators that are no longer templates.
---

Tested x86_64-linux.

This iterator type isn't defined in the standard, and users shouldn't be
doing funny things with it, so nothing prevents us from replacing its
operators with hidden friends.

 libstdc++-v3/include/bits/stl_iterator.h | 341 ++++++++++++-----------
 libstdc++-v3/src/c++11/string-inst.cc    |  11 -
 2 files changed, 184 insertions(+), 168 deletions(-)

diff --git a/libstdc++-v3/include/bits/stl_iterator.h 
b/libstdc++-v3/include/bits/stl_iterator.h
index e872598d7d8..656a47e5f76 100644
--- a/libstdc++-v3/include/bits/stl_iterator.h
+++ b/libstdc++-v3/include/bits/stl_iterator.h
@@ -1164,188 +1164,215 @@ _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()); }
+      template<typename _Iter>
+       static constexpr bool __nothrow_synth3way
+         = noexcept(std::__detail::__synth3way(std::declval<_Iterator&>(),
+                                               std::declval<_Iter&>()));
 
-  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 _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(__nothrow_synth3way<_Iter>)
+       requires requires {
+         std::__detail::__synth3way(__lhs.base(), __rhs.base());
+       }
+       { return std::__detail::__synth3way(__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()); }
+      [[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(); }
+
+      [[nodiscard, __gnu__::__always_inline__]]
+      friend
+      constexpr auto
+      operator<=>(const __normal_iterator& __lhs,
+                 const __normal_iterator& __rhs)
+      noexcept(__nothrow_synth3way<_Iterator>)
+      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
+       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__)) _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
+      inline 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
+       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__)) _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
+      inline 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
+      inline 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
+       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__)) _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
+      inline 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
+       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__)) _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
+      inline 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
+       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__)) _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
+      inline 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
+      inline 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
+      inline __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 ec5ba41ebcd..b8806304949 100644
--- a/libstdc++-v3/src/c++11/string-inst.cc
+++ b/libstdc++-v3/src/c++11/string-inst.cc
@@ -110,14 +110,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
-- 
2.47.0

Reply via email to