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