[PATCH] libstdc++: Make debug iterator pointer sequence const [PR116369]

François Dumont frs.dumont@gmail.com
Sat Jul 5 13:03:31 GMT 2025


On 01/07/2025 22:51, Jonathan Wakely wrote:
> On Mon, 16 Jun 2025 at 18:36, François Dumont <frs.dumont@gmail.com> wrote:
>> I eventually wonder if it is such a big deal to add the new symbols for _GLIBCXX_DEBUG mode.
> I like this version much more than the one trying to duplicate symbols with asm.
>
>
>> Here is the patch doing this. It avoids to add many const_cast which is what we are trying to achieve here.
> I'm still not really sure if this is worth it though - is it fixing a
> bug or a correctness problem? (using const_cast is safe if the objects
> aren't actually const)
>
> All the new tests already pass, even without this patch. Are these
> just tests for const member functions that we aren't currently testing
> at all?

Those tests are showing the same UB that you fixed as part of your 
PR116369 patch but this time with local_iterator. Even if tests are 
passing without this patch it's still UB before it, do you prefer to 
remove those tests then ?

Globally this patch is following your recommendations on PR116369 commit 
where you were saying:

     Ideally we would not need the const_cast at all. Instead, the _M_attach
     member (and everything it calls) should be const-qualified. That would
     work fine now, because the members that it ends up modifying are
     mutable. Making that change would require a number of new exports from
     the shared library, and would require retaining the old non-const 
member
     functions (maybe as symbol aliases) for backwards compatibility. That
     might be worth changing at some point, but isn't done here.

In addition to what is said here I made the sequence pointer const too 
as the added mutable allows that.

It was also the occasion to fix some types used in std::forward_list in 
Debug mode.

Do you think it is useless eventually ?


>
>
>> I've updated the PR keeping 2 commits so that if this last step is not good I can just drop it.
>>
>> I even updated the versioned namespace mode breaking this mode abi, I think it's fine, no ?
> Yes that's fine.
>
>
>> François
>>
>>
>>
>> On 08/06/2025 22:00, François Dumont wrote:
>>
>> 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.gcc@gmail.com> wrote:
>>>
>>>
>>> On Thu, 15 May 2025, 06:26 François Dumont, <frs.dumont@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.dumont@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
>>>>
-------------- next part --------------
diff --git a/libstdc++-v3/config/abi/pre/gnu-versioned-namespace.ver b/libstdc++-v3/config/abi/pre/gnu-versioned-namespace.ver
index 2818ab3561f..1c423ff2f57 100644
--- a/libstdc++-v3/config/abi/pre/gnu-versioned-namespace.ver
+++ b/libstdc++-v3/config/abi/pre/gnu-versioned-namespace.ver
@@ -117,11 +117,11 @@ GLIBCXX_8.0 {
     _ZN9__gnu_cxx3__818stdio_sync_filebufI[cw]NSt3__811char_traitsI[cw]EEE[5-9]*;
 
     # debug mode
-    _ZN11__gnu_debug19_Safe_sequence_base12_M_get_mutexEv;
-    _ZN11__gnu_debug19_Safe_sequence_base13_M_detach_allEv;
-    _ZN11__gnu_debug19_Safe_sequence_base18_M_detach_singularEv;
-    _ZN11__gnu_debug19_Safe_sequence_base22_M_revalidate_singularEv;
-    _ZN11__gnu_debug19_Safe_sequence_base7_M_swapERS0_;
+    _ZNK11__gnu_debug19_Safe_sequence_base12_M_get_mutexEv;
+    _ZNK11__gnu_debug19_Safe_sequence_base13_M_detach_allEv;
+    _ZNK11__gnu_debug19_Safe_sequence_base18_M_detach_singularEv;
+    _ZNK11__gnu_debug19_Safe_sequence_base22_M_revalidate_singularEv;
+    _ZNK11__gnu_debug19_Safe_sequence_base7_M_swapERKS0_;
 
     _ZN11__gnu_debug19_Safe_iterator_base9_M_attach*;
     _ZN11__gnu_debug19_Safe_iterator_base16_M_attach_single*;
@@ -136,11 +136,11 @@ GLIBCXX_8.0 {
 
     # __gnu_debug::_Safe_unordered_container_base
     # __gnu_debug::_Safe_local_iterator_base
-    _ZN11__gnu_debug30_Safe_unordered_container_base7_M_swapERS0_;
-    _ZN11__gnu_debug30_Safe_unordered_container_base13_M_detach_allEv;
-    _ZN11__gnu_debug25_Safe_local_iterator_base9_M_attachEPNS_19_Safe_sequence_baseEb;
+    _ZNK11__gnu_debug30_Safe_unordered_container_base7_M_swapERKS0_;
+    _ZNK11__gnu_debug30_Safe_unordered_container_base13_M_detach_allEv;
+    _ZN11__gnu_debug25_Safe_local_iterator_base9_M_attachEPKNS_30_Safe_unordered_container_baseEb;
     _ZN11__gnu_debug25_Safe_local_iterator_base9_M_detachEv;
-    _ZN11__gnu_debug25_Safe_local_iterator_base16_M_attach_singleEPNS_19_Safe_sequence_baseEb;
+    _ZN11__gnu_debug25_Safe_local_iterator_base16_M_attach_singleEPKNS_30_Safe_unordered_container_baseEb;
 
     # parallel mode
     _ZN14__gnu_parallel9_Settings3getEv;
diff --git a/libstdc++-v3/config/abi/pre/gnu.ver b/libstdc++-v3/config/abi/pre/gnu.ver
index 73b6f338613..b5a89c31e0e 100644
--- a/libstdc++-v3/config/abi/pre/gnu.ver
+++ b/libstdc++-v3/config/abi/pre/gnu.ver
@@ -2555,6 +2555,20 @@ GLIBCXX_3.4.35 {
     _ZNSt8__detail17__wait_until_implEPKvRNS_16__wait_args_baseERKNSt6chrono8durationI[lx]St5ratioIL[lx]1EL[lx]1000000000EEEE;
     _ZNSt8__detail11__wait_args22_M_load_proxy_wait_valEPKv;
 
+    # __gnu_debug::_Safe_iterator_base and _Safe_sequence_base const
+    _ZN11__gnu_debug19_Safe_iterator_base9_M_attachEPKNS_19_Safe_sequence_baseEb;
+    _ZN11__gnu_debug19_Safe_iterator_base16_M_attach_singleEPKNS_19_Safe_sequence_baseEb;
+    _ZNK11__gnu_debug19_Safe_sequence_base13_M_detach_allEv;
+    _ZNK11__gnu_debug19_Safe_sequence_base18_M_detach_singularEv;
+    _ZNK11__gnu_debug19_Safe_sequence_base12_M_get_mutexEv;
+    _ZNK11__gnu_debug19_Safe_sequence_base22_M_revalidate_singularEv;
+    _ZNK11__gnu_debug19_Safe_sequence_base7_M_swapERKS0_;
+
+    # __gnu_debug::_Safe_local_iterator_base and _Safe_unordered_container_base const
+    _ZN11__gnu_debug25_Safe_local_iterator_base9_M_attachEPKNS_30_Safe_unordered_container_baseEb;
+    _ZN11__gnu_debug25_Safe_local_iterator_base16_M_attach_singleEPKNS_30_Safe_unordered_container_baseEb;
+    _ZNK11__gnu_debug30_Safe_unordered_container_base13_M_detach_allEv;
+    _ZNK11__gnu_debug30_Safe_unordered_container_base7_M_swapERKS0_;
 } GLIBCXX_3.4.34;
 
 # Symbols in the support library (libsupc++) have their own tag.
diff --git a/libstdc++-v3/include/debug/deque b/libstdc++-v3/include/debug/deque
index 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..4e1511da4e8 100644
--- a/libstdc++-v3/include/debug/forward_list
+++ b/libstdc++-v3/include/debug/forward_list
@@ -58,44 +58,44 @@ namespace __gnu_debug
     class _Safe_forward_list
     : public _Safe_sequence<_SafeSequence>
     {
-      _SafeSequence&
-      _M_this() noexcept
-      { return *static_cast<_SafeSequence*>(this); }
+      const _SafeSequence*
+      _M_this() const noexcept
+      { return static_cast<const _SafeSequence*>(this); }
 
       static void
-      _M_swap_aux(_Safe_sequence_base& __lhs,
+      _S_swap_aux(const _Safe_forward_list& __lhs,
 		  _Safe_iterator_base*& __lhs_iterators,
-		  _Safe_sequence_base& __rhs,
+		  const _Safe_forward_list& __rhs,
 		  _Safe_iterator_base*& __rhs_iterators);
 
-      void _M_swap_single(_Safe_sequence_base&) noexcept;
+      void _M_swap_single(const _Safe_forward_list&) const noexcept;
 
     protected:
       void
-      _M_invalidate_all()
+      _M_invalidate_all() const
       {
-	using _Base_const_iterator = __decltype(_M_this()._M_base().cend());
+	using _Base_const_iterator = __decltype(_M_this()->_M_base().cend());
 	this->_M_invalidate_if([this](_Base_const_iterator __it)
 	{
-	  return __it != _M_this()._M_base().cbefore_begin()
-	    && __it != _M_this()._M_base().cend(); });
+	  return __it != _M_this()->_M_base().cbefore_begin()
+	    && __it != _M_this()->_M_base().cend(); });
       }
 
-      void _M_swap(_Safe_sequence_base&) noexcept;
+      void
+      _M_swap(const _Safe_forward_list&) const noexcept;
     };
 
    template<typename _SafeSequence>
     void
     _Safe_forward_list<_SafeSequence>::
-    _M_swap_aux(_Safe_sequence_base& __lhs,
+    _S_swap_aux(const _Safe_forward_list& __lhs,
 		_Safe_iterator_base*& __lhs_iterators,
-		_Safe_sequence_base& __rhs,
+		const _Safe_forward_list& __rhs,
 		_Safe_iterator_base*& __rhs_iterators)
     {
       using const_iterator = typename _SafeSequence::const_iterator;
       _Safe_iterator_base* __bbegin_its = 0;
       _Safe_iterator_base* __last_bbegin = 0;
-      _SafeSequence& __rseq = static_cast<_SafeSequence&>(__rhs);
 
       for (_Safe_iterator_base* __iter = __lhs_iterators; __iter;)
 	{
@@ -104,7 +104,7 @@ namespace __gnu_debug
 	  const_iterator* __victim =
 	    static_cast<const_iterator*>(__victim_base);
 	  __iter = __iter->_M_next;
-	  if (__victim->base() == __rseq._M_base().cbefore_begin())
+	  if (__victim->base() == __rhs._M_this()->_M_base().cbefore_begin())
 	    {
 	      __victim->_M_unlink();
 	      if (__lhs_iterators == __victim_base)
@@ -136,21 +136,21 @@ namespace __gnu_debug
    template<typename _SafeSequence>
     void
     _Safe_forward_list<_SafeSequence>::
-    _M_swap_single(_Safe_sequence_base& __other) noexcept
+    _M_swap_single(const _Safe_forward_list& __other) const noexcept
     {
-      std::swap(_M_this()._M_iterators, __other._M_iterators);
-      std::swap(_M_this()._M_const_iterators, __other._M_const_iterators);
+      std::swap(_M_this()->_M_iterators, __other._M_iterators);
+      std::swap(_M_this()->_M_const_iterators, __other._M_const_iterators);
       // Useless, always 1 on forward_list
-      //std::swap(_M_this()_M_version, __other._M_version);
-      _Safe_iterator_base* __this_its = _M_this()._M_iterators;
-      _M_swap_aux(__other, __other._M_iterators,
-		  _M_this(), _M_this()._M_iterators);
-      _Safe_iterator_base* __this_const_its = _M_this()._M_const_iterators;
-      _M_swap_aux(__other, __other._M_const_iterators,
-		  _M_this(), _M_this()._M_const_iterators);
-      _M_swap_aux(_M_this(), __this_its,
+      //std::swap(_M_this()->_M_version, __other._M_version);
+      _Safe_iterator_base* __this_its = _M_this()->_M_iterators;
+      _S_swap_aux(__other, __other._M_iterators,
+		  _M_this(), _M_this()->_M_iterators);
+      _Safe_iterator_base* __this_const_its = _M_this()->_M_const_iterators;
+      _S_swap_aux(__other, __other._M_const_iterators,
+		  _M_this(), _M_this()->_M_const_iterators);
+      _S_swap_aux(_M_this(), __this_its,
 		  __other, __other._M_iterators);
-      _M_swap_aux(_M_this(), __this_const_its,
+      _S_swap_aux(_M_this(), __this_const_its,
 		  __other, __other._M_const_iterators);
     }
 
@@ -159,13 +159,12 @@ namespace __gnu_debug
    template<typename _SafeSequence>
     void
     _Safe_forward_list<_SafeSequence>::
-    _M_swap(_Safe_sequence_base& __other) noexcept
+    _M_swap(const _Safe_forward_list& __other) const noexcept
     {
       // We need to lock both sequences to swap
       using namespace __gnu_cxx;
-      __mutex *__this_mutex = &_M_this()._M_get_mutex();
-      __mutex *__other_mutex =
-	&static_cast<_SafeSequence&>(__other)._M_get_mutex();
+      __mutex *__this_mutex = &_M_this()->_M_get_mutex();
+      __mutex *__other_mutex = &__other._M_get_mutex();
       if (__this_mutex == __other_mutex)
 	{
 	  __scoped_lock __lock(*__this_mutex);
@@ -565,7 +564,8 @@ namespace __debug
       void
       resize(size_type __sz)
       {
-	this->_M_detach_singular();
+	const forward_list* __this = this;
+	__this->_M_detach_singular();
 
 	// if __sz < size(), invalidate all iterators in [begin+__sz, end()
 	_Base_iterator __victim = _Base::begin();
@@ -585,7 +585,7 @@ namespace __debug
 	  }
 	__catch(...)
 	  {
-	    this->_M_revalidate_singular();
+	    __this->_M_revalidate_singular();
 	    __throw_exception_again;
 	  }
       }
@@ -593,7 +593,8 @@ namespace __debug
       void
       resize(size_type __sz, const value_type& __val)
       {
-	this->_M_detach_singular();
+	const forward_list* __this = this;
+	__this->_M_detach_singular();
 
 	// if __sz < size(), invalidate all iterators in [begin+__sz, end())
 	_Base_iterator __victim = _Base::begin();
@@ -613,7 +614,7 @@ namespace __debug
 	  }
 	__catch(...)
 	  {
-	    this->_M_revalidate_singular();
+	    __this->_M_revalidate_singular();
 	    __throw_exception_again;
 	  }
       }
diff --git a/libstdc++-v3/include/debug/list b/libstdc++-v3/include/debug/list
index 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..44622970792 100644
--- a/libstdc++-v3/include/debug/safe_base.h
+++ b/libstdc++-v3/include/debug/safe_base.h
@@ -53,8 +53,10 @@ namespace __gnu_debug
 
   public:
     /** The sequence this iterator references; may be NULL to indicate
-	a singular iterator. */
-    _Safe_sequence_base*	_M_sequence;
+     *  a singular iterator. Stored as pointer-to-const because sequence
+     *  could be declared as const.
+     */
+    const _Safe_sequence_base*	_M_sequence;
 
     /** The version number of this iterator. The sentinel value 0 is
      *  used to indicate an invalidated iterator (i.e., one that is
@@ -92,7 +94,7 @@ namespace __gnu_debug
     : _M_sequence(0), _M_version(0), _M_prior(0), _M_next(0)
     {
       if (!std::__is_constant_evaluated())
-	this->_M_attach(const_cast<_Safe_sequence_base*>(__seq), __constant);
+	this->_M_attach(__seq, __constant);
     }
 
     /** Initializes the iterator to reference the same sequence that
@@ -115,7 +117,7 @@ namespace __gnu_debug
 
     /** For use in _Safe_iterator. */
     __gnu_cxx::__mutex&
-    _M_get_mutex() throw ();
+    _M_get_mutex() _GLIBCXX_USE_NOEXCEPT;
 
     /** Attaches this iterator to the given sequence, detaching it
      *	from whatever sequence it was attached to originally. If the
@@ -123,11 +125,12 @@ namespace __gnu_debug
      *	unattached.
      */
     void
-    _M_attach(_Safe_sequence_base* __seq, bool __constant);
+    _M_attach(const _Safe_sequence_base* __seq, bool __constant);
 
     /** Likewise, but not thread-safe. */
     void
-    _M_attach_single(_Safe_sequence_base* __seq, bool __constant) throw ();
+    _M_attach_single(const _Safe_sequence_base* __seq,
+		     bool __constant) _GLIBCXX_USE_NOEXCEPT;
 
     /** Detach the iterator for whatever sequence it is attached to,
      *	if any.
@@ -135,10 +138,23 @@ namespace __gnu_debug
     void
     _M_detach();
 
+#if !_GLIBCXX_INLINE_VERSION
+  private:
+    /***************************************************************/
+    /** Not-const method preserved for abi backward compatibility. */
+    void
+    _M_attach(_Safe_sequence_base* __seq, bool __constant);
+
+    void
+    _M_attach_single(_Safe_sequence_base* __seq,
+		     bool __constant) _GLIBCXX_USE_NOEXCEPT;
+    /***************************************************************/
+#endif
+
   public:
     /** Likewise, but not thread-safe. */
     void
-    _M_detach_single() throw ();
+    _M_detach_single() _GLIBCXX_USE_NOEXCEPT;
 
     /** Determines if we are attached to the given sequence. */
     bool
@@ -147,13 +163,13 @@ namespace __gnu_debug
 
     /** Is this iterator singular? */
     _GLIBCXX_PURE bool
-    _M_singular() const throw ();
+    _M_singular() const _GLIBCXX_USE_NOEXCEPT;
 
     /** Can we compare this iterator to the given iterator @p __x?
 	Returns true if both iterators are nonsingular and reference
 	the same sequence. */
     _GLIBCXX_PURE bool
-    _M_can_compare(const _Safe_iterator_base& __x) const throw ();
+    _M_can_compare(const _Safe_iterator_base& __x) const _GLIBCXX_USE_NOEXCEPT;
 
     /** Invalidate the iterator, making it singular. */
     void
@@ -162,11 +178,11 @@ namespace __gnu_debug
 
     /** Reset all member variables */
     void
-    _M_reset() throw ();
+    _M_reset() _GLIBCXX_USE_NOEXCEPT;
 
     /** Unlink itself */
     void
-    _M_unlink() throw ()
+    _M_unlink() _GLIBCXX_USE_NOEXCEPT
     {
       if (_M_prior)
 	_M_prior->_M_next = _M_next;
@@ -246,14 +262,14 @@ namespace __gnu_debug
 
     /** Detach all iterators, leaving them singular. */
     void
-    _M_detach_all();
+    _M_detach_all() const;
 
     /** Detach all singular iterators.
      *  @post for all iterators i attached to this sequence,
      *   i->_M_version == _M_version.
      */
     void
-    _M_detach_singular();
+    _M_detach_singular() const;
 
     /** Revalidates all attached singular iterators.  This method may
      *  be used to validate iterators that were invalidated before
@@ -261,7 +277,7 @@ namespace __gnu_debug
      *  valid again).
      */
     void
-    _M_revalidate_singular();
+    _M_revalidate_singular() const;
 
     /** Swap this sequence with the given sequence. This operation
      *  also swaps ownership of the iterators, so that when the
@@ -269,11 +285,11 @@ namespace __gnu_debug
      *  one container now reference the other container.
      */
     void
-    _M_swap(_Safe_sequence_base& __x) _GLIBCXX_USE_NOEXCEPT;
+    _M_swap(const _Safe_sequence_base& __x) const _GLIBCXX_USE_NOEXCEPT;
 
     /** For use in _Safe_sequence. */
     __gnu_cxx::__mutex&
-    _M_get_mutex() throw ();
+    _M_get_mutex() const _GLIBCXX_USE_NOEXCEPT;
 
     /** Invalidates all iterators. */
     void
@@ -281,21 +297,42 @@ namespace __gnu_debug
     { if (++_M_version == 0) _M_version = 1; }
 
   private:
+#if !_GLIBCXX_INLINE_VERSION
+    /***************************************************************/
+    /** Not-const method preserved for abi backward compatibility. */
+    void
+    _M_detach_all();
+
+    void
+    _M_detach_singular();
+
+    void
+    _M_revalidate_singular();
+
+    void
+    _M_swap(_Safe_sequence_base& __x) _GLIBCXX_USE_NOEXCEPT;
+
+    __gnu_cxx::__mutex&
+    _M_get_mutex() _GLIBCXX_USE_NOEXCEPT;
+    /***************************************************************/
+#endif
+
     /** Attach an iterator to this sequence. */
     void
-    _M_attach(_Safe_iterator_base* __it, bool __constant);
+    _M_attach(_Safe_iterator_base* __it, bool __constant) const;
 
     /** Likewise but not thread safe. */
     void
-    _M_attach_single(_Safe_iterator_base* __it, bool __constant) throw ();
+    _M_attach_single(_Safe_iterator_base* __it,
+		     bool __constant) const _GLIBCXX_USE_NOEXCEPT;
 
     /** Detach an iterator from this sequence */
     void
-    _M_detach(_Safe_iterator_base* __it);
+    _M_detach(_Safe_iterator_base* __it) const;
 
     /** Likewise but not thread safe. */
     void
-    _M_detach_single(_Safe_iterator_base* __it) throw ();
+    _M_detach_single(_Safe_iterator_base* __it) const _GLIBCXX_USE_NOEXCEPT;
   };
 } // namespace __gnu_debug
 
diff --git a/libstdc++-v3/include/debug/safe_container.h b/libstdc++-v3/include/debug/safe_container.h
index 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;
diff --git a/libstdc++-v3/include/debug/safe_unordered_base.h b/libstdc++-v3/include/debug/safe_unordered_base.h
index 1547f5b7b9d..55cf581e315 100644
--- a/libstdc++-v3/include/debug/safe_unordered_base.h
+++ b/libstdc++-v3/include/debug/safe_unordered_base.h
@@ -49,6 +49,10 @@ namespace __gnu_debug
    */
   class _Safe_local_iterator_base : public _Safe_iterator_base
   {
+  public:
+    const _Safe_unordered_container_base*
+    _M_safe_container() const noexcept;
+
   protected:
     /** Initializes the iterator and makes it singular. */
     _Safe_local_iterator_base()
@@ -61,32 +65,32 @@ namespace __gnu_debug
      *  singular. Otherwise, the iterator will reference @p __seq and
      *  be nonsingular.
      */
-    _Safe_local_iterator_base(const _Safe_sequence_base* __seq, bool __constant)
-    { this->_M_attach(const_cast<_Safe_sequence_base*>(__seq), __constant); }
+    _Safe_local_iterator_base(const _Safe_unordered_container_base* __seq,
+			      bool __constant)
+    { _M_attach(__seq, __constant); }
 
     /** Initializes the iterator to reference the same container that
 	@p __x does. @p __constant is true if this is a constant
 	iterator, and false if it is mutable. */
     _Safe_local_iterator_base(const _Safe_local_iterator_base& __x,
 			      bool __constant)
-    { this->_M_attach(__x._M_sequence, __constant); }
+    { this->_M_attach(__x._M_safe_container(), __constant); }
 
     ~_Safe_local_iterator_base() { this->_M_detach(); }
 
-    _Safe_unordered_container_base*
-    _M_get_container() const noexcept;
-
     /** Attaches this iterator to the given container, detaching it
      *	from whatever container it was attached to originally. If the
      *	new container is the NULL pointer, the iterator is left
      *	unattached.
      */
     void
-    _M_attach(_Safe_sequence_base* __seq, bool __constant);
+    _M_attach(const _Safe_unordered_container_base* __cont,
+	      bool __constant);
 
     /** Likewise, but not thread-safe. */
     void
-    _M_attach_single(_Safe_sequence_base* __seq, bool __constant) throw ();
+    _M_attach_single(const _Safe_unordered_container_base* __cont,
+		     bool __constant) noexcept;
 
     /** Detach the iterator for whatever container it is attached to,
      *	if any.
@@ -96,7 +100,19 @@ namespace __gnu_debug
 
     /** Likewise, but not thread-safe. */
     void
-    _M_detach_single() throw ();
+    _M_detach_single() noexcept;
+
+#if !_GLIBCXX_INLINE_VERSION
+  private:
+    /***************************************************************/
+    /** Not-const method preserved for abi backward compatibility. */
+    void
+    _M_attach(_Safe_sequence_base* __seq, bool __constant);
+
+    void
+    _M_attach_single(_Safe_sequence_base* __seq, bool __constant) noexcept;
+    /***************************************************************/
+#endif
   };
 
   /**
@@ -124,10 +140,10 @@ namespace __gnu_debug
 
   public:
     /// The list of mutable local iterators that reference this container
-    _Safe_iterator_base* _M_local_iterators;
+    mutable _Safe_iterator_base* _M_local_iterators;
 
     /// The list of constant local iterators that reference this container
-    _Safe_iterator_base* _M_const_local_iterators;
+    mutable _Safe_iterator_base* _M_const_local_iterators;
 
   protected:
     // Initialize with a version number of 1 and no iterators
@@ -153,7 +169,7 @@ namespace __gnu_debug
 
     /** Detach all iterators, leaving them singular. */
     void
-    _M_detach_all();
+    _M_detach_all() const;
 
     /** Swap this container with the given container. This operation
      *  also swaps ownership of the iterators, so that when the
@@ -161,25 +177,42 @@ namespace __gnu_debug
      *  one container now reference the other container.
      */
     void
-    _M_swap(_Safe_unordered_container_base& __x) noexcept;
+    _M_swap(const _Safe_unordered_container_base& __x) const noexcept;
 
   private:
+#if !_GLIBCXX_INLINE_VERSION
+    /***************************************************************/
+    /** Not-const method preserved for abi backward compatibility. */
+    void
+    _M_detach_all();
+
+    void
+    _M_swap(_Safe_unordered_container_base& __x) noexcept;
+    /***************************************************************/
+#endif
+
     /** Attach an iterator to this container. */
     void
-    _M_attach_local(_Safe_iterator_base* __it, bool __constant);
+    _M_attach_local(_Safe_iterator_base* __it, bool __constant) const;
 
     /** Likewise but not thread safe. */
     void
-    _M_attach_local_single(_Safe_iterator_base* __it, bool __constant) throw ();
+    _M_attach_local_single(_Safe_iterator_base* __it,
+			   bool __constant) const noexcept;
 
     /** Detach an iterator from this container */
     void
-    _M_detach_local(_Safe_iterator_base* __it);
+    _M_detach_local(_Safe_iterator_base* __it) const;
 
     /** Likewise but not thread safe. */
     void
-    _M_detach_local_single(_Safe_iterator_base* __it) throw ();
+    _M_detach_local_single(_Safe_iterator_base* __it) const noexcept;
   };
+
+  inline const _Safe_unordered_container_base*
+  _Safe_local_iterator_base::
+  _M_safe_container() const noexcept
+  { return static_cast<const _Safe_unordered_container_base*>(_M_sequence); }
 } // namespace __gnu_debug
 
 #endif
diff --git a/libstdc++-v3/include/debug/safe_unordered_container.h b/libstdc++-v3/include/debug/safe_unordered_container.h
index 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..c6f6ef7ecb7 100644
--- a/libstdc++-v3/src/c++11/debug.cc
+++ b/libstdc++-v3/src/c++11/debug.cc
@@ -54,7 +54,7 @@ namespace
    *  in order to limit contention without breaking current library binary
    *  compatibility. */
   __gnu_cxx::__mutex&
-  get_safe_base_mutex(void* address)
+  get_safe_base_mutex(const void* address)
   {
     // Use arbitrarily __gnu_debug::vector<int> as the container giving
     // alignment of debug containers.
@@ -70,9 +70,9 @@ namespace
 #pragma GCC diagnostic warning "-Wabi=6"
 
   void
-  swap_its(__gnu_debug::_Safe_sequence_base& __lhs,
+  swap_its(const __gnu_debug::_Safe_sequence_base& __lhs,
 	   __gnu_debug::_Safe_iterator_base*& __lhs_its,
-	   __gnu_debug::_Safe_sequence_base& __rhs,
+	   const __gnu_debug::_Safe_sequence_base& __rhs,
 	   __gnu_debug::_Safe_iterator_base*& __rhs_its)
   {
     swap(__lhs_its, __rhs_its);
@@ -84,8 +84,8 @@ namespace
   }
 
   void
-  swap_seq_single(__gnu_debug::_Safe_sequence_base& __lhs,
-		  __gnu_debug::_Safe_sequence_base& __rhs)
+  swap_seq_single(const __gnu_debug::_Safe_sequence_base& __lhs,
+		  const __gnu_debug::_Safe_sequence_base& __rhs)
   {
     swap(__lhs._M_version, __rhs._M_version);
     swap_its(__lhs, __lhs._M_iterators,
@@ -118,17 +118,17 @@ namespace
 
   void
   swap_seq(__gnu_cxx::__mutex& lhs_mutex,
-	   __gnu_debug::_Safe_sequence_base& lhs,
+	   const __gnu_debug::_Safe_sequence_base& lhs,
 	   __gnu_cxx::__mutex& rhs_mutex,
-	   __gnu_debug::_Safe_sequence_base& rhs)
+	   const __gnu_debug::_Safe_sequence_base& rhs)
   {
     lock_and_run(lhs_mutex, rhs_mutex,
 		 [&lhs, &rhs]() { swap_seq_single(lhs, rhs); });
   }
 
   void
-  swap_ucont_single(__gnu_debug::_Safe_unordered_container_base& __lhs,
-		    __gnu_debug::_Safe_unordered_container_base& __rhs)
+  swap_ucont_single(const __gnu_debug::_Safe_unordered_container_base& __lhs,
+		    const __gnu_debug::_Safe_unordered_container_base& __rhs)
   {
     swap_seq_single(__lhs, __rhs);
     swap_its(__lhs, __lhs._M_local_iterators,
@@ -139,9 +139,9 @@ namespace
 
   void
   swap_ucont(__gnu_cxx::__mutex& lhs_mutex,
-	     __gnu_debug::_Safe_unordered_container_base& lhs,
+	     const __gnu_debug::_Safe_unordered_container_base& lhs,
 	     __gnu_cxx::__mutex& rhs_mutex,
-	     __gnu_debug::_Safe_unordered_container_base& rhs)
+	     const __gnu_debug::_Safe_unordered_container_base& rhs)
   {
     lock_and_run(lhs_mutex, rhs_mutex,
 		 [&lhs, &rhs]() { swap_ucont_single(lhs, rhs); });
@@ -158,8 +158,8 @@ namespace
       }
   }
 
-  void*
-  acquire_sequence_ptr_for_lock(__gnu_debug::_Safe_sequence_base*& seq)
+  const void*
+  acquire_sequence_ptr_for_lock(__gnu_debug::_Safe_sequence_base const*& seq)
   {
 #ifdef __GTHREADS
     if (!__gnu_cxx::__is_single_threaded())
@@ -169,7 +169,7 @@ namespace
   }
 
   void
-  reset_sequence_ptr(__gnu_debug::_Safe_sequence_base*& seq)
+  reset_sequence_ptr(__gnu_debug::_Safe_sequence_base const*& seq)
   {
 #ifdef __GTHREADS
     if (!__gnu_cxx::__is_single_threaded())
@@ -327,7 +327,7 @@ namespace __gnu_debug
 
   void
   _Safe_sequence_base::
-  _M_detach_all()
+  _M_detach_all() const
   {
     __gnu_cxx::__scoped_lock sentry(_M_get_mutex());
     detach_all(_M_iterators);
@@ -339,7 +339,7 @@ namespace __gnu_debug
 
   void
   _Safe_sequence_base::
-  _M_detach_singular()
+  _M_detach_singular() const
   {
     __gnu_cxx::__scoped_lock sentry(_M_get_mutex());
     for (_Safe_iterator_base* __iter = _M_iterators; __iter;)
@@ -361,7 +361,7 @@ namespace __gnu_debug
 
   void
   _Safe_sequence_base::
-  _M_revalidate_singular()
+  _M_revalidate_singular() const
   {
     __gnu_cxx::__scoped_lock sentry(_M_get_mutex());
     for (_Safe_iterator_base* __iter = _M_iterators; __iter;
@@ -375,17 +375,59 @@ namespace __gnu_debug
 
   void
   _Safe_sequence_base::
-  _M_swap(_Safe_sequence_base& __x) noexcept
+  _M_swap(const _Safe_sequence_base& __x) const noexcept
   { swap_seq(_M_get_mutex(), *this, __x._M_get_mutex(), __x); }
 
   __gnu_cxx::__mutex&
   _Safe_sequence_base::
-  _M_get_mutex() noexcept
+  _M_get_mutex() const noexcept
   { return get_safe_base_mutex(this); }
 
+#if !_GLIBCXX_INLINE_VERSION
+  void
+  _Safe_sequence_base::
+  _M_detach_all()
+  {
+    const _Safe_sequence_base* __this = this;
+    __this->_M_detach_all();
+  }
+
+  void
+  _Safe_sequence_base::
+  _M_detach_singular()
+  {
+    const _Safe_sequence_base* __this = this;
+    __this->_M_detach_singular();
+  }
+
+  void
+  _Safe_sequence_base::
+  _M_revalidate_singular()
+  {
+    const _Safe_sequence_base* __this = this;
+    __this->_M_revalidate_singular();
+  }
+
   void
   _Safe_sequence_base::
-  _M_attach(_Safe_iterator_base* __it, bool __constant)
+  _M_swap(_Safe_sequence_base& __x) noexcept
+  {
+    const _Safe_sequence_base* __this = this;
+    __this->_M_swap(__x);
+  }
+
+  __gnu_cxx::__mutex&
+  _Safe_sequence_base::
+  _M_get_mutex() noexcept
+  {
+    const _Safe_sequence_base* __this = this;
+    return __this->_M_get_mutex();
+  }
+#endif
+
+  void
+  _Safe_sequence_base::
+  _M_attach(_Safe_iterator_base* __it, bool __constant) const
   {
     __gnu_cxx::__scoped_lock sentry(_M_get_mutex());
     _M_attach_single(__it, __constant);
@@ -393,7 +435,7 @@ namespace __gnu_debug
 
   void
   _Safe_sequence_base::
-  _M_attach_single(_Safe_iterator_base* __it, bool __constant) noexcept
+  _M_attach_single(_Safe_iterator_base* __it, bool __constant) const noexcept
   {
     _Safe_iterator_base*& __its =
       __constant ? _M_const_iterators : _M_iterators;
@@ -405,7 +447,7 @@ namespace __gnu_debug
 
   void
   _Safe_sequence_base::
-  _M_detach(_Safe_iterator_base* __it)
+  _M_detach(_Safe_iterator_base* __it) const
   {
     // Remove __it from this sequence's list
     __gnu_cxx::__scoped_lock sentry(_M_get_mutex());
@@ -414,7 +456,7 @@ namespace __gnu_debug
 
   void
   _Safe_sequence_base::
-  _M_detach_single(_Safe_iterator_base* __it) noexcept
+  _M_detach_single(_Safe_iterator_base* __it) const noexcept
   {
     // Remove __it from this sequence's list
     __it->_M_unlink();
@@ -426,7 +468,7 @@ namespace __gnu_debug
 
   void
   _Safe_iterator_base::
-  _M_attach(_Safe_sequence_base* __seq, bool __constant)
+  _M_attach(const _Safe_sequence_base* __seq, bool __constant)
   {
     _M_detach();
 
@@ -443,7 +485,7 @@ namespace __gnu_debug
 
   void
   _Safe_iterator_base::
-  _M_attach_single(_Safe_sequence_base* __seq, bool __constant) noexcept
+  _M_attach_single(const _Safe_sequence_base* __seq, bool __constant) noexcept
   {
     _M_detach_single();
 
@@ -514,14 +556,27 @@ namespace __gnu_debug
   _M_get_mutex() noexcept
   { return _M_sequence->_M_get_mutex(); }
 
-  _Safe_unordered_container_base*
-  _Safe_local_iterator_base::
-  _M_get_container() const noexcept
-  { return static_cast<_Safe_unordered_container_base*>(_M_sequence); }
+#if !_GLIBCXX_INLINE_VERSION
+  void
+  _Safe_iterator_base::
+  _M_attach(_Safe_sequence_base* __seq, bool __constant)
+  {
+    const _Safe_sequence_base* __cseq = __seq;
+    _M_attach(__cseq, __constant);
+  }
+
+  void
+  _Safe_iterator_base::
+  _M_attach_single(_Safe_sequence_base* __seq, bool __constant) noexcept
+  {
+    const _Safe_sequence_base* __cseq = __seq;
+    _M_attach_single(__cseq, __constant);
+  }
+#endif
 
   void
   _Safe_local_iterator_base::
-  _M_attach(_Safe_sequence_base* __cont, bool __constant)
+  _M_attach(const _Safe_unordered_container_base* __cont, bool __constant)
   {
     _M_detach();
 
@@ -530,7 +585,7 @@ namespace __gnu_debug
       {
 	_M_sequence = __cont;
 	_M_version = _M_sequence->_M_version;
-	_M_get_container()->_M_attach_local(this, __constant);
+	_M_safe_container()->_M_attach_local(this, __constant);
       }
     else
       _M_version = 0;
@@ -538,7 +593,8 @@ namespace __gnu_debug
 
   void
   _Safe_local_iterator_base::
-  _M_attach_single(_Safe_sequence_base* __cont, bool __constant) noexcept
+  _M_attach_single(const _Safe_unordered_container_base* __cont,
+		   bool __constant) noexcept
   {
     _M_detach_single();
 
@@ -547,7 +603,7 @@ namespace __gnu_debug
       {
 	_M_sequence = __cont;
 	_M_version = _M_sequence->_M_version;
-	_M_get_container()->_M_attach_local_single(this, __constant);
+	_M_safe_container()->_M_attach_local_single(this, __constant);
       }
     else
       _M_version = 0;
@@ -570,14 +626,34 @@ namespace __gnu_debug
   {
     if (_M_sequence)
       {
-	_M_get_container()->_M_detach_local_single(this);
+	_M_safe_container()->_M_detach_local_single(this);
 	_M_reset();
       }
   }
 
+#if !_GLIBCXX_INLINE_VERSION
+  void
+  _Safe_local_iterator_base::
+  _M_attach(_Safe_sequence_base* __seq, bool __constant)
+  {
+    const _Safe_unordered_container_base* __cont
+      = static_cast<_Safe_unordered_container_base*>(__seq);
+    _M_attach(__cont, __constant);
+  }
+
+  void
+  _Safe_local_iterator_base::
+  _M_attach_single(_Safe_sequence_base* __seq, bool __constant) noexcept
+  {
+    const _Safe_unordered_container_base* __cont
+      = static_cast<_Safe_unordered_container_base*>(__seq);
+    _M_attach_single(__cont, __constant);
+  }
+#endif
+
   void
   _Safe_unordered_container_base::
-  _M_detach_all()
+  _M_detach_all() const
   {
     __gnu_cxx::__scoped_lock sentry(_M_get_mutex());
     detach_all(_M_iterators);
@@ -595,12 +671,12 @@ namespace __gnu_debug
 
   void
   _Safe_unordered_container_base::
-  _M_swap(_Safe_unordered_container_base& __x) noexcept
+  _M_swap(const _Safe_unordered_container_base& __x) const noexcept
   { swap_ucont(_M_get_mutex(), *this, __x._M_get_mutex(), __x); }
 
   void
   _Safe_unordered_container_base::
-  _M_attach_local(_Safe_iterator_base* __it, bool __constant)
+  _M_attach_local(_Safe_iterator_base* __it, bool __constant) const
   {
     __gnu_cxx::__scoped_lock sentry(_M_get_mutex());
     _M_attach_local_single(__it, __constant);
@@ -608,7 +684,7 @@ namespace __gnu_debug
 
   void
   _Safe_unordered_container_base::
-  _M_attach_local_single(_Safe_iterator_base* __it, bool __constant) noexcept
+  _M_attach_local_single(_Safe_iterator_base* __it, bool __constant) const noexcept
   {
     _Safe_iterator_base*& __its =
       __constant ? _M_const_local_iterators : _M_local_iterators;
@@ -620,7 +696,7 @@ namespace __gnu_debug
 
   void
   _Safe_unordered_container_base::
-  _M_detach_local(_Safe_iterator_base* __it)
+  _M_detach_local(_Safe_iterator_base* __it) const
   {
     // Remove __it from this container's list
     __gnu_cxx::__scoped_lock sentry(_M_get_mutex());
@@ -629,7 +705,7 @@ namespace __gnu_debug
 
   void
   _Safe_unordered_container_base::
-  _M_detach_local_single(_Safe_iterator_base* __it) noexcept
+  _M_detach_local_single(_Safe_iterator_base* __it) const noexcept
   {
     // Remove __it from this container's list
     __it->_M_unlink();
@@ -638,6 +714,24 @@ namespace __gnu_debug
     if (_M_local_iterators == __it)
       _M_local_iterators = __it->_M_next;
   }
+
+#if !_GLIBCXX_INLINE_VERSION
+  void
+  _Safe_unordered_container_base::
+  _M_detach_all()
+  {
+    const _Safe_unordered_container_base* __this = this;
+    __this->_M_detach_all();
+  }
+
+  void
+  _Safe_unordered_container_base::
+  _M_swap(_Safe_unordered_container_base& __x) noexcept
+  {
+    const _Safe_unordered_container_base* __this = this;
+    __this->_M_swap(__x);
+  }
+#endif
 }
 
 namespace
diff --git a/libstdc++-v3/testsuite/23_containers/unordered_map/const_container.cc b/libstdc++-v3/testsuite/23_containers/unordered_map/const_container.cc
new file mode 100644
index 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() );
       }
   };
 


More information about the Libstdc++ mailing list