Files
gcc/libstdc++-v3/include/debug/safe_container.h
François Dumont 2fd6f42c17 libstdc++: Make debug iterator pointer sequence const [PR116369]
In revision a35dd276cb the debug sequence
have been made mutable to allow attach iterators to const containers.
This change completes this fix by also declaring debug unordered container
members mutable.

Additionally the debug iterator sequence is now a pointer-to-const and so
_Safe_sequence_base _M_attach and all other methods are const qualified.
Not-const methods exported are preserved for abi backward compatibility.

libstdc++-v3/ChangeLog:

	PR c++/116369
	* config/abi/pre/gnu-versioned-namespace.ver: Use new const qualified symbols.
	* config/abi/pre/gnu.ver: Add new const qualified symbols.
	* include/debug/safe_base.h
	(_Safe_iterator_base::_M_sequence): Declare as pointer-to-const.
	(_Safe_iterator_base::_M_attach, _M_attach_single): New, take pointer-to-const
	_Safe_sequence_base.
	(_Safe_sequence_base::_M_detach_all, _M_detach_singular, _M_revalidate_singular)
	(_M_swap, _M_get_mutex): New, const qualified.
	(_Safe_sequence_base::_M_attach, _M_attach_single, _M_detach, _M_detach_single):
	const qualify.
	* include/debug/safe_container.h (_Safe_container<>::_M_cont): Add const qualifier.
	(_Safe_container<>::_M_swap_base): New.
	(_Safe_container(_Safe_container&&, const _Alloc&, std::false_type)):
	Adapt to use latter.
	(_Safe_container<>::operator=(_Safe_container&&)): Likewise.
	(_Safe_container<>::_M_swap): Likewise and take parameter as const reference.
	* include/debug/safe_unordered_base.h
	(_Safe_local_iterator_base::_M_safe_container): New.
	(_Safe_local_iterator_base::_Safe_local_iterator_base): Take
	_Safe_unordered_container_base as pointer-to-const.
	(_Safe_unordered_container_base::_M_attach, _M_attach_single): New, take
	container as _Safe_unordered_container_base pointer-to-const.
	(_Safe_unordered_container_base::_M_local_iterators, _M_const_local_iterators):
	Add mutable.
	(_Safe_unordered_container_base::_M_detach_all, _M_swap): New, const qualify.
	(_Safe_unordered_container_base::_M_attach_local, _M_attach_local_single)
	(_M_detach_local, _M_detach_local_single): Add const qualifier.
	* include/debug/safe_unordered_container.h (_Safe_unordered_container::_M_self()): New.
	* include/debug/safe_unordered_container.tcc
	(_Safe_unordered_container::_M_invalidate_if, _M_invalidated_local_if): Use latter.
	* include/debug/safe_iterator.h (_Safe_iterator<>::_M_attach, _M_attach_single):
	Take _Safe_sequence_base as pointer-to-const.
	(_Safe_iterator<>::_M_get_sequence): Add const_cast and comment about it.
	* include/debug/safe_local_iterator.h (_Safe_local_iterator<>): Replace usages
	of _M_sequence member by _M_safe_container().
	(_Safe_local_iterator<>::_M_attach, _M_attach_single): Take
	_Safe_unordered_container_base as pointer-to-const.
	(_Safe_local_iterator<>::_M_get_sequence): Rename into...
	(_Safe_local_iterator<>::_M_get_ucontainer): ...this. Add necessary const_cast and
	comment to explain it.
	(_Safe_local_iterator<>::_M_is_begin, _M_is_end): Adapt.
	* include/debug/safe_local_iterator.tcc: Adapt.
	* include/debug/safe_sequence.h
	(_Safe_sequence<>::_M_invalidate_if, _M_transfer_from_if): Add const qualifier.
	* include/debug/safe_sequence.tcc: Adapt.
	* include/debug/deque (std::__debug::deque::erase): Adapt to use new const
	qualified methods.
	* include/debug/formatter.h: Adapt.
	* include/debug/forward_list (_Safe_forward_list::_M_this): Add const
	qualification and return pointer for consistency with 'this' keyword.
	(_Safe_forward_list::_M_swap_aux): Rename into...
	(_Safe_forward_list::_S_swap_aux): ...this and take sequence as const reference.
	(forward_list<>::resize): Adapt to use const methods.
	* include/debug/list (list<>::resize): Likewise.
	* src/c++11/debug.cc: Adapt to const qualification.
	* testsuite/util/testsuite_containers.h
	(forward_members_unordered::forward_members_unordered): Add check on local_iterator
	conversion to const_local_iterator.
	(forward_members::forward_members): Add check on iterator conversion to
	const_iterator.
	* testsuite/23_containers/unordered_map/const_container.cc: New test case.
	* testsuite/23_containers/unordered_multimap/const_container.cc: New test case.
	* testsuite/23_containers/unordered_multiset/const_container.cc: New test case.
	* testsuite/23_containers/unordered_set/const_container.cc: New test case.
	* testsuite/23_containers/vector/debug/mutex_association.cc: Adapt.
2025-07-08 07:04:00 +02:00

159 lines
4.4 KiB
C++

// Safe container implementation -*- C++ -*-
// Copyright (C) 2014-2025 Free Software Foundation, Inc.
//
// This file is part of the GNU ISO C++ Library. This library is free
// software; you can redistribute it and/or modify it under the
// terms of the GNU General Public License as published by the
// Free Software Foundation; either version 3, or (at your option)
// any later version.
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// Under Section 7 of GPL version 3, you are granted additional
// permissions described in the GCC Runtime Library Exception, version
// 3.1, as published by the Free Software Foundation.
// You should have received a copy of the GNU General Public License and
// a copy of the GCC Runtime Library Exception along with this program;
// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
// <http://www.gnu.org/licenses/>.
/** @file debug/safe_container.h
* This file is a GNU debug extension to the Standard C++ Library.
*/
#ifndef _GLIBCXX_DEBUG_SAFE_CONTAINER_H
#define _GLIBCXX_DEBUG_SAFE_CONTAINER_H 1
#include <ext/alloc_traits.h>
namespace __gnu_debug
{
/// Safe class dealing with some allocator dependent operations.
template<typename _SafeContainer,
typename _Alloc,
template<typename> class _SafeBase,
bool _IsCxx11AllocatorAware = true>
class _Safe_container
: public _SafeBase<_SafeContainer>
{
typedef _SafeBase<_SafeContainer> _Base;
_GLIBCXX20_CONSTEXPR
const _SafeContainer&
_M_cont() const _GLIBCXX_NOEXCEPT
{ return *static_cast<const _SafeContainer*>(this); }
protected:
#if __cplusplus >= 201103L
_Safe_container() = default;
_Safe_container(const _Safe_container&) = default;
_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))
{ }
_GLIBCXX20_CONSTEXPR
_Safe_container(_Safe_container&& __x, const _Alloc& __a, std::false_type)
: _Safe_container()
{
if (!std::__is_constant_evaluated())
{
if (__x._M_cont().get_allocator() == __a)
_M_swap_base(__x);
else
__x._M_invalidate_all();
}
}
protected:
_GLIBCXX20_CONSTEXPR
_Safe_container(_Safe_container&& __x, const _Alloc& __a)
: _Safe_container(std::move(__x), __a,
typename std::allocator_traits<_Alloc>::is_always_equal{})
{ }
#endif
// Copy assignment invalidate all iterators.
_GLIBCXX20_CONSTEXPR
_Safe_container&
operator=(const _Safe_container&) _GLIBCXX_NOEXCEPT
{
if (!std::__is_constant_evaluated())
this->_M_invalidate_all();
return *this;
}
#if __cplusplus >= 201103L
_GLIBCXX20_CONSTEXPR
_Safe_container&
operator=(_Safe_container&& __x) noexcept
{
if (std::__is_constant_evaluated())
return *this;
if (std::__addressof(__x) == this)
{
// Standard containers have a valid but unspecified value after
// self-move, so we invalidate all debug iterators even if the
// underlying container happens to preserve its contents.
this->_M_invalidate_all();
return *this;
}
if (_IsCxx11AllocatorAware)
{
typedef __gnu_cxx::__alloc_traits<_Alloc> _Alloc_traits;
bool __xfer_memory = _Alloc_traits::_S_propagate_on_move_assign()
|| _M_cont().get_allocator() == __x._M_cont().get_allocator();
if (__xfer_memory)
_M_swap_base(__x);
else
this->_M_invalidate_all();
}
else
_M_swap_base(__x);
__x._M_invalidate_all();
return *this;
}
_GLIBCXX20_CONSTEXPR
void
_M_swap(const _Safe_container& __x) const noexcept
{
if (_IsCxx11AllocatorAware)
{
typedef __gnu_cxx::__alloc_traits<_Alloc> _Alloc_traits;
if (!_Alloc_traits::_S_propagate_on_swap())
__glibcxx_check_equal_allocs(this->_M_cont()._M_base(),
__x._M_cont()._M_base());
}
_M_swap_base(__x);
}
#else
void
_M_swap(const _Safe_container& __x) const throw()
{ _Base::_M_swap(__x); }
#endif
};
} // namespace __gnu_debug
#endif