]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
libstdc++: Make debug iterator pointer sequence const [PR116369]
authorFrançois Dumont <frs.dumont@gmail.com>
Thu, 27 Mar 2025 18:02:59 +0000 (19:02 +0100)
committerFrançois Dumont <fdumont@gcc.gnu.org>
Tue, 8 Jul 2025 05:04:00 +0000 (07:04 +0200)
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.

23 files changed:
libstdc++-v3/config/abi/pre/gnu-versioned-namespace.ver
libstdc++-v3/config/abi/pre/gnu.ver
libstdc++-v3/include/debug/deque
libstdc++-v3/include/debug/formatter.h
libstdc++-v3/include/debug/forward_list
libstdc++-v3/include/debug/list
libstdc++-v3/include/debug/safe_base.h
libstdc++-v3/include/debug/safe_container.h
libstdc++-v3/include/debug/safe_iterator.h
libstdc++-v3/include/debug/safe_local_iterator.h
libstdc++-v3/include/debug/safe_local_iterator.tcc
libstdc++-v3/include/debug/safe_sequence.h
libstdc++-v3/include/debug/safe_sequence.tcc
libstdc++-v3/include/debug/safe_unordered_base.h
libstdc++-v3/include/debug/safe_unordered_container.h
libstdc++-v3/include/debug/safe_unordered_container.tcc
libstdc++-v3/src/c++11/debug.cc
libstdc++-v3/testsuite/23_containers/unordered_map/const_container.cc [new file with mode: 0644]
libstdc++-v3/testsuite/23_containers/unordered_multimap/const_container.cc [new file with mode: 0644]
libstdc++-v3/testsuite/23_containers/unordered_multiset/const_container.cc [new file with mode: 0644]
libstdc++-v3/testsuite/23_containers/unordered_set/const_container.cc [new file with mode: 0644]
libstdc++-v3/testsuite/23_containers/vector/debug/mutex_association.cc
libstdc++-v3/testsuite/util/testsuite_containers.h

index 2818ab3561f95e2213909ead37d622befe09bbde..1c423ff2f572fdba85fa5bebbcdf04c734fa32de 100644 (file)
@@ -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;
index 73b6f338613e8cf8a2ba7306778cf9d9b6630d72..b5a89c31e0eb152c5ce898c7477897074d924e25 100644 (file)
@@ -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.
index 59d60b2120dbe1b9e26dd9df1ab61f8a953ab9ff..ed69eb842e2bc31d10724006f7eaabf0669ed217 100644 (file)
@@ -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;
              }
          }
index d80e8a78dcb43895651a9db1e8454a2f2120567b..8aa84adec77854cdb6c0fbb0b717ba4f8919e490 100644 (file)
@@ -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())
            {
index 60a254297d543897abeb22e5d67dfe1470887ced..4e1511da4e826ce20477abd93304b1e2fdd6e1d3 100644 (file)
@@ -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;
          }
       }
index a9d974c40a5d575ce3a815afbdea64a2ca2565b1..c502c7cb6e23bd03d84b0fbbb98e1429e622aa1a 100644 (file)
@@ -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;
          }
       }
index cf3f1708ad25251e589b6df4d8840064b7cac054..44622970792b3255d2bcb5126200a97ed1f053a9 100644 (file)
@@ -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
 
index cb1e69a2d6974993b0eafbcec47d13b295de4ace..3341806fd596f841421b94b3c8f474d2ba52d427 100644 (file)
@@ -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
     };
 
index 7c563381d0bff85886ffe884ac5fc9c60faff1b7..e0b1b46939c3c3f45a30d6cc70790729e4f929a3 100644 (file)
@@ -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
index c84f4f10093ad97ba15bde506eb8d152aa869455..47b3a807a8bc17d5be6ce16104d254cb3190ef7b 100644 (file)
@@ -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
index 71e532065e4f22995ef5e1434254ea77ce0e9ed0..10fec3fad4a7a22443c6f486615b423f87c2f6e0 100644 (file)
@@ -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
              };
 
index 6b35afa66c63a3b1aaf95966f19853c93502b5d9..e10474aae79ca74b4202cda093e2bf42341b23b7 100644 (file)
@@ -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()));
       }
     };
index 336bf2a0b2b6f6a37dc292291013c8a877e0d771..053361dff3c058c3a6779b2d64a35f2b9618cbef 100644 (file)
@@ -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 =
index 1547f5b7b9d592167b272002a6cc15efd1411eb6..55cf581e315e3ca4ba920ddc0d243dac6295f622 100644 (file)
@@ -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
index 2ba27dbbecbb49ed841b789975b3e5f73333ee5d..b67b7e06b2fc69dcddd3ad6688f83cd8b4a5c76b 100644 (file)
@@ -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()
index 68193891b01dc5ac1c97d34760f25c14964bb0ae..0732e6374bfc214ec18745c4b6850615c0724dbd 100644 (file)
@@ -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);
index 3533b5e1df126dd57f5aa605ccbb42b98f3a1014..c6f6ef7ecb744a803c9c8f13d0c02c4e6afe101c 100644 (file)
@@ -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 (file)
index 0000000..e62f158
--- /dev/null
@@ -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 (file)
index 0000000..3da1e33
--- /dev/null
@@ -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 (file)
index 0000000..841d25a
--- /dev/null
@@ -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 (file)
index 0000000..ffdbbad
--- /dev/null
@@ -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() );
+}
index ba2ede04447ea0730afe0c2da706adf8cad16a97..792ed455e2c6b80854fcadf55bf31682b12d840e 100644 (file)
@@ -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(); }
 };
 
index 37491a405dc01ec2640d229fa796a7813b7d71df..ab0107f79e449c950c987fb601dd78f97ab71164 100644 (file)
@@ -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() );
       }
   };