Here is a new attempt preserving symbols.

    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. The     new const methods are calling the latter thanks to a safe use of const_cast.

    libstdc++-v3/ChangeLog:

            PR c++/116369
            * 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_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.
            (_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.

Tested under Linux x86_64.

Ok to commit ?

François


On 26/05/2025 19:07, François Dumont wrote:

Ok, I'll give it another try.

Trying to use the same approach for targets using gnu.ver and others thought, seems more reasonable to me.

François


On 22/05/2025 09:28, Jonathan Wakely wrote:


On Thu, 22 May 2025, 08:26 Jonathan Wakely, <jwakely....@gmail.com> wrote:



    On Thu, 15 May 2025, 06:26 François Dumont,
    <frs.dum...@gmail.com> wrote:

        Got

        On 14/05/2025 18:46, Jonathan Wakely wrote:
        > On Wed, 14 May 2025 at 17:31, François Dumont
        <frs.dum...@gmail.com> wrote:
        >> On 12/05/2025 23:03, Jonathan Wakely wrote:
        >>> On 31/03/25 22:20 +0200, François Dumont wrote:
        >>>> Hi
        >>>>
        >>>> Following this previous patch
        >>>>
        https://gcc.gnu.org/pipermail/libstdc++/2024-August/059418.html
        I've
        >>>> completed it for the _Safe_unordered_container_base type and
        >>>> implemented the rest of the change to store the safe
        iterator
        >>>> sequence as a pointer-to-const.
        >>>>
        >>>>      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.
        >>>>      Symbols export are maintained thanks to __asm
        directives.
        >>>>
        >>> I can't compile this, it seems to be missing changes to
        >>> safe_local_iterator.tcc:
        >>>
        >>> In file included from
        >>>
        
/home/jwakely/src/gcc/build/x86_64-pc-linux-gnu/libstdc++-v3/include/debug/safe_local_iterator.h:444,
        >>>                   from
        >>> /home/jwakely/src/gcc/gcc/libstdc++-v3/src/c++11/debug.cc:33:
        >>>
        
/home/jwakely/src/gcc/build/x86_64-pc-linux-gnu/libstdc++-v3/include/debug/safe_local_iterator.tcc:
        >>> In member function ‘typename
        >>> __gnu_debug::_Distance_traits<_Iterator>::__type
        >>> __gnu_debug::_Safe_local_iterator<_Iterator,
        >>> _Sequence>::_M_get_distance_to(const
        >>> __gnu_debug::_Safe_local_iterator<_Iterator, _Sequence>&)
        const’:
        >>>
        
/home/jwakely/src/gcc/build/x86_64-pc-linux-gnu/libstdc++-v3/include/debug/safe_local_iterator.tcc:47:17:
        >>> error: there are no arguments to ‘_M_get_sequence’ that
        depend on a
        >>> template parameter, so a declaration of ‘_M_get_sequence’
        must be
        >>> available [-Wtemplate-body]
        >>>     47 | _M_get_sequence()->bucket_size(bucket()),
        >>>        |  ^~~~~~~~~~~~~~~
        >>>
        
/home/jwakely/src/gcc/build/x86_64-pc-linux-gnu/libstdc++-v3/include/debug/safe_local_iterator.tcc:47:17:
        >>> note: (if you use ‘-fpermissive’, G++ will accept your
        code, but
        >>> allowing the use of an undeclared name is deprecated)
        >>>
        
/home/jwakely/src/gcc/build/x86_64-pc-linux-gnu/libstdc++-v3/include/debug/safe_local_iterator.tcc:59:18:
        >>> error: there are no arguments to ‘_M_get_sequence’ that
        depend on a
        >>> template parameter, so a declaration of ‘_M_get_sequence’
        must be
        >>> available [-Wtemplate-body]
        >>>     59 | -_M_get_sequence()->bucket_size(bucket()),
        >>>        | ^~~~~~~~~~~~~~~
        >>>
        >> Yes, sorry, I had already spotted this problem, but only
        updated the PR
        >> and not re-sending patch here.
        >>
        >>
        >>>> Also available as a PR
        >>>>
        >>>> https://forge.sourceware.org/gcc/gcc-TEST/pulls/47
        >>>>
        >>>>      /** 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
        >>>> +
        __asm("_ZN11__gnu_debug19_Safe_sequence_base18_M_detach_singularEv");
        >>> Does this work on all targets?
        >> No idea ! I thought the symbol name used here just had to
        match the
        >> entries in config/abi/pre/gnu.ver.
        > That linker script is not used for all targets.

        Ok, got it, I only need to use this when symbol versioning is
        activated.


    I don't think that's right. For targets that don't use gnu.ver we
    still want to preserve the same symbols. They just aren't
    versioned on those targets.
    And e.g. Solaris uses versioning, but a different format, not
    gnu.ver, and I don't remember it the same macro is defined.

    Isn't it possible to do this without asm somehow? At least as a
    fallback for targets that don't use gnu.ver


Basically this needs more research, and then testing on other targets.





        I think this new patch should do it if so.

        François
diff --git a/libstdc++-v3/include/debug/deque b/libstdc++-v3/include/debug/deque
index 59d60b2120d..ed69eb842e2 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 d80e8a78dcb..8aa84adec77 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 60a254297d5..29be0665e11 100644
--- a/libstdc++-v3/include/debug/forward_list
+++ b/libstdc++-v3/include/debug/forward_list
@@ -58,21 +58,21 @@ 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());
        this->_M_invalidate_if([this](_Base_const_iterator __it)
@@ -81,21 +81,21 @@ namespace __gnu_debug
            && __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);
       // Useless, always 1 on forward_list
-      //std::swap(_M_this()_M_version, __other._M_version);
+      //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,
+      _S_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,
+      _S_swap_aux(__other, __other._M_const_iterators,
                  _M_this(), _M_this()._M_const_iterators);
-      _M_swap_aux(_M_this(), __this_its,
+      _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 *__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 a9d974c40a5..c502c7cb6e2 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 cf3f1708ad2..56a73739ab5 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
@@ -123,11 +125,13 @@ namespace __gnu_debug
      * unattached.
      */
     void
-    _M_attach(_Safe_sequence_base* __seq, bool __constant);
+    _M_attach(const _Safe_sequence_base* __seq, bool __constant)
+    { _M_attach(const_cast<_Safe_sequence_base*>(__seq), __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) throw 
()
+    { _M_attach_single(const_cast<_Safe_sequence_base*>(__seq), __constant); }
 
     /** Detach the iterator for whatever sequence it is attached to,
      * if any.
@@ -135,6 +139,15 @@ namespace __gnu_debug
     void
     _M_detach();
 
+  private:
+    /** Not-const method preserved for abi backward compatibility. */
+    void
+    _M_attach(_Safe_sequence_base* __seq, bool __constant);
+
+    /** Not-const method preserved for abi backward compatibility. */
+    void
+    _M_attach_single(_Safe_sequence_base* __seq, bool __constant) throw ();
+
   public:
     /** Likewise, but not thread-safe. */
     void
@@ -246,14 +259,16 @@ namespace __gnu_debug
 
     /** Detach all iterators, leaving them singular. */
     void
-    _M_detach_all();
+    _M_detach_all() const
+    { const_cast<_Safe_sequence_base*>(this)->_M_detach_all(); }
 
     /** 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
+    { const_cast<_Safe_sequence_base*>(this)->_M_detach_singular(); }
 
     /** Revalidates all attached singular iterators.  This method may
      *  be used to validate iterators that were invalidated before
@@ -261,7 +276,8 @@ namespace __gnu_debug
      *  valid again).
      */
     void
-    _M_revalidate_singular();
+    _M_revalidate_singular() const
+    { const_cast<_Safe_sequence_base*>(this)->_M_revalidate_singular(); }
 
     /** Swap this sequence with the given sequence. This operation
      *  also swaps ownership of the iterators, so that when the
@@ -269,11 +285,16 @@ 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
+    {
+      const_cast<_Safe_sequence_base*>(this)->_M_swap
+       (const_cast<_Safe_sequence_base&>(__x));
+    }
 
     /** For use in _Safe_sequence. */
     __gnu_cxx::__mutex&
-    _M_get_mutex() throw ();
+    _M_get_mutex() const throw ()
+    { return const_cast<_Safe_sequence_base*>(this)->_M_get_mutex(); }
 
     /** Invalidates all iterators. */
     void
@@ -281,21 +302,41 @@ namespace __gnu_debug
     { if (++_M_version == 0) _M_version = 1; }
 
   private:
+    /** Not-const method preserved for abi backward compatibility. */
+    void
+    _M_detach_all();
+
+    /** Not-const method preserved for abi backward compatibility. */
+    void
+    _M_detach_singular();
+
+    /** Not-const method preserved for abi backward compatibility. */
+    void
+    _M_revalidate_singular();
+
+    /** Not-const method preserved for abi backward compatibility. */
+    void
+    _M_swap(_Safe_sequence_base& __x) _GLIBCXX_USE_NOEXCEPT;
+
+    /** Not-const method preserved for abi backward compatibility. */
+    __gnu_cxx::__mutex&
+    _M_get_mutex() throw ();
+
     /** 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 throw 
();
 
     /** 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 throw ();
   };
 } // namespace __gnu_debug
 
diff --git a/libstdc++-v3/include/debug/safe_container.h 
b/libstdc++-v3/include/debug/safe_container.h
index cb1e69a2d69..3341806fd59 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 7c563381d0b..e0b1b46939c 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 c84f4f10093..47b3a807a8b 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 71e532065e4..10fec3fad4a 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 6b35afa66c6..e10474aae79 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 336bf2a0b2b..053361dff3c 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 1547f5b7b9d..b036edd5976 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.
@@ -97,6 +101,15 @@ namespace __gnu_debug
     /** Likewise, but not thread-safe. */
     void
     _M_detach_single() throw ();
+
+  private:
+    /** Not-const method preserved for abi backward compatibility. */
+    void
+    _M_attach(_Safe_sequence_base* __seq, bool __constant);
+
+    /** Not-const method preserved for abi backward compatibility. */
+    void
+    _M_attach_single(_Safe_sequence_base* __seq, bool __constant) noexcept;
   };
 
   /**
@@ -124,10 +137,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 +166,8 @@ namespace __gnu_debug
 
     /** Detach all iterators, leaving them singular. */
     void
-    _M_detach_all();
+    _M_detach_all() const
+    { const_cast<_Safe_unordered_container_base*>(this)->_M_detach_all(); }
 
     /** Swap this container with the given container. This operation
      *  also swaps ownership of the iterators, so that when the
@@ -161,25 +175,60 @@ 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
+    {
+      const_cast<_Safe_unordered_container_base*>(this)->_M_swap
+       (const_cast<_Safe_unordered_container_base&>(__x));
+    }
 
   private:
+    /** Not-const method preserved for abi backward compatibility. */
+    void
+    _M_detach_all();
+
+    /** Not-const method preserved for abi backward compatibility. */
+    void
+    _M_swap(_Safe_unordered_container_base& __x) noexcept;
+
     /** 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); }
+
+  inline void
+  _Safe_local_iterator_base::
+  _M_attach(const _Safe_unordered_container_base* __cont, bool __constant)
+  {
+    const _Safe_sequence_base* __seq = __cont;
+    _M_attach(const_cast<_Safe_sequence_base*>(__seq), __constant);
+  }
+
+  inline void
+  _Safe_local_iterator_base::
+  _M_attach_single(const _Safe_unordered_container_base* __cont,
+                  bool __constant) noexcept
+  {
+    const _Safe_sequence_base* __seq = __cont;
+    _M_attach_single(const_cast<_Safe_sequence_base*>(__seq), __constant);
+  }
 } // 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 2ba27dbbecb..b67b7e06b2f 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 68193891b01..0732e6374bf 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 3533b5e1df1..92c76ac6eb9 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())
@@ -385,7 +385,7 @@ namespace __gnu_debug
 
   void
   _Safe_sequence_base::
-  _M_attach(_Safe_iterator_base* __it, bool __constant)
+  _M_attach(_Safe_iterator_base* __it, bool __constant) const
   {
     __gnu_cxx::__scoped_lock sentry(_M_get_mutex());
     _M_attach_single(__it, __constant);
@@ -393,7 +393,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 +405,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 +414,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();
@@ -514,11 +514,6 @@ 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); }
-
   void
   _Safe_local_iterator_base::
   _M_attach(_Safe_sequence_base* __cont, bool __constant)
@@ -530,7 +525,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;
@@ -547,7 +542,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,7 +565,7 @@ namespace __gnu_debug
   {
     if (_M_sequence)
       {
-       _M_get_container()->_M_detach_local_single(this);
+       _M_safe_container()->_M_detach_local_single(this);
        _M_reset();
       }
   }
@@ -579,7 +574,8 @@ namespace __gnu_debug
   _Safe_unordered_container_base::
   _M_detach_all()
   {
-    __gnu_cxx::__scoped_lock sentry(_M_get_mutex());
+    const _Safe_unordered_container_base& __cont = *this;
+    __gnu_cxx::__scoped_lock sentry(__cont._M_get_mutex());
     detach_all(_M_iterators);
     _M_iterators = 0;
 
@@ -596,11 +592,15 @@ namespace __gnu_debug
   void
   _Safe_unordered_container_base::
   _M_swap(_Safe_unordered_container_base& __x) noexcept
-  { swap_ucont(_M_get_mutex(), *this, __x._M_get_mutex(), __x); }
+  {
+    const _Safe_unordered_container_base& __cont = *this;
+    const _Safe_unordered_container_base& __x_cont = __x;
+    swap_ucont(__cont._M_get_mutex(), *this, __x_cont._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 +608,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 +620,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 +629,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();
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 00000000000..71b8bfec85a
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/unordered_map/const_container.cc
@@ -0,0 +1,18 @@
+// { dg-do compile { target c++11 } }
+
+#include <unordered_map>
+
+#include <testsuite_hooks.h>
+
+int main()
+{
+  const std::unordered_map<int, int> um
+    {
+      { 0, 1 },
+      { 2, 3 },
+      { 4, 5 }
+    };
+
+  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 00000000000..376e922a671
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/unordered_multimap/const_container.cc
@@ -0,0 +1,21 @@
+// { dg-do compile { target c++11 } }
+
+#include <unordered_map>
+
+#include <testsuite_hooks.h>
+
+int main()
+{
+  const std::unordered_multimap<int, int> umm
+    {
+      { 0, 1 },
+      { 0, 1 },
+      { 2, 3 },
+      { 2, 3 },
+      { 4, 5 },
+      { 4, 5 }
+    };
+
+  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 00000000000..c0dcacef638
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/unordered_multiset/const_container.cc
@@ -0,0 +1,14 @@
+// { dg-do compile { target c++11 } }
+
+#include <unordered_set>
+
+#include <testsuite_hooks.h>
+
+int main()
+{
+  const std::unordered_multiset<int> ums
+    { 0, 0, 1, 1, 2, 2 };
+
+  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 00000000000..34d10aa7a28
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/unordered_set/const_container.cc
@@ -0,0 +1,13 @@
+// { dg-do compile { target c++11 } }
+
+#include <unordered_set>
+
+#include <testsuite_hooks.h>
+
+int main()
+{
+  const std::unordered_set<int> us { 0, 1, 2 };
+
+  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 ba2ede04447..792ed455e2c 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 37491a405dc..ab0107f79e4 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() );
       }
   };
 

Reply via email to