https://gcc.gnu.org/g:2fd6f42c17a8040dbd3460ca34d93695dacf8575
commit r16-2084-g2fd6f42c17a8040dbd3460ca34d93695dacf8575 Author: François Dumont <frs.dum...@gmail.com> Date: Thu Mar 27 19:02:59 2025 +0100 libstdc++: Make debug iterator pointer sequence const [PR116369] In revision a35dd276cbf6236e08bcf6e56e62c2be41cf6e3c the debug sequence have been made mutable to allow attach iterators to const containers. This change completes this fix by also declaring debug unordered container members mutable. Additionally the debug iterator sequence is now a pointer-to-const and so _Safe_sequence_base _M_attach and all other methods are const qualified. Not-const methods exported are preserved for abi backward compatibility. libstdc++-v3/ChangeLog: PR c++/116369 * config/abi/pre/gnu-versioned-namespace.ver: Use new const qualified symbols. * config/abi/pre/gnu.ver: Add new const qualified symbols. * include/debug/safe_base.h (_Safe_iterator_base::_M_sequence): Declare as pointer-to-const. (_Safe_iterator_base::_M_attach, _M_attach_single): New, take pointer-to-const _Safe_sequence_base. (_Safe_sequence_base::_M_detach_all, _M_detach_singular, _M_revalidate_singular) (_M_swap, _M_get_mutex): New, const qualified. (_Safe_sequence_base::_M_attach, _M_attach_single, _M_detach, _M_detach_single): const qualify. * include/debug/safe_container.h (_Safe_container<>::_M_cont): Add const qualifier. (_Safe_container<>::_M_swap_base): New. (_Safe_container(_Safe_container&&, const _Alloc&, std::false_type)): Adapt to use latter. (_Safe_container<>::operator=(_Safe_container&&)): Likewise. (_Safe_container<>::_M_swap): Likewise and take parameter as const reference. * include/debug/safe_unordered_base.h (_Safe_local_iterator_base::_M_safe_container): New. (_Safe_local_iterator_base::_Safe_local_iterator_base): Take _Safe_unordered_container_base as pointer-to-const. (_Safe_unordered_container_base::_M_attach, _M_attach_single): New, take container as _Safe_unordered_container_base pointer-to-const. (_Safe_unordered_container_base::_M_local_iterators, _M_const_local_iterators): Add mutable. (_Safe_unordered_container_base::_M_detach_all, _M_swap): New, const qualify. (_Safe_unordered_container_base::_M_attach_local, _M_attach_local_single) (_M_detach_local, _M_detach_local_single): Add const qualifier. * include/debug/safe_unordered_container.h (_Safe_unordered_container::_M_self()): New. * include/debug/safe_unordered_container.tcc (_Safe_unordered_container::_M_invalidate_if, _M_invalidated_local_if): Use latter. * include/debug/safe_iterator.h (_Safe_iterator<>::_M_attach, _M_attach_single): Take _Safe_sequence_base as pointer-to-const. (_Safe_iterator<>::_M_get_sequence): Add const_cast and comment about it. * include/debug/safe_local_iterator.h (_Safe_local_iterator<>): Replace usages of _M_sequence member by _M_safe_container(). (_Safe_local_iterator<>::_M_attach, _M_attach_single): Take _Safe_unordered_container_base as pointer-to-const. (_Safe_local_iterator<>::_M_get_sequence): Rename into... (_Safe_local_iterator<>::_M_get_ucontainer): ...this. Add necessary const_cast and comment to explain it. (_Safe_local_iterator<>::_M_is_begin, _M_is_end): Adapt. * include/debug/safe_local_iterator.tcc: Adapt. * include/debug/safe_sequence.h (_Safe_sequence<>::_M_invalidate_if, _M_transfer_from_if): Add const qualifier. * include/debug/safe_sequence.tcc: Adapt. * include/debug/deque (std::__debug::deque::erase): Adapt to use new const qualified methods. * include/debug/formatter.h: Adapt. * include/debug/forward_list (_Safe_forward_list::_M_this): Add const qualification and return pointer for consistency with 'this' keyword. (_Safe_forward_list::_M_swap_aux): Rename into... (_Safe_forward_list::_S_swap_aux): ...this and take sequence as const reference. (forward_list<>::resize): Adapt to use const methods. * include/debug/list (list<>::resize): Likewise. * src/c++11/debug.cc: Adapt to const qualification. * testsuite/util/testsuite_containers.h (forward_members_unordered::forward_members_unordered): Add check on local_iterator conversion to const_local_iterator. (forward_members::forward_members): Add check on iterator conversion to const_iterator. * testsuite/23_containers/unordered_map/const_container.cc: New test case. * testsuite/23_containers/unordered_multimap/const_container.cc: New test case. * testsuite/23_containers/unordered_multiset/const_container.cc: New test case. * testsuite/23_containers/unordered_set/const_container.cc: New test case. * testsuite/23_containers/vector/debug/mutex_association.cc: Adapt. Diff: --- .../config/abi/pre/gnu-versioned-namespace.ver | 18 +-- libstdc++-v3/config/abi/pre/gnu.ver | 14 ++ libstdc++-v3/include/debug/deque | 5 +- libstdc++-v3/include/debug/formatter.h | 10 +- libstdc++-v3/include/debug/forward_list | 71 ++++----- libstdc++-v3/include/debug/list | 15 +- libstdc++-v3/include/debug/safe_base.h | 77 ++++++--- libstdc++-v3/include/debug/safe_container.h | 25 ++- libstdc++-v3/include/debug/safe_iterator.h | 14 +- libstdc++-v3/include/debug/safe_local_iterator.h | 102 ++++++------ libstdc++-v3/include/debug/safe_local_iterator.tcc | 4 +- libstdc++-v3/include/debug/safe_sequence.h | 9 +- libstdc++-v3/include/debug/safe_sequence.tcc | 6 +- libstdc++-v3/include/debug/safe_unordered_base.h | 67 ++++++-- .../include/debug/safe_unordered_container.h | 4 + .../include/debug/safe_unordered_container.tcc | 4 +- libstdc++-v3/src/c++11/debug.cc | 174 ++++++++++++++++----- .../23_containers/unordered_map/const_container.cc | 19 +++ .../unordered_multimap/const_container.cc | 22 +++ .../unordered_multiset/const_container.cc | 15 ++ .../23_containers/unordered_set/const_container.cc | 14 ++ .../vector/debug/mutex_association.cc | 2 +- libstdc++-v3/testsuite/util/testsuite_containers.h | 6 + 23 files changed, 491 insertions(+), 206 deletions(-) diff --git a/libstdc++-v3/config/abi/pre/gnu-versioned-namespace.ver b/libstdc++-v3/config/abi/pre/gnu-versioned-namespace.ver index 2818ab3561f9..1c423ff2f572 100644 --- a/libstdc++-v3/config/abi/pre/gnu-versioned-namespace.ver +++ b/libstdc++-v3/config/abi/pre/gnu-versioned-namespace.ver @@ -117,11 +117,11 @@ GLIBCXX_8.0 { _ZN9__gnu_cxx3__818stdio_sync_filebufI[cw]NSt3__811char_traitsI[cw]EEE[5-9]*; # debug mode - _ZN11__gnu_debug19_Safe_sequence_base12_M_get_mutexEv; - _ZN11__gnu_debug19_Safe_sequence_base13_M_detach_allEv; - _ZN11__gnu_debug19_Safe_sequence_base18_M_detach_singularEv; - _ZN11__gnu_debug19_Safe_sequence_base22_M_revalidate_singularEv; - _ZN11__gnu_debug19_Safe_sequence_base7_M_swapERS0_; + _ZNK11__gnu_debug19_Safe_sequence_base12_M_get_mutexEv; + _ZNK11__gnu_debug19_Safe_sequence_base13_M_detach_allEv; + _ZNK11__gnu_debug19_Safe_sequence_base18_M_detach_singularEv; + _ZNK11__gnu_debug19_Safe_sequence_base22_M_revalidate_singularEv; + _ZNK11__gnu_debug19_Safe_sequence_base7_M_swapERKS0_; _ZN11__gnu_debug19_Safe_iterator_base9_M_attach*; _ZN11__gnu_debug19_Safe_iterator_base16_M_attach_single*; @@ -136,11 +136,11 @@ GLIBCXX_8.0 { # __gnu_debug::_Safe_unordered_container_base # __gnu_debug::_Safe_local_iterator_base - _ZN11__gnu_debug30_Safe_unordered_container_base7_M_swapERS0_; - _ZN11__gnu_debug30_Safe_unordered_container_base13_M_detach_allEv; - _ZN11__gnu_debug25_Safe_local_iterator_base9_M_attachEPNS_19_Safe_sequence_baseEb; + _ZNK11__gnu_debug30_Safe_unordered_container_base7_M_swapERKS0_; + _ZNK11__gnu_debug30_Safe_unordered_container_base13_M_detach_allEv; + _ZN11__gnu_debug25_Safe_local_iterator_base9_M_attachEPKNS_30_Safe_unordered_container_baseEb; _ZN11__gnu_debug25_Safe_local_iterator_base9_M_detachEv; - _ZN11__gnu_debug25_Safe_local_iterator_base16_M_attach_singleEPNS_19_Safe_sequence_baseEb; + _ZN11__gnu_debug25_Safe_local_iterator_base16_M_attach_singleEPKNS_30_Safe_unordered_container_baseEb; # parallel mode _ZN14__gnu_parallel9_Settings3getEv; diff --git a/libstdc++-v3/config/abi/pre/gnu.ver b/libstdc++-v3/config/abi/pre/gnu.ver index 73b6f338613e..b5a89c31e0eb 100644 --- a/libstdc++-v3/config/abi/pre/gnu.ver +++ b/libstdc++-v3/config/abi/pre/gnu.ver @@ -2555,6 +2555,20 @@ GLIBCXX_3.4.35 { _ZNSt8__detail17__wait_until_implEPKvRNS_16__wait_args_baseERKNSt6chrono8durationI[lx]St5ratioIL[lx]1EL[lx]1000000000EEEE; _ZNSt8__detail11__wait_args22_M_load_proxy_wait_valEPKv; + # __gnu_debug::_Safe_iterator_base and _Safe_sequence_base const + _ZN11__gnu_debug19_Safe_iterator_base9_M_attachEPKNS_19_Safe_sequence_baseEb; + _ZN11__gnu_debug19_Safe_iterator_base16_M_attach_singleEPKNS_19_Safe_sequence_baseEb; + _ZNK11__gnu_debug19_Safe_sequence_base13_M_detach_allEv; + _ZNK11__gnu_debug19_Safe_sequence_base18_M_detach_singularEv; + _ZNK11__gnu_debug19_Safe_sequence_base12_M_get_mutexEv; + _ZNK11__gnu_debug19_Safe_sequence_base22_M_revalidate_singularEv; + _ZNK11__gnu_debug19_Safe_sequence_base7_M_swapERKS0_; + + # __gnu_debug::_Safe_local_iterator_base and _Safe_unordered_container_base const + _ZN11__gnu_debug25_Safe_local_iterator_base9_M_attachEPKNS_30_Safe_unordered_container_baseEb; + _ZN11__gnu_debug25_Safe_local_iterator_base16_M_attach_singleEPKNS_30_Safe_unordered_container_baseEb; + _ZNK11__gnu_debug30_Safe_unordered_container_base13_M_detach_allEv; + _ZNK11__gnu_debug30_Safe_unordered_container_base7_M_swapERKS0_; } GLIBCXX_3.4.34; # Symbols in the support library (libsupc++) have their own tag. diff --git a/libstdc++-v3/include/debug/deque b/libstdc++-v3/include/debug/deque index 59d60b2120db..ed69eb842e2b 100644 --- a/libstdc++-v3/include/debug/deque +++ b/libstdc++-v3/include/debug/deque @@ -650,7 +650,8 @@ namespace __debug else if (__first.base() == _Base::begin() || __last.base() == _Base::end()) { - this->_M_detach_singular(); + const deque* __this = this; + __this->_M_detach_singular(); for (_Base_const_iterator __position = __first.base(); __position != __last.base(); ++__position) { @@ -663,7 +664,7 @@ namespace __debug } __catch(...) { - this->_M_revalidate_singular(); + __this->_M_revalidate_singular(); __throw_exception_again; } } diff --git a/libstdc++-v3/include/debug/formatter.h b/libstdc++-v3/include/debug/formatter.h index d80e8a78dcb4..8aa84adec778 100644 --- a/libstdc++-v3/include/debug/formatter.h +++ b/libstdc++-v3/include/debug/formatter.h @@ -96,7 +96,7 @@ namespace __gnu_debug template<typename _Iterator, typename _Sequence, typename _Category> class _Safe_iterator; - template<typename _Iterator, typename _Sequence> + template<typename _Iterator, typename _UContainer> class _Safe_local_iterator; template<typename _Sequence> @@ -316,8 +316,8 @@ namespace __gnu_debug } } - template<typename _Iterator, typename _Sequence> - _Parameter(_Safe_local_iterator<_Iterator, _Sequence> const& __it, + template<typename _Iterator, typename _UContainer> + _Parameter(_Safe_local_iterator<_Iterator, _UContainer> const& __it, const char* __name, _Is_iterator) : _M_kind(__iterator), _M_variant() { @@ -326,8 +326,8 @@ namespace __gnu_debug _M_variant._M_iterator._M_type = _GLIBCXX_TYPEID(_Iterator); _M_variant._M_iterator._M_constness = __it._S_constant() ? __const_iterator : __mutable_iterator; - _M_variant._M_iterator._M_sequence = __it._M_get_sequence(); - _M_variant._M_iterator._M_seq_type = _GLIBCXX_TYPEID(_Sequence); + _M_variant._M_iterator._M_sequence = __it._M_get_ucontainer(); + _M_variant._M_iterator._M_seq_type = _GLIBCXX_TYPEID(_UContainer); if (__it._M_singular()) { diff --git a/libstdc++-v3/include/debug/forward_list b/libstdc++-v3/include/debug/forward_list index 60a254297d54..4e1511da4e82 100644 --- a/libstdc++-v3/include/debug/forward_list +++ b/libstdc++-v3/include/debug/forward_list @@ -58,44 +58,44 @@ namespace __gnu_debug class _Safe_forward_list : public _Safe_sequence<_SafeSequence> { - _SafeSequence& - _M_this() noexcept - { return *static_cast<_SafeSequence*>(this); } + const _SafeSequence* + _M_this() const noexcept + { return static_cast<const _SafeSequence*>(this); } static void - _M_swap_aux(_Safe_sequence_base& __lhs, + _S_swap_aux(const _Safe_forward_list& __lhs, _Safe_iterator_base*& __lhs_iterators, - _Safe_sequence_base& __rhs, + const _Safe_forward_list& __rhs, _Safe_iterator_base*& __rhs_iterators); - void _M_swap_single(_Safe_sequence_base&) noexcept; + void _M_swap_single(const _Safe_forward_list&) const noexcept; protected: void - _M_invalidate_all() + _M_invalidate_all() const { - using _Base_const_iterator = __decltype(_M_this()._M_base().cend()); + using _Base_const_iterator = __decltype(_M_this()->_M_base().cend()); this->_M_invalidate_if([this](_Base_const_iterator __it) { - return __it != _M_this()._M_base().cbefore_begin() - && __it != _M_this()._M_base().cend(); }); + return __it != _M_this()->_M_base().cbefore_begin() + && __it != _M_this()->_M_base().cend(); }); } - void _M_swap(_Safe_sequence_base&) noexcept; + void + _M_swap(const _Safe_forward_list&) const noexcept; }; template<typename _SafeSequence> void _Safe_forward_list<_SafeSequence>:: - _M_swap_aux(_Safe_sequence_base& __lhs, + _S_swap_aux(const _Safe_forward_list& __lhs, _Safe_iterator_base*& __lhs_iterators, - _Safe_sequence_base& __rhs, + const _Safe_forward_list& __rhs, _Safe_iterator_base*& __rhs_iterators) { using const_iterator = typename _SafeSequence::const_iterator; _Safe_iterator_base* __bbegin_its = 0; _Safe_iterator_base* __last_bbegin = 0; - _SafeSequence& __rseq = static_cast<_SafeSequence&>(__rhs); for (_Safe_iterator_base* __iter = __lhs_iterators; __iter;) { @@ -104,7 +104,7 @@ namespace __gnu_debug const_iterator* __victim = static_cast<const_iterator*>(__victim_base); __iter = __iter->_M_next; - if (__victim->base() == __rseq._M_base().cbefore_begin()) + if (__victim->base() == __rhs._M_this()->_M_base().cbefore_begin()) { __victim->_M_unlink(); if (__lhs_iterators == __victim_base) @@ -136,21 +136,21 @@ namespace __gnu_debug template<typename _SafeSequence> void _Safe_forward_list<_SafeSequence>:: - _M_swap_single(_Safe_sequence_base& __other) noexcept + _M_swap_single(const _Safe_forward_list& __other) const noexcept { - std::swap(_M_this()._M_iterators, __other._M_iterators); - std::swap(_M_this()._M_const_iterators, __other._M_const_iterators); + std::swap(_M_this()->_M_iterators, __other._M_iterators); + std::swap(_M_this()->_M_const_iterators, __other._M_const_iterators); // Useless, always 1 on forward_list - //std::swap(_M_this()_M_version, __other._M_version); - _Safe_iterator_base* __this_its = _M_this()._M_iterators; - _M_swap_aux(__other, __other._M_iterators, - _M_this(), _M_this()._M_iterators); - _Safe_iterator_base* __this_const_its = _M_this()._M_const_iterators; - _M_swap_aux(__other, __other._M_const_iterators, - _M_this(), _M_this()._M_const_iterators); - _M_swap_aux(_M_this(), __this_its, + //std::swap(_M_this()->_M_version, __other._M_version); + _Safe_iterator_base* __this_its = _M_this()->_M_iterators; + _S_swap_aux(__other, __other._M_iterators, + _M_this(), _M_this()->_M_iterators); + _Safe_iterator_base* __this_const_its = _M_this()->_M_const_iterators; + _S_swap_aux(__other, __other._M_const_iterators, + _M_this(), _M_this()->_M_const_iterators); + _S_swap_aux(_M_this(), __this_its, __other, __other._M_iterators); - _M_swap_aux(_M_this(), __this_const_its, + _S_swap_aux(_M_this(), __this_const_its, __other, __other._M_const_iterators); } @@ -159,13 +159,12 @@ namespace __gnu_debug template<typename _SafeSequence> void _Safe_forward_list<_SafeSequence>:: - _M_swap(_Safe_sequence_base& __other) noexcept + _M_swap(const _Safe_forward_list& __other) const noexcept { // We need to lock both sequences to swap using namespace __gnu_cxx; - __mutex *__this_mutex = &_M_this()._M_get_mutex(); - __mutex *__other_mutex = - &static_cast<_SafeSequence&>(__other)._M_get_mutex(); + __mutex *__this_mutex = &_M_this()->_M_get_mutex(); + __mutex *__other_mutex = &__other._M_get_mutex(); if (__this_mutex == __other_mutex) { __scoped_lock __lock(*__this_mutex); @@ -565,7 +564,8 @@ namespace __debug void resize(size_type __sz) { - this->_M_detach_singular(); + const forward_list* __this = this; + __this->_M_detach_singular(); // if __sz < size(), invalidate all iterators in [begin+__sz, end() _Base_iterator __victim = _Base::begin(); @@ -585,7 +585,7 @@ namespace __debug } __catch(...) { - this->_M_revalidate_singular(); + __this->_M_revalidate_singular(); __throw_exception_again; } } @@ -593,7 +593,8 @@ namespace __debug void resize(size_type __sz, const value_type& __val) { - this->_M_detach_singular(); + const forward_list* __this = this; + __this->_M_detach_singular(); // if __sz < size(), invalidate all iterators in [begin+__sz, end()) _Base_iterator __victim = _Base::begin(); @@ -613,7 +614,7 @@ namespace __debug } __catch(...) { - this->_M_revalidate_singular(); + __this->_M_revalidate_singular(); __throw_exception_again; } } diff --git a/libstdc++-v3/include/debug/list b/libstdc++-v3/include/debug/list index a9d974c40a5d..c502c7cb6e23 100644 --- a/libstdc++-v3/include/debug/list +++ b/libstdc++-v3/include/debug/list @@ -321,7 +321,8 @@ namespace __debug void resize(size_type __sz) { - this->_M_detach_singular(); + const list* __this = this; + __this->_M_detach_singular(); // if __sz < size(), invalidate all iterators in [begin + __sz, end()) _Base_iterator __victim = _Base::begin(); @@ -338,7 +339,7 @@ namespace __debug } __catch(...) { - this->_M_revalidate_singular(); + __this->_M_revalidate_singular(); __throw_exception_again; } } @@ -346,7 +347,8 @@ namespace __debug void resize(size_type __sz, const _Tp& __c) { - this->_M_detach_singular(); + const list* __this = this; + __this->_M_detach_singular(); // if __sz < size(), invalidate all iterators in [begin + __sz, end()) _Base_iterator __victim = _Base::begin(); @@ -363,7 +365,7 @@ namespace __debug } __catch(...) { - this->_M_revalidate_singular(); + __this->_M_revalidate_singular(); __throw_exception_again; } } @@ -371,7 +373,8 @@ namespace __debug void resize(size_type __sz, _Tp __c = _Tp()) { - this->_M_detach_singular(); + const list* __this = this; + __this->_M_detach_singular(); // if __sz < size(), invalidate all iterators in [begin + __sz, end()) _Base_iterator __victim = _Base::begin(); @@ -388,7 +391,7 @@ namespace __debug } __catch(...) { - this->_M_revalidate_singular(); + __this->_M_revalidate_singular(); __throw_exception_again; } } diff --git a/libstdc++-v3/include/debug/safe_base.h b/libstdc++-v3/include/debug/safe_base.h index cf3f1708ad25..44622970792b 100644 --- a/libstdc++-v3/include/debug/safe_base.h +++ b/libstdc++-v3/include/debug/safe_base.h @@ -53,8 +53,10 @@ namespace __gnu_debug public: /** The sequence this iterator references; may be NULL to indicate - a singular iterator. */ - _Safe_sequence_base* _M_sequence; + * a singular iterator. Stored as pointer-to-const because sequence + * could be declared as const. + */ + const _Safe_sequence_base* _M_sequence; /** The version number of this iterator. The sentinel value 0 is * used to indicate an invalidated iterator (i.e., one that is @@ -92,7 +94,7 @@ namespace __gnu_debug : _M_sequence(0), _M_version(0), _M_prior(0), _M_next(0) { if (!std::__is_constant_evaluated()) - this->_M_attach(const_cast<_Safe_sequence_base*>(__seq), __constant); + this->_M_attach(__seq, __constant); } /** Initializes the iterator to reference the same sequence that @@ -115,7 +117,7 @@ namespace __gnu_debug /** For use in _Safe_iterator. */ __gnu_cxx::__mutex& - _M_get_mutex() throw (); + _M_get_mutex() _GLIBCXX_USE_NOEXCEPT; /** Attaches this iterator to the given sequence, detaching it * from whatever sequence it was attached to originally. If the @@ -123,11 +125,12 @@ namespace __gnu_debug * unattached. */ void - _M_attach(_Safe_sequence_base* __seq, bool __constant); + _M_attach(const _Safe_sequence_base* __seq, bool __constant); /** Likewise, but not thread-safe. */ void - _M_attach_single(_Safe_sequence_base* __seq, bool __constant) throw (); + _M_attach_single(const _Safe_sequence_base* __seq, + bool __constant) _GLIBCXX_USE_NOEXCEPT; /** Detach the iterator for whatever sequence it is attached to, * if any. @@ -135,10 +138,23 @@ namespace __gnu_debug void _M_detach(); +#if !_GLIBCXX_INLINE_VERSION + private: + /***************************************************************/ + /** Not-const method preserved for abi backward compatibility. */ + void + _M_attach(_Safe_sequence_base* __seq, bool __constant); + + void + _M_attach_single(_Safe_sequence_base* __seq, + bool __constant) _GLIBCXX_USE_NOEXCEPT; + /***************************************************************/ +#endif + public: /** Likewise, but not thread-safe. */ void - _M_detach_single() throw (); + _M_detach_single() _GLIBCXX_USE_NOEXCEPT; /** Determines if we are attached to the given sequence. */ bool @@ -147,13 +163,13 @@ namespace __gnu_debug /** Is this iterator singular? */ _GLIBCXX_PURE bool - _M_singular() const throw (); + _M_singular() const _GLIBCXX_USE_NOEXCEPT; /** Can we compare this iterator to the given iterator @p __x? Returns true if both iterators are nonsingular and reference the same sequence. */ _GLIBCXX_PURE bool - _M_can_compare(const _Safe_iterator_base& __x) const throw (); + _M_can_compare(const _Safe_iterator_base& __x) const _GLIBCXX_USE_NOEXCEPT; /** Invalidate the iterator, making it singular. */ void @@ -162,11 +178,11 @@ namespace __gnu_debug /** Reset all member variables */ void - _M_reset() throw (); + _M_reset() _GLIBCXX_USE_NOEXCEPT; /** Unlink itself */ void - _M_unlink() throw () + _M_unlink() _GLIBCXX_USE_NOEXCEPT { if (_M_prior) _M_prior->_M_next = _M_next; @@ -246,14 +262,14 @@ namespace __gnu_debug /** Detach all iterators, leaving them singular. */ void - _M_detach_all(); + _M_detach_all() const; /** Detach all singular iterators. * @post for all iterators i attached to this sequence, * i->_M_version == _M_version. */ void - _M_detach_singular(); + _M_detach_singular() const; /** Revalidates all attached singular iterators. This method may * be used to validate iterators that were invalidated before @@ -261,7 +277,7 @@ namespace __gnu_debug * valid again). */ void - _M_revalidate_singular(); + _M_revalidate_singular() const; /** Swap this sequence with the given sequence. This operation * also swaps ownership of the iterators, so that when the @@ -269,11 +285,11 @@ namespace __gnu_debug * one container now reference the other container. */ void - _M_swap(_Safe_sequence_base& __x) _GLIBCXX_USE_NOEXCEPT; + _M_swap(const _Safe_sequence_base& __x) const _GLIBCXX_USE_NOEXCEPT; /** For use in _Safe_sequence. */ __gnu_cxx::__mutex& - _M_get_mutex() throw (); + _M_get_mutex() const _GLIBCXX_USE_NOEXCEPT; /** Invalidates all iterators. */ void @@ -281,21 +297,42 @@ namespace __gnu_debug { if (++_M_version == 0) _M_version = 1; } private: +#if !_GLIBCXX_INLINE_VERSION + /***************************************************************/ + /** Not-const method preserved for abi backward compatibility. */ + void + _M_detach_all(); + + void + _M_detach_singular(); + + void + _M_revalidate_singular(); + + void + _M_swap(_Safe_sequence_base& __x) _GLIBCXX_USE_NOEXCEPT; + + __gnu_cxx::__mutex& + _M_get_mutex() _GLIBCXX_USE_NOEXCEPT; + /***************************************************************/ +#endif + /** Attach an iterator to this sequence. */ void - _M_attach(_Safe_iterator_base* __it, bool __constant); + _M_attach(_Safe_iterator_base* __it, bool __constant) const; /** Likewise but not thread safe. */ void - _M_attach_single(_Safe_iterator_base* __it, bool __constant) throw (); + _M_attach_single(_Safe_iterator_base* __it, + bool __constant) const _GLIBCXX_USE_NOEXCEPT; /** Detach an iterator from this sequence */ void - _M_detach(_Safe_iterator_base* __it); + _M_detach(_Safe_iterator_base* __it) const; /** Likewise but not thread safe. */ void - _M_detach_single(_Safe_iterator_base* __it) throw (); + _M_detach_single(_Safe_iterator_base* __it) const _GLIBCXX_USE_NOEXCEPT; }; } // namespace __gnu_debug diff --git a/libstdc++-v3/include/debug/safe_container.h b/libstdc++-v3/include/debug/safe_container.h index cb1e69a2d697..3341806fd596 100644 --- a/libstdc++-v3/include/debug/safe_container.h +++ b/libstdc++-v3/include/debug/safe_container.h @@ -44,9 +44,9 @@ namespace __gnu_debug typedef _SafeBase<_SafeContainer> _Base; _GLIBCXX20_CONSTEXPR - _SafeContainer& - _M_cont() _GLIBCXX_NOEXCEPT - { return *static_cast<_SafeContainer*>(this); } + const _SafeContainer& + _M_cont() const _GLIBCXX_NOEXCEPT + { return *static_cast<const _SafeContainer*>(this); } protected: #if __cplusplus >= 201103L @@ -55,6 +55,11 @@ namespace __gnu_debug _Safe_container(_Safe_container&&) = default; private: + _GLIBCXX20_CONSTEXPR + void + _M_swap_base(const _Safe_container& __x) const noexcept + { _Base::_M_swap(__x); } + _GLIBCXX20_CONSTEXPR _Safe_container(_Safe_container&& __x, const _Alloc&, std::true_type) : _Safe_container(std::move(__x)) @@ -67,7 +72,7 @@ namespace __gnu_debug if (!std::__is_constant_evaluated()) { if (__x._M_cont().get_allocator() == __a) - _Base::_M_swap(__x); + _M_swap_base(__x); else __x._M_invalidate_all(); } @@ -115,12 +120,12 @@ namespace __gnu_debug bool __xfer_memory = _Alloc_traits::_S_propagate_on_move_assign() || _M_cont().get_allocator() == __x._M_cont().get_allocator(); if (__xfer_memory) - _Base::_M_swap(__x); + _M_swap_base(__x); else this->_M_invalidate_all(); } else - _Base::_M_swap(__x); + _M_swap_base(__x); __x._M_invalidate_all(); return *this; @@ -128,7 +133,7 @@ namespace __gnu_debug _GLIBCXX20_CONSTEXPR void - _M_swap(_Safe_container& __x) noexcept + _M_swap(const _Safe_container& __x) const noexcept { if (_IsCxx11AllocatorAware) { @@ -139,8 +144,12 @@ namespace __gnu_debug __x._M_cont()._M_base()); } - _Base::_M_swap(__x); + _M_swap_base(__x); } +#else + void + _M_swap(const _Safe_container& __x) const throw() + { _Base::_M_swap(__x); } #endif }; diff --git a/libstdc++-v3/include/debug/safe_iterator.h b/libstdc++-v3/include/debug/safe_iterator.h index 7c563381d0bf..e0b1b46939c3 100644 --- a/libstdc++-v3/include/debug/safe_iterator.h +++ b/libstdc++-v3/include/debug/safe_iterator.h @@ -224,7 +224,7 @@ namespace __gnu_debug _M_message(__msg_init_copy_singular) ._M_iterator(*this, "this") ._M_iterator(__x, "other")); - _Safe_sequence_base* __seq = __x._M_sequence; + const _Safe_sequence_base* __seq = __x._M_sequence; __x._M_detach(); std::swap(base(), __x.base()); _M_attach(__seq); @@ -445,12 +445,12 @@ namespace __gnu_debug /** Attach iterator to the given sequence. */ void - _M_attach(_Safe_sequence_base* __seq) + _M_attach(const _Safe_sequence_base* __seq) { _Safe_base::_M_attach(__seq, _S_constant()); } /** Likewise, but not thread-safe. */ void - _M_attach_single(_Safe_sequence_base* __seq) + _M_attach_single(const _Safe_sequence_base* __seq) { _Safe_base::_M_attach_single(__seq, _S_constant()); } /// Is the iterator dereferenceable? @@ -500,7 +500,13 @@ namespace __gnu_debug typename __gnu_cxx::__conditional_type< _IsConstant::__value, const _Sequence*, _Sequence*>::__type _M_get_sequence() const - { return static_cast<_Sequence*>(_M_sequence); } + { + // Looks like not const-correct, but if _IsConstant the constness + // is restored when returning the sequence pointer and if not + // _IsConstant we are allowed to remove constness. + return static_cast<_Sequence*> + (const_cast<_Safe_sequence_base*>(_M_sequence)); + } // Get distance to __rhs. typename _Distance_traits<_Iterator>::__type diff --git a/libstdc++-v3/include/debug/safe_local_iterator.h b/libstdc++-v3/include/debug/safe_local_iterator.h index c84f4f10093a..47b3a807a8bc 100644 --- a/libstdc++-v3/include/debug/safe_local_iterator.h +++ b/libstdc++-v3/include/debug/safe_local_iterator.h @@ -52,15 +52,15 @@ namespace __gnu_debug /** \brief Safe iterator wrapper. * * The class template %_Safe_local_iterator is a wrapper around an - * iterator that tracks the iterator's movement among sequences and - * checks that operations performed on the "safe" iterator are + * iterator that tracks the iterator's movement among unordered containers + * and checks that operations performed on the "safe" iterator are * legal. In additional to the basic iterator operations (which are * validated, and then passed to the underlying iterator), * %_Safe_local_iterator has member functions for iterator invalidation, - * attaching/detaching the iterator from sequences, and querying + * attaching/detaching the iterator from unordered containers, and querying * the iterator's state. */ - template<typename _Iterator, typename _Sequence> + template<typename _Iterator, typename _UContainer> class _Safe_local_iterator : private _Iterator , public _Safe_local_iterator_base @@ -68,28 +68,27 @@ namespace __gnu_debug typedef _Iterator _Iter_base; typedef _Safe_local_iterator_base _Safe_base; - typedef typename _Sequence::size_type size_type; + typedef typename _UContainer::size_type size_type; typedef std::iterator_traits<_Iterator> _Traits; - typedef std::__are_same< - typename _Sequence::_Base::const_local_iterator, - _Iterator> _IsConstant; + using _IsConstant = std::__are_same< + typename _UContainer::_Base::const_local_iterator, _Iterator>; - typedef typename __gnu_cxx::__conditional_type<_IsConstant::__value, - typename _Sequence::_Base::local_iterator, - typename _Sequence::_Base::const_local_iterator>::__type - _OtherIterator; + using _OtherIterator = std::__conditional_t< + _IsConstant::__value, + typename _UContainer::_Base::local_iterator, + typename _UContainer::_Base::const_local_iterator>; typedef _Safe_local_iterator _Self; - typedef _Safe_local_iterator<_OtherIterator, _Sequence> _OtherSelf; + typedef _Safe_local_iterator<_OtherIterator, _UContainer> _OtherSelf; struct _Unchecked { }; _Safe_local_iterator(const _Safe_local_iterator& __x, _Unchecked) noexcept : _Iter_base(__x.base()) - { _M_attach(__x._M_sequence); } + { _M_attach(__x._M_safe_container()); } public: typedef _Iterator iterator_type; @@ -104,12 +103,13 @@ namespace __gnu_debug /** * @brief Safe iterator construction from an unsafe iterator and - * its sequence. + * its unordered container. * - * @pre @p seq is not NULL + * @pre @p cont is not NULL * @post this is not singular */ - _Safe_local_iterator(_Iterator __i, const _Safe_sequence_base* __cont) + _Safe_local_iterator(_Iterator __i, + const _Safe_unordered_container_base* __cont) : _Iter_base(__i), _Safe_base(__cont, _S_constant()) { } @@ -126,7 +126,7 @@ namespace __gnu_debug _M_message(__msg_init_copy_singular) ._M_iterator(*this, "this") ._M_iterator(__x, "other")); - _M_attach(__x._M_sequence); + _M_attach(__x._M_safe_container()); } /** @@ -141,7 +141,7 @@ namespace __gnu_debug _M_message(__msg_init_copy_singular) ._M_iterator(*this, "this") ._M_iterator(__x, "other")); - auto __cont = __x._M_sequence; + auto __cont = __x._M_safe_container(); __x._M_detach(); std::swap(base(), __x.base()); _M_attach(__cont); @@ -156,7 +156,7 @@ namespace __gnu_debug const _Safe_local_iterator<_MutableIterator, typename __gnu_cxx::__enable_if<_IsConstant::__value && std::__are_same<_MutableIterator, _OtherIterator>::__value, - _Sequence>::__type>& __x) noexcept + _UContainer>::__type>& __x) noexcept : _Iter_base(__x.base()) { // _GLIBCXX_RESOLVE_LIB_DEFECTS @@ -166,7 +166,7 @@ namespace __gnu_debug _M_message(__msg_init_const_singular) ._M_iterator(*this, "this") ._M_iterator(__x, "other")); - _M_attach(__x._M_sequence); + _M_attach(__x._M_safe_container()); } /** @@ -193,7 +193,7 @@ namespace __gnu_debug { _M_detach(); base() = __x.base(); - _M_attach(__x._M_sequence); + _M_attach(__x._M_safe_container()); } return *this; @@ -225,7 +225,7 @@ namespace __gnu_debug { _M_detach(); base() = __x.base(); - _M_attach(__x._M_sequence); + _M_attach(__x._M_safe_container()); } __x._M_detach(); @@ -318,15 +318,15 @@ namespace __gnu_debug */ operator _Iterator() const { return *this; } - /** Attach iterator to the given sequence. */ + /** Attach iterator to the given unordered container. */ void - _M_attach(_Safe_sequence_base* __seq) - { _Safe_base::_M_attach(__seq, _S_constant()); } + _M_attach(const _Safe_unordered_container_base* __cont) + { _Safe_base::_M_attach(__cont, _S_constant()); } /** Likewise, but not thread-safe. */ void - _M_attach_single(_Safe_sequence_base* __seq) - { _Safe_base::_M_attach_single(__seq, _S_constant()); } + _M_attach_single(const _Safe_unordered_container_base* __cont) + { _Safe_base::_M_attach_single(__cont, _S_constant()); } /// Is the iterator dereferenceable? bool @@ -353,25 +353,31 @@ namespace __gnu_debug typename _Distance_traits<_Iterator>::__type _M_get_distance_to(const _Safe_local_iterator& __rhs) const; - // The sequence this iterator references. - typename __gnu_cxx::__conditional_type< - _IsConstant::__value, const _Sequence*, _Sequence*>::__type - _M_get_sequence() const - { return static_cast<_Sequence*>(_M_sequence); } + // The unordered container this iterator references. + std::__conditional_t< + _IsConstant::__value, const _UContainer*, _UContainer*> + _M_get_ucontainer() const + { + // Looks like not const-correct, but if _IsConstant the constness + // is restored when returning the container pointer and if not + // _IsConstant we are allowed to remove constness. + return static_cast<_UContainer*> + (const_cast<_Safe_unordered_container_base*>(_M_safe_container())); + } - /// Is this iterator equal to the sequence's begin(bucket) iterator? + /// Is this iterator equal to the container's begin(bucket) iterator? bool _M_is_begin() const - { return base() == _M_get_sequence()->_M_base().begin(bucket()); } + { return base() == _M_get_ucontainer()->_M_base().begin(bucket()); } - /// Is this iterator equal to the sequence's end(bucket) iterator? + /// Is this iterator equal to the container's end(bucket) iterator? bool _M_is_end() const - { return base() == _M_get_sequence()->_M_base().end(bucket()); } + { return base() == _M_get_ucontainer()->_M_base().end(bucket()); } /// Is this iterator part of the same bucket as the other one? template<typename _Other> bool _M_in_same_bucket(const _Safe_local_iterator<_Other, - _Sequence>& __other) const + _UContainer>& __other) const { return bucket() == __other.bucket(); } friend inline bool @@ -404,31 +410,31 @@ namespace __gnu_debug }; /** Safe local iterators know how to check if they form a valid range. */ - template<typename _Iterator, typename _Sequence> + template<typename _Iterator, typename _UContainer> inline bool - __valid_range(const _Safe_local_iterator<_Iterator, _Sequence>& __first, - const _Safe_local_iterator<_Iterator, _Sequence>& __last, + __valid_range(const _Safe_local_iterator<_Iterator, _UContainer>& __first, + const _Safe_local_iterator<_Iterator, _UContainer>& __last, typename _Distance_traits<_Iterator>::__type& __dist_info) { return __first._M_valid_range(__last, __dist_info); } - template<typename _Iterator, typename _Sequence> + template<typename _Iterator, typename _UContainer> inline bool - __valid_range(const _Safe_local_iterator<_Iterator, _Sequence>& __first, - const _Safe_local_iterator<_Iterator, _Sequence>& __last) + __valid_range(const _Safe_local_iterator<_Iterator, _UContainer>& __first, + const _Safe_local_iterator<_Iterator, _UContainer>& __last) { typename _Distance_traits<_Iterator>::__type __dist_info; return __first._M_valid_range(__last, __dist_info); } #if __cplusplus < 201103L - template<typename _Iterator, typename _Sequence> - struct _Unsafe_type<_Safe_local_iterator<_Iterator, _Sequence> > + template<typename _Iterator, typename _UContainer> + struct _Unsafe_type<_Safe_local_iterator<_Iterator, _UContainer> > { typedef _Iterator _Type; }; #endif - template<typename _Iterator, typename _Sequence> + template<typename _Iterator, typename _UContainer> inline _Iterator - __unsafe(const _Safe_local_iterator<_Iterator, _Sequence>& __it) + __unsafe(const _Safe_local_iterator<_Iterator, _UContainer>& __it) { return __it.base(); } } // namespace __gnu_debug diff --git a/libstdc++-v3/include/debug/safe_local_iterator.tcc b/libstdc++-v3/include/debug/safe_local_iterator.tcc index 71e532065e4f..10fec3fad4a7 100644 --- a/libstdc++-v3/include/debug/safe_local_iterator.tcc +++ b/libstdc++-v3/include/debug/safe_local_iterator.tcc @@ -44,7 +44,7 @@ namespace __gnu_debug if (__rhs._M_is_end()) return { - _M_get_sequence()->bucket_size(bucket()), + _M_get_ucontainer()->bucket_size(bucket()), __dp_exact }; @@ -56,7 +56,7 @@ namespace __gnu_debug if (__rhs._M_is_begin()) return { - -_M_get_sequence()->bucket_size(bucket()), + -_M_get_ucontainer()->bucket_size(bucket()), __dp_exact }; diff --git a/libstdc++-v3/include/debug/safe_sequence.h b/libstdc++-v3/include/debug/safe_sequence.h index 6b35afa66c63..e10474aae79c 100644 --- a/libstdc++-v3/include/debug/safe_sequence.h +++ b/libstdc++-v3/include/debug/safe_sequence.h @@ -114,7 +114,7 @@ namespace __gnu_debug in the safe ones. */ template<typename _Predicate> void - _M_invalidate_if(_Predicate __pred); + _M_invalidate_if(_Predicate __pred) const; /** Transfers all iterators @c x that reference @c from sequence, are not singular, and for which @c __pred(x) returns @c @@ -122,7 +122,8 @@ namespace __gnu_debug in the safe ones. */ template<typename _Predicate> void - _M_transfer_from_if(_Safe_sequence& __from, _Predicate __pred); + _M_transfer_from_if(const _Safe_sequence& __from, + _Predicate __pred) const; }; /// Like _Safe_sequence but with a special _M_invalidate_all implementation @@ -133,12 +134,12 @@ namespace __gnu_debug { protected: void - _M_invalidate_all() + _M_invalidate_all() const { typedef typename _Sequence::const_iterator _Const_iterator; typedef typename _Const_iterator::iterator_type _Base_const_iterator; typedef __gnu_debug::_Not_equal_to<_Base_const_iterator> _Not_equal; - const _Sequence& __seq = *static_cast<_Sequence*>(this); + const _Sequence& __seq = *static_cast<const _Sequence*>(this); this->_M_invalidate_if(_Not_equal(__seq._M_base().end())); } }; diff --git a/libstdc++-v3/include/debug/safe_sequence.tcc b/libstdc++-v3/include/debug/safe_sequence.tcc index 336bf2a0b2b6..053361dff3c0 100644 --- a/libstdc++-v3/include/debug/safe_sequence.tcc +++ b/libstdc++-v3/include/debug/safe_sequence.tcc @@ -35,7 +35,7 @@ namespace __gnu_debug template<typename _Predicate> void _Safe_sequence<_Sequence>:: - _M_invalidate_if(_Predicate __pred) + _M_invalidate_if(_Predicate __pred) const { typedef typename _Sequence::iterator iterator; typedef typename _Sequence::const_iterator const_iterator; @@ -66,7 +66,7 @@ namespace __gnu_debug template<typename _Predicate> void _Safe_sequence<_Sequence>:: - _M_transfer_from_if(_Safe_sequence& __from, _Predicate __pred) + _M_transfer_from_if(const _Safe_sequence& __from, _Predicate __pred) const { if (this == std::__addressof(__from)) return; @@ -104,7 +104,7 @@ namespace __gnu_debug } for (_Safe_iterator_base* __iter2 = __from._M_const_iterators; - __iter2;) + __iter2;) { _Safe_iterator_base* __victim_base = __iter2; const_iterator* __victim = diff --git a/libstdc++-v3/include/debug/safe_unordered_base.h b/libstdc++-v3/include/debug/safe_unordered_base.h index 1547f5b7b9d5..55cf581e315e 100644 --- a/libstdc++-v3/include/debug/safe_unordered_base.h +++ b/libstdc++-v3/include/debug/safe_unordered_base.h @@ -49,6 +49,10 @@ namespace __gnu_debug */ class _Safe_local_iterator_base : public _Safe_iterator_base { + public: + const _Safe_unordered_container_base* + _M_safe_container() const noexcept; + protected: /** Initializes the iterator and makes it singular. */ _Safe_local_iterator_base() @@ -61,32 +65,32 @@ namespace __gnu_debug * singular. Otherwise, the iterator will reference @p __seq and * be nonsingular. */ - _Safe_local_iterator_base(const _Safe_sequence_base* __seq, bool __constant) - { this->_M_attach(const_cast<_Safe_sequence_base*>(__seq), __constant); } + _Safe_local_iterator_base(const _Safe_unordered_container_base* __seq, + bool __constant) + { _M_attach(__seq, __constant); } /** Initializes the iterator to reference the same container that @p __x does. @p __constant is true if this is a constant iterator, and false if it is mutable. */ _Safe_local_iterator_base(const _Safe_local_iterator_base& __x, bool __constant) - { this->_M_attach(__x._M_sequence, __constant); } + { this->_M_attach(__x._M_safe_container(), __constant); } ~_Safe_local_iterator_base() { this->_M_detach(); } - _Safe_unordered_container_base* - _M_get_container() const noexcept; - /** Attaches this iterator to the given container, detaching it * from whatever container it was attached to originally. If the * new container is the NULL pointer, the iterator is left * unattached. */ void - _M_attach(_Safe_sequence_base* __seq, bool __constant); + _M_attach(const _Safe_unordered_container_base* __cont, + bool __constant); /** Likewise, but not thread-safe. */ void - _M_attach_single(_Safe_sequence_base* __seq, bool __constant) throw (); + _M_attach_single(const _Safe_unordered_container_base* __cont, + bool __constant) noexcept; /** Detach the iterator for whatever container it is attached to, * if any. @@ -96,7 +100,19 @@ namespace __gnu_debug /** Likewise, but not thread-safe. */ void - _M_detach_single() throw (); + _M_detach_single() noexcept; + +#if !_GLIBCXX_INLINE_VERSION + private: + /***************************************************************/ + /** Not-const method preserved for abi backward compatibility. */ + void + _M_attach(_Safe_sequence_base* __seq, bool __constant); + + void + _M_attach_single(_Safe_sequence_base* __seq, bool __constant) noexcept; + /***************************************************************/ +#endif }; /** @@ -124,10 +140,10 @@ namespace __gnu_debug public: /// The list of mutable local iterators that reference this container - _Safe_iterator_base* _M_local_iterators; + mutable _Safe_iterator_base* _M_local_iterators; /// The list of constant local iterators that reference this container - _Safe_iterator_base* _M_const_local_iterators; + mutable _Safe_iterator_base* _M_const_local_iterators; protected: // Initialize with a version number of 1 and no iterators @@ -153,7 +169,7 @@ namespace __gnu_debug /** Detach all iterators, leaving them singular. */ void - _M_detach_all(); + _M_detach_all() const; /** Swap this container with the given container. This operation * also swaps ownership of the iterators, so that when the @@ -161,25 +177,42 @@ namespace __gnu_debug * one container now reference the other container. */ void - _M_swap(_Safe_unordered_container_base& __x) noexcept; + _M_swap(const _Safe_unordered_container_base& __x) const noexcept; private: +#if !_GLIBCXX_INLINE_VERSION + /***************************************************************/ + /** Not-const method preserved for abi backward compatibility. */ + void + _M_detach_all(); + + void + _M_swap(_Safe_unordered_container_base& __x) noexcept; + /***************************************************************/ +#endif + /** Attach an iterator to this container. */ void - _M_attach_local(_Safe_iterator_base* __it, bool __constant); + _M_attach_local(_Safe_iterator_base* __it, bool __constant) const; /** Likewise but not thread safe. */ void - _M_attach_local_single(_Safe_iterator_base* __it, bool __constant) throw (); + _M_attach_local_single(_Safe_iterator_base* __it, + bool __constant) const noexcept; /** Detach an iterator from this container */ void - _M_detach_local(_Safe_iterator_base* __it); + _M_detach_local(_Safe_iterator_base* __it) const; /** Likewise but not thread safe. */ void - _M_detach_local_single(_Safe_iterator_base* __it) throw (); + _M_detach_local_single(_Safe_iterator_base* __it) const noexcept; }; + + inline const _Safe_unordered_container_base* + _Safe_local_iterator_base:: + _M_safe_container() const noexcept + { return static_cast<const _Safe_unordered_container_base*>(_M_sequence); } } // namespace __gnu_debug #endif diff --git a/libstdc++-v3/include/debug/safe_unordered_container.h b/libstdc++-v3/include/debug/safe_unordered_container.h index 2ba27dbbecbb..b67b7e06b2fc 100644 --- a/libstdc++-v3/include/debug/safe_unordered_container.h +++ b/libstdc++-v3/include/debug/safe_unordered_container.h @@ -62,6 +62,10 @@ namespace __gnu_debug _M_cont() noexcept { return *static_cast<_Container*>(this); } + const _Safe_unordered_container* + _M_self() const + { return this; } + protected: void _M_invalidate_locals() diff --git a/libstdc++-v3/include/debug/safe_unordered_container.tcc b/libstdc++-v3/include/debug/safe_unordered_container.tcc index 68193891b01d..0732e6374bfc 100644 --- a/libstdc++-v3/include/debug/safe_unordered_container.tcc +++ b/libstdc++-v3/include/debug/safe_unordered_container.tcc @@ -40,7 +40,7 @@ namespace __gnu_debug typedef typename _Container::iterator iterator; typedef typename _Container::const_iterator const_iterator; - __gnu_cxx::__scoped_lock sentry(this->_M_get_mutex()); + __gnu_cxx::__scoped_lock sentry(_M_self()->_M_get_mutex()); for (_Safe_iterator_base* __iter = _M_iterators; __iter;) { iterator* __victim = static_cast<iterator*>(__iter); @@ -72,7 +72,7 @@ namespace __gnu_debug typedef typename _Container::local_iterator local_iterator; typedef typename _Container::const_local_iterator const_local_iterator; - __gnu_cxx::__scoped_lock sentry(this->_M_get_mutex()); + __gnu_cxx::__scoped_lock sentry(_M_self()->_M_get_mutex()); for (_Safe_iterator_base* __iter = _M_local_iterators; __iter;) { local_iterator* __victim = static_cast<local_iterator*>(__iter); diff --git a/libstdc++-v3/src/c++11/debug.cc b/libstdc++-v3/src/c++11/debug.cc index 3533b5e1df12..c6f6ef7ecb74 100644 --- a/libstdc++-v3/src/c++11/debug.cc +++ b/libstdc++-v3/src/c++11/debug.cc @@ -54,7 +54,7 @@ namespace * in order to limit contention without breaking current library binary * compatibility. */ __gnu_cxx::__mutex& - get_safe_base_mutex(void* address) + get_safe_base_mutex(const void* address) { // Use arbitrarily __gnu_debug::vector<int> as the container giving // alignment of debug containers. @@ -70,9 +70,9 @@ namespace #pragma GCC diagnostic warning "-Wabi=6" void - swap_its(__gnu_debug::_Safe_sequence_base& __lhs, + swap_its(const __gnu_debug::_Safe_sequence_base& __lhs, __gnu_debug::_Safe_iterator_base*& __lhs_its, - __gnu_debug::_Safe_sequence_base& __rhs, + const __gnu_debug::_Safe_sequence_base& __rhs, __gnu_debug::_Safe_iterator_base*& __rhs_its) { swap(__lhs_its, __rhs_its); @@ -84,8 +84,8 @@ namespace } void - swap_seq_single(__gnu_debug::_Safe_sequence_base& __lhs, - __gnu_debug::_Safe_sequence_base& __rhs) + swap_seq_single(const __gnu_debug::_Safe_sequence_base& __lhs, + const __gnu_debug::_Safe_sequence_base& __rhs) { swap(__lhs._M_version, __rhs._M_version); swap_its(__lhs, __lhs._M_iterators, @@ -118,17 +118,17 @@ namespace void swap_seq(__gnu_cxx::__mutex& lhs_mutex, - __gnu_debug::_Safe_sequence_base& lhs, + const __gnu_debug::_Safe_sequence_base& lhs, __gnu_cxx::__mutex& rhs_mutex, - __gnu_debug::_Safe_sequence_base& rhs) + const __gnu_debug::_Safe_sequence_base& rhs) { lock_and_run(lhs_mutex, rhs_mutex, [&lhs, &rhs]() { swap_seq_single(lhs, rhs); }); } void - swap_ucont_single(__gnu_debug::_Safe_unordered_container_base& __lhs, - __gnu_debug::_Safe_unordered_container_base& __rhs) + swap_ucont_single(const __gnu_debug::_Safe_unordered_container_base& __lhs, + const __gnu_debug::_Safe_unordered_container_base& __rhs) { swap_seq_single(__lhs, __rhs); swap_its(__lhs, __lhs._M_local_iterators, @@ -139,9 +139,9 @@ namespace void swap_ucont(__gnu_cxx::__mutex& lhs_mutex, - __gnu_debug::_Safe_unordered_container_base& lhs, + const __gnu_debug::_Safe_unordered_container_base& lhs, __gnu_cxx::__mutex& rhs_mutex, - __gnu_debug::_Safe_unordered_container_base& rhs) + const __gnu_debug::_Safe_unordered_container_base& rhs) { lock_and_run(lhs_mutex, rhs_mutex, [&lhs, &rhs]() { swap_ucont_single(lhs, rhs); }); @@ -158,8 +158,8 @@ namespace } } - void* - acquire_sequence_ptr_for_lock(__gnu_debug::_Safe_sequence_base*& seq) + const void* + acquire_sequence_ptr_for_lock(__gnu_debug::_Safe_sequence_base const*& seq) { #ifdef __GTHREADS if (!__gnu_cxx::__is_single_threaded()) @@ -169,7 +169,7 @@ namespace } void - reset_sequence_ptr(__gnu_debug::_Safe_sequence_base*& seq) + reset_sequence_ptr(__gnu_debug::_Safe_sequence_base const*& seq) { #ifdef __GTHREADS if (!__gnu_cxx::__is_single_threaded()) @@ -327,7 +327,7 @@ namespace __gnu_debug void _Safe_sequence_base:: - _M_detach_all() + _M_detach_all() const { __gnu_cxx::__scoped_lock sentry(_M_get_mutex()); detach_all(_M_iterators); @@ -339,7 +339,7 @@ namespace __gnu_debug void _Safe_sequence_base:: - _M_detach_singular() + _M_detach_singular() const { __gnu_cxx::__scoped_lock sentry(_M_get_mutex()); for (_Safe_iterator_base* __iter = _M_iterators; __iter;) @@ -361,7 +361,7 @@ namespace __gnu_debug void _Safe_sequence_base:: - _M_revalidate_singular() + _M_revalidate_singular() const { __gnu_cxx::__scoped_lock sentry(_M_get_mutex()); for (_Safe_iterator_base* __iter = _M_iterators; __iter; @@ -375,17 +375,59 @@ namespace __gnu_debug void _Safe_sequence_base:: - _M_swap(_Safe_sequence_base& __x) noexcept + _M_swap(const _Safe_sequence_base& __x) const noexcept { swap_seq(_M_get_mutex(), *this, __x._M_get_mutex(), __x); } __gnu_cxx::__mutex& _Safe_sequence_base:: - _M_get_mutex() noexcept + _M_get_mutex() const noexcept { return get_safe_base_mutex(this); } +#if !_GLIBCXX_INLINE_VERSION + void + _Safe_sequence_base:: + _M_detach_all() + { + const _Safe_sequence_base* __this = this; + __this->_M_detach_all(); + } + + void + _Safe_sequence_base:: + _M_detach_singular() + { + const _Safe_sequence_base* __this = this; + __this->_M_detach_singular(); + } + + void + _Safe_sequence_base:: + _M_revalidate_singular() + { + const _Safe_sequence_base* __this = this; + __this->_M_revalidate_singular(); + } + void _Safe_sequence_base:: - _M_attach(_Safe_iterator_base* __it, bool __constant) + _M_swap(_Safe_sequence_base& __x) noexcept + { + const _Safe_sequence_base* __this = this; + __this->_M_swap(__x); + } + + __gnu_cxx::__mutex& + _Safe_sequence_base:: + _M_get_mutex() noexcept + { + const _Safe_sequence_base* __this = this; + return __this->_M_get_mutex(); + } +#endif + + void + _Safe_sequence_base:: + _M_attach(_Safe_iterator_base* __it, bool __constant) const { __gnu_cxx::__scoped_lock sentry(_M_get_mutex()); _M_attach_single(__it, __constant); @@ -393,7 +435,7 @@ namespace __gnu_debug void _Safe_sequence_base:: - _M_attach_single(_Safe_iterator_base* __it, bool __constant) noexcept + _M_attach_single(_Safe_iterator_base* __it, bool __constant) const noexcept { _Safe_iterator_base*& __its = __constant ? _M_const_iterators : _M_iterators; @@ -405,7 +447,7 @@ namespace __gnu_debug void _Safe_sequence_base:: - _M_detach(_Safe_iterator_base* __it) + _M_detach(_Safe_iterator_base* __it) const { // Remove __it from this sequence's list __gnu_cxx::__scoped_lock sentry(_M_get_mutex()); @@ -414,7 +456,7 @@ namespace __gnu_debug void _Safe_sequence_base:: - _M_detach_single(_Safe_iterator_base* __it) noexcept + _M_detach_single(_Safe_iterator_base* __it) const noexcept { // Remove __it from this sequence's list __it->_M_unlink(); @@ -426,7 +468,7 @@ namespace __gnu_debug void _Safe_iterator_base:: - _M_attach(_Safe_sequence_base* __seq, bool __constant) + _M_attach(const _Safe_sequence_base* __seq, bool __constant) { _M_detach(); @@ -443,7 +485,7 @@ namespace __gnu_debug void _Safe_iterator_base:: - _M_attach_single(_Safe_sequence_base* __seq, bool __constant) noexcept + _M_attach_single(const _Safe_sequence_base* __seq, bool __constant) noexcept { _M_detach_single(); @@ -514,14 +556,27 @@ namespace __gnu_debug _M_get_mutex() noexcept { return _M_sequence->_M_get_mutex(); } - _Safe_unordered_container_base* - _Safe_local_iterator_base:: - _M_get_container() const noexcept - { return static_cast<_Safe_unordered_container_base*>(_M_sequence); } +#if !_GLIBCXX_INLINE_VERSION + void + _Safe_iterator_base:: + _M_attach(_Safe_sequence_base* __seq, bool __constant) + { + const _Safe_sequence_base* __cseq = __seq; + _M_attach(__cseq, __constant); + } + + void + _Safe_iterator_base:: + _M_attach_single(_Safe_sequence_base* __seq, bool __constant) noexcept + { + const _Safe_sequence_base* __cseq = __seq; + _M_attach_single(__cseq, __constant); + } +#endif void _Safe_local_iterator_base:: - _M_attach(_Safe_sequence_base* __cont, bool __constant) + _M_attach(const _Safe_unordered_container_base* __cont, bool __constant) { _M_detach(); @@ -530,7 +585,7 @@ namespace __gnu_debug { _M_sequence = __cont; _M_version = _M_sequence->_M_version; - _M_get_container()->_M_attach_local(this, __constant); + _M_safe_container()->_M_attach_local(this, __constant); } else _M_version = 0; @@ -538,7 +593,8 @@ namespace __gnu_debug void _Safe_local_iterator_base:: - _M_attach_single(_Safe_sequence_base* __cont, bool __constant) noexcept + _M_attach_single(const _Safe_unordered_container_base* __cont, + bool __constant) noexcept { _M_detach_single(); @@ -547,7 +603,7 @@ namespace __gnu_debug { _M_sequence = __cont; _M_version = _M_sequence->_M_version; - _M_get_container()->_M_attach_local_single(this, __constant); + _M_safe_container()->_M_attach_local_single(this, __constant); } else _M_version = 0; @@ -570,14 +626,34 @@ namespace __gnu_debug { if (_M_sequence) { - _M_get_container()->_M_detach_local_single(this); + _M_safe_container()->_M_detach_local_single(this); _M_reset(); } } +#if !_GLIBCXX_INLINE_VERSION + void + _Safe_local_iterator_base:: + _M_attach(_Safe_sequence_base* __seq, bool __constant) + { + const _Safe_unordered_container_base* __cont + = static_cast<_Safe_unordered_container_base*>(__seq); + _M_attach(__cont, __constant); + } + + void + _Safe_local_iterator_base:: + _M_attach_single(_Safe_sequence_base* __seq, bool __constant) noexcept + { + const _Safe_unordered_container_base* __cont + = static_cast<_Safe_unordered_container_base*>(__seq); + _M_attach_single(__cont, __constant); + } +#endif + void _Safe_unordered_container_base:: - _M_detach_all() + _M_detach_all() const { __gnu_cxx::__scoped_lock sentry(_M_get_mutex()); detach_all(_M_iterators); @@ -595,12 +671,12 @@ namespace __gnu_debug void _Safe_unordered_container_base:: - _M_swap(_Safe_unordered_container_base& __x) noexcept + _M_swap(const _Safe_unordered_container_base& __x) const noexcept { swap_ucont(_M_get_mutex(), *this, __x._M_get_mutex(), __x); } void _Safe_unordered_container_base:: - _M_attach_local(_Safe_iterator_base* __it, bool __constant) + _M_attach_local(_Safe_iterator_base* __it, bool __constant) const { __gnu_cxx::__scoped_lock sentry(_M_get_mutex()); _M_attach_local_single(__it, __constant); @@ -608,7 +684,7 @@ namespace __gnu_debug void _Safe_unordered_container_base:: - _M_attach_local_single(_Safe_iterator_base* __it, bool __constant) noexcept + _M_attach_local_single(_Safe_iterator_base* __it, bool __constant) const noexcept { _Safe_iterator_base*& __its = __constant ? _M_const_local_iterators : _M_local_iterators; @@ -620,7 +696,7 @@ namespace __gnu_debug void _Safe_unordered_container_base:: - _M_detach_local(_Safe_iterator_base* __it) + _M_detach_local(_Safe_iterator_base* __it) const { // Remove __it from this container's list __gnu_cxx::__scoped_lock sentry(_M_get_mutex()); @@ -629,7 +705,7 @@ namespace __gnu_debug void _Safe_unordered_container_base:: - _M_detach_local_single(_Safe_iterator_base* __it) noexcept + _M_detach_local_single(_Safe_iterator_base* __it) const noexcept { // Remove __it from this container's list __it->_M_unlink(); @@ -638,6 +714,24 @@ namespace __gnu_debug if (_M_local_iterators == __it) _M_local_iterators = __it->_M_next; } + +#if !_GLIBCXX_INLINE_VERSION + void + _Safe_unordered_container_base:: + _M_detach_all() + { + const _Safe_unordered_container_base* __this = this; + __this->_M_detach_all(); + } + + void + _Safe_unordered_container_base:: + _M_swap(_Safe_unordered_container_base& __x) noexcept + { + const _Safe_unordered_container_base* __this = this; + __this->_M_swap(__x); + } +#endif } namespace diff --git a/libstdc++-v3/testsuite/23_containers/unordered_map/const_container.cc b/libstdc++-v3/testsuite/23_containers/unordered_map/const_container.cc new file mode 100644 index 000000000000..e62f15822018 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/unordered_map/const_container.cc @@ -0,0 +1,19 @@ +// { dg-do compile { target c++11 } } + +#include <unordered_map> + +#include <testsuite_hooks.h> + +// PR c++/116369 +const std::unordered_map<int, int> um + { + { 0, 1 }, + { 2, 3 }, + { 4, 5 } + }; + +int main() +{ + VERIFY( um.size() == 3 ); + VERIFY( um.find(0) != um.end() ); +} diff --git a/libstdc++-v3/testsuite/23_containers/unordered_multimap/const_container.cc b/libstdc++-v3/testsuite/23_containers/unordered_multimap/const_container.cc new file mode 100644 index 000000000000..3da1e3327a53 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/unordered_multimap/const_container.cc @@ -0,0 +1,22 @@ +// { dg-do compile { target c++11 } } + +#include <unordered_map> + +#include <testsuite_hooks.h> + +// PR c++/116369 +const std::unordered_multimap<int, int> umm + { + { 0, 1 }, + { 0, 1 }, + { 2, 3 }, + { 2, 3 }, + { 4, 5 }, + { 4, 5 } + }; + +int main() +{ + VERIFY( umm.size() == 6 ); + VERIFY( umm.find(0) != umm.end() ); +} diff --git a/libstdc++-v3/testsuite/23_containers/unordered_multiset/const_container.cc b/libstdc++-v3/testsuite/23_containers/unordered_multiset/const_container.cc new file mode 100644 index 000000000000..841d25a2e62b --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/unordered_multiset/const_container.cc @@ -0,0 +1,15 @@ +// { dg-do compile { target c++11 } } + +#include <unordered_set> + +#include <testsuite_hooks.h> + +// PR c++/116369 +const std::unordered_multiset<int> ums + { 0, 0, 1, 1, 2, 2 }; + +int main() +{ + VERIFY( ums.size() == 6 ); + VERIFY( ums.find(0) != ums.end() ); +} diff --git a/libstdc++-v3/testsuite/23_containers/unordered_set/const_container.cc b/libstdc++-v3/testsuite/23_containers/unordered_set/const_container.cc new file mode 100644 index 000000000000..ffdbbad57842 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/unordered_set/const_container.cc @@ -0,0 +1,14 @@ +// { dg-do compile { target c++11 } } + +#include <unordered_set> + +#include <testsuite_hooks.h> + +// PR c++/116369 +const std::unordered_set<int> us { 0, 1, 2 }; + +int main() +{ + VERIFY( us.size() == 3 ); + VERIFY( us.find(0) != us.end() ); +} diff --git a/libstdc++-v3/testsuite/23_containers/vector/debug/mutex_association.cc b/libstdc++-v3/testsuite/23_containers/vector/debug/mutex_association.cc index ba2ede04447e..792ed455e2c6 100644 --- a/libstdc++-v3/testsuite/23_containers/vector/debug/mutex_association.cc +++ b/libstdc++-v3/testsuite/23_containers/vector/debug/mutex_association.cc @@ -25,7 +25,7 @@ class container : public __gnu_debug::_Safe_sequence<container> { public: __gnu_cxx::__mutex& - get_mutex() + get_mutex() const { return this->_M_get_mutex(); } }; diff --git a/libstdc++-v3/testsuite/util/testsuite_containers.h b/libstdc++-v3/testsuite/util/testsuite_containers.h index 37491a405dc0..ab0107f79e44 100644 --- a/libstdc++-v3/testsuite/util/testsuite_containers.h +++ b/libstdc++-v3/testsuite/util/testsuite_containers.h @@ -210,6 +210,9 @@ namespace __gnu_test clit = container.cbegin(bn); assert( ++clit == container.cend(bn) ); + clit = container.begin(bn); + assert( ++clit == container.cend(bn) ); + assert( container.begin(bn) != container.cend(bn) ); } }; @@ -304,6 +307,9 @@ namespace __gnu_test assert( container.cbegin() != container.cend() ); assert( container.cbegin() != container.end() ); assert( container.begin() != container.cend() ); + + auto cit = container.begin(); + assert( cit == container.cbegin() ); } };