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