[PATCH][_GLIBCXX_DEBUG] Enhance __gnu_debug::vector iterator invalidation
Jonathan Wakely
jwakely@redhat.com
Thu May 28 11:46:52 GMT 2026
On Thu, 21 May 2026 at 22:20 +0200, François Dumont wrote:
>Hi
>
>Following your remark Jonathan regarding how iterators are invalidated
>in vector I reviewed the std::__debug::vector implementation.
Can you remind me where I said that? I remember discussing it for
inplace_vector::assign (2025-11-03 in the thread about
__debug::inplace_vector).
I don't remember the comment you're referring to, so I don't know what
I said :-)
>I'll do something similar on std::__debug::inplace_vector.
>
> libstdc++: [_GLIBCXX_DEBUG] Enhance __gnu_debug::vector iterator
>invalidation
>
> Rework the way std::__debug::vector's iterators are being
>invalidated. Use a guard
> approach which on destructor invalidates iterators based on the
>state of the container.
>
> Moreover update invalidation policy in following vector methods:
> - operator=(initializer_list)
> - assign(Iterator, Iterator)
> - assign(size_t, const _Tp&)
> - assign(initializer_list)
>
> Current behavior to invalidate all iterators unconditionally is
>preserved only if
> _GLIBCXX_DEBUG_PEDANTIC is defined. Otherwise if a reallocation
>occurs all iterators
> are invaliidated else only iterators after the new container size
>are invalidated.
>
> libstdc++-v3/ChangeLog:
>
> * include/debug/assertions.h [_GLIBCXX_DEBUG_STD_C]: New macro.
> * include/debug/vector (_Safe_vector<_Tp, _Allocator>):
>Update template parameter.
> (_Safe_vector::_M_requires_reallocation): Remove.
> (_SafeVectorGuard): New.
> [_GLIBCXX_DEBUG_PEDANTIC](_SafeVectorPedanticGuard): New.
> (_SafeVectorInsertGuard): New.
> (vector): Adapt methods to use new guard type.
> *
>testsuite/23_containers/vector/cons/destructible_debug_neg.cc: Adapt
>error line
> number.
> *
>testsuite/23_containers/vector/debug/initializer_list.cc: New test
>case.
> *
>testsuite/23_containers/vector/debug/initializer_list_pedantic.cc: New
>test case.
>
>Partially tested on x86_64 w/o _GLIBCXX_DEBUG mode.
>
>Ok to commit once tests completed ?
>
>https://forge.sourceware.org/gcc/gcc-TEST/pulls/159
>
>François
>
>
>diff --git a/libstdc++-v3/include/debug/assertions.h b/libstdc++-v3/include/debug/assertions.h
>index c4993dc8596..768a7f05228 100644
>--- a/libstdc++-v3/include/debug/assertions.h
>+++ b/libstdc++-v3/include/debug/assertions.h
>@@ -31,6 +31,12 @@
>
> #include <bits/c++config.h>
>
>+#ifdef _GLIBCXX_DEBUG
>+# define _GLIBCXX_DEBUG_STD_C ::std::_GLIBCXX_STD_C
>+#else
>+# define _GLIBCXX_DEBUG_STD_C ::std
>+#endif
>+
> #ifndef _GLIBCXX_DEBUG
> // Verify that [_First, _Last) forms a non-empty iterator range.
> # define __glibcxx_requires_non_empty_range(_First,_Last) \
>diff --git a/libstdc++-v3/include/debug/vector b/libstdc++-v3/include/debug/vector
>index 61e5ff78a7a..1e1a971036e 100644
>--- a/libstdc++-v3/include/debug/vector
>+++ b/libstdc++-v3/include/debug/vector
>@@ -51,11 +51,12 @@ namespace __gnu_debug
> * detecting code which relies on non-portable implementation details of
> * the libstdc++ reallocation policy.
> */
>- template<typename _SafeSequence,
>- typename _BaseSequence>
>+ template<class _Tp, typename _Allocator>
> class _Safe_vector
> {
>- typedef typename _BaseSequence::size_type size_type;
>+ typedef std::__debug::vector<_Tp, _Allocator> _SafeSequence;
>+ typedef _GLIBCXX_DEBUG_STD_C::vector<_Tp, _Allocator> _StdVector;
>+ typedef typename _StdVector::size_type size_type;
>
> _GLIBCXX20_CONSTEXPR
> const _SafeSequence&
>@@ -103,10 +104,6 @@ namespace __gnu_debug
>
> size_type _M_guaranteed_capacity;
>
>- bool
>- _M_requires_reallocation(size_type __elements) const _GLIBCXX_NOEXCEPT
>- { return __elements > _M_seq().capacity(); }
>-
> _GLIBCXX20_CONSTEXPR
> void
> _M_update_guaranteed_capacity() _GLIBCXX_NOEXCEPT
>@@ -115,6 +112,66 @@ namespace __gnu_debug
> _M_guaranteed_capacity = _M_seq().size();
> }
> };
>+
>+ template<class _Tp, typename _Allocator>
>+ class _SafeVectorGuard
>+ {
>+ typedef std::__debug::vector<_Tp, _Allocator> _SafeVector;
>+ typedef _GLIBCXX_DEBUG_STD_C::vector<_Tp, _Allocator> _StdVector;
>+ typedef typename _StdVector::size_type size_type;
>+
>+ _SafeVector& _M_vect;
>+ size_type _M_capacity, _M_size;
>+
>+ public:
>+ bool _M_active;
>+
>+ _GLIBCXX20_CONSTEXPR
>+ _SafeVectorGuard(_SafeVector& __vector);
>+
>+ _GLIBCXX20_CONSTEXPR
>+ ~_SafeVectorGuard();
>+ };
>+
>+#ifdef _GLIBCXX_DEBUG_PEDANTIC
>+ template<class _Tp, typename _Allocator>
>+ class _SafeVectorPedanticGuard
>+ {
>+ typedef std::__debug::vector<_Tp, _Allocator> _SafeVector;
>+ _SafeVector& _M_vect;
>+
>+ public:
>+ bool _M_active;
>+
>+ _GLIBCXX20_CONSTEXPR
>+ _SafeVectorPedanticGuard(_SafeVector& __vector);
>+
>+ _GLIBCXX20_CONSTEXPR
>+ ~_SafeVectorPedanticGuard();
>+ };
>+#endif
>+
>+ template<class _Tp, typename _Allocator>
>+ class _SafeVectorInsertGuard
>+ {
>+ typedef std::__debug::vector<_Tp, _Allocator> _SafeVector;
>+ typedef _GLIBCXX_DEBUG_STD_C::vector<_Tp, _Allocator> _StdVector;
>+ typedef typename _StdVector::size_type size_type;
>+ typedef typename _StdVector::difference_type difference_type;
>+
>+ _SafeVector& _M_vect;
>+ size_type _M_capacity;
>+ difference_type _M_offset;
>+
>+ public:
>+ bool _M_active;
>+
>+ _GLIBCXX20_CONSTEXPR
>+ _SafeVectorInsertGuard(_SafeVector& __vector, difference_type __offset);
>+
>+ _GLIBCXX20_CONSTEXPR
>+ ~_SafeVectorInsertGuard();
>+ };
> }
All the guard types above need comments explaining what they do. When
should you use each one? How are they different from each other?
How do we deviate from the standard when not in pedantic mode?
I'm unclear what they actually do, and how that corresponds to the
standard.
_SafeVectorGuard invalidates all iterators if the size increased to
greater than capacity. That's used by resize and emplace_back and
push_back, right? And if the size was reduced, invalidate iterators to
the erased elements. This must not be used for reserve, because it
would not invalidate all iterators on reallocation, because the size
would not change.
_SafeVectorPedanticGuard invalidates all iterators unconditionally,
which is what the standard says to do for assign.
_SafeVectorInsertGuard seems to be almost the same as _SafeVectorGuard
but using an arbitrary position for the "invalidates all after pos"
instead of only invalidating at the end.
Would it be more clear to have _ResizeGuard, _AssignGuard (which
changes behaviour for pedantic vs non-pedantic), and _InsertGuard?
>
> namespace std _GLIBCXX_VISIBILITY(default)
>@@ -128,14 +185,33 @@ namespace __debug
> : public __gnu_debug::_Safe_container<
> vector<_Tp, _Allocator>, _Allocator, __gnu_debug::_Safe_sequence>,
> public _GLIBCXX_STD_C::vector<_Tp, _Allocator>,
>- public __gnu_debug::_Safe_vector<
>- vector<_Tp, _Allocator>,
>- _GLIBCXX_STD_C::vector<_Tp, _Allocator> >
>+ public __gnu_debug::_Safe_vector<_Tp, _Allocator>
> {
> typedef _GLIBCXX_STD_C::vector<_Tp, _Allocator> _Base;
> typedef __gnu_debug::_Safe_container<
> vector, _Allocator, __gnu_debug::_Safe_sequence> _Safe;
>- typedef __gnu_debug::_Safe_vector<vector, _Base> _Safe_vector;
>+ typedef __gnu_debug::_Safe_vector<_Tp, _Allocator> _Safe_vector;
>+
>+ typedef __gnu_debug::_SafeVectorGuard<_Tp, _Allocator> _Guard;
>+#ifdef _GLIBCXX_DEBUG_PEDANTIC
>+ typedef __gnu_debug::_SafeVectorPedanticGuard<_Tp, _Allocator>
>+ _MaybePedanticGuard;
>+#else
>+ typedef _Guard _MaybePedanticGuard;
This name seems focused on the detail of how we decide which type to
use, not what it actually does. And _SafeVectorGuard is also "maybe
pedantic" because its destructor changes behaviour for pedantic mode.
Would _AssignGuard be a better name? That reflects where it's actually
used.
>+#endif
>+ typedef __gnu_debug::_SafeVectorInsertGuard<_Tp, _Allocator>
>+ _InsertGuard;
>+
>+ template<typename _Tp2, typename _Alloc2>
>+ friend class ::__gnu_debug::_SafeVectorGuard;
>+
>+#ifdef _GLIBCXX_DEBUG_PEDANTIC
>+ template<typename _Tp2, typename _Alloc2>
>+ friend class ::__gnu_debug::_SafeVectorPedanticGuard;
>+#endif
>+
>+ template<typename _Tp2, typename _Alloc2>
>+ friend class ::__gnu_debug::_SafeVectorInsertGuard;
>
> typedef typename _Base::iterator _Base_iterator;
> typedef typename _Base::const_iterator _Base_const_iterator;
>@@ -276,12 +352,9 @@ namespace __debug
> vector&
> operator=(initializer_list<value_type> __l)
> {
>+ _MaybePedanticGuard __guard(*this);
> _Base::operator=(__l);
>- if (!std::__is_constant_evaluated())
>- {
>- this->_M_invalidate_all();
>- this->_M_update_guaranteed_capacity();
>- }
>+ __guard._M_active = true;
> return *this;
> }
> #endif
>@@ -303,26 +376,23 @@ namespace __debug
> typename __gnu_debug::_Distance_traits<_InputIterator>::__type __dist;
> __glibcxx_check_valid_range2(__first, __last, __dist);
>
>+ _MaybePedanticGuard __guard(*this);
> if (__dist.second >= __gnu_debug::__dp_sign)
> _Base::assign(__gnu_debug::__unsafe(__first),
> __gnu_debug::__unsafe(__last));
> else
> _Base::assign(__first, __last);
>
>- this->_M_invalidate_all();
>- this->_M_update_guaranteed_capacity();
>+ __guard._M_active = true;
> }
>
> _GLIBCXX20_CONSTEXPR
> void
> assign(size_type __n, const _Tp& __u)
> {
>+ _MaybePedanticGuard __guard(*this);
> _Base::assign(__n, __u);
>- if (!std::__is_constant_evaluated())
>- {
>- this->_M_invalidate_all();
>- this->_M_update_guaranteed_capacity();
>- }
>+ __guard._M_active = true;
> }
>
> #if __cplusplus >= 201103L
>@@ -330,12 +400,9 @@ namespace __debug
> void
> assign(initializer_list<value_type> __l)
> {
>+ _MaybePedanticGuard __guard(*this);
> _Base::assign(__l);
>- if (!std::__is_constant_evaluated())
>- {
>- this->_M_invalidate_all();
>- this->_M_update_guaranteed_capacity();
>- }
>+ __guard._M_active = true;
> }
> #endif
>
>@@ -428,13 +495,9 @@ namespace __debug
> if (std::__is_constant_evaluated())
> return _Base::resize(__sz);
>
>- bool __realloc = this->_M_requires_reallocation(__sz);
>- if (__sz < this->size())
>- this->_M_invalidate_after_nth(__sz);
>+ _Guard __guard(*this);
> _Base::resize(__sz);
>- if (__realloc)
>- this->_M_invalidate_all();
>- this->_M_update_guaranteed_capacity();
>+ __guard._M_active = true;
> }
>
> _GLIBCXX20_CONSTEXPR
>@@ -444,25 +507,17 @@ namespace __debug
> if (std::__is_constant_evaluated())
> return _Base::resize(__sz, __c);
>
>- bool __realloc = this->_M_requires_reallocation(__sz);
>- if (__sz < this->size())
>- this->_M_invalidate_after_nth(__sz);
>+ _Guard __guard(*this);
> _Base::resize(__sz, __c);
>- if (__realloc)
>- this->_M_invalidate_all();
>- this->_M_update_guaranteed_capacity();
>+ __guard._M_active = true;
> }
> #else
> void
> resize(size_type __sz, _Tp __c = _Tp())
> {
>- bool __realloc = this->_M_requires_reallocation(__sz);
>- if (__sz < this->size())
>- this->_M_invalidate_after_nth(__sz);
>+ _Guard __guard(*this);
> _Base::resize(__sz, __c);
>- if (__realloc)
>- this->_M_invalidate_all();
>- this->_M_update_guaranteed_capacity();
>+ __guard._M_active = true;
> }
> #endif
>
>@@ -506,7 +561,7 @@ namespace __debug
> if (std::__is_constant_evaluated())
> return _Base::reserve(__n);
>
>- bool __realloc = this->_M_requires_reallocation(__n);
>+ bool __realloc = __n > capacity();
> _Base::reserve(__n);
> if (__n > this->_M_guaranteed_capacity)
> this->_M_guaranteed_capacity = __n;
>@@ -583,11 +638,9 @@ namespace __debug
> if (std::__is_constant_evaluated())
> return _Base::push_back(__x);
>
>- bool __realloc = this->_M_requires_reallocation(this->size() + 1);
>+ _Guard __guard(*this);
> _Base::push_back(__x);
>- if (__realloc)
>- this->_M_invalidate_all();
>- this->_M_update_guaranteed_capacity();
>+ __guard._M_active = true;
> }
>
> #if __cplusplus >= 201103L
>@@ -610,11 +663,9 @@ namespace __debug
> if (std::__is_constant_evaluated())
> return _Base::emplace_back(std::forward<_Args>(__args)...);
>
>- bool __realloc = this->_M_requires_reallocation(this->size() + 1);
>+ _Guard __guard(*this);
> _Base::emplace_back(std::forward<_Args>(__args)...);
>- if (__realloc)
>- this->_M_invalidate_all();
>- this->_M_update_guaranteed_capacity();
>+ __guard._M_active = true;
> #if __cplusplus > 201402L
> return back();
> #endif
>@@ -645,15 +696,14 @@ namespace __debug
> this);
>
> __glibcxx_check_insert(__position);
>- bool __realloc = this->_M_requires_reallocation(this->size() + 1);
>+ _Base_iterator __res;
>+ {
> difference_type __offset = __position.base() - _Base::cbegin();
>- _Base_iterator __res = _Base::emplace(__position.base(),
>+ _InsertGuard __guard(*this, __offset);
>+ __res = _Base::emplace(__position.base(),
> std::forward<_Args>(__args)...);
>- if (__realloc)
>- this->_M_invalidate_all();
>- else
>- this->_M_invalidate_after_nth(__offset);
>- this->_M_update_guaranteed_capacity();
>+ __guard._M_active = true;
>+ }
> return { __res, this };
> }
> #endif
>@@ -670,14 +720,13 @@ namespace __debug
> return iterator(_Base::insert(__position.base(), __x), this);
>
> __glibcxx_check_insert(__position);
>- bool __realloc = this->_M_requires_reallocation(this->size() + 1);
>+ _Base_iterator __res;
>+ {
> difference_type __offset = __position.base() - _Base::begin();
>- _Base_iterator __res = _Base::insert(__position.base(), __x);
>- if (__realloc)
>- this->_M_invalidate_all();
>- else
>- this->_M_invalidate_after_nth(__offset);
>- this->_M_update_guaranteed_capacity();
>+ _InsertGuard __guard(*this, __offset);
>+ __res = _Base::insert(__position.base(), __x);
>+ __guard._M_active = true;
>+ }
> return iterator(__res, this);
> }
>
>@@ -704,14 +753,13 @@ namespace __debug
> return iterator(_Base::insert(__position.base(), __n, __x), this);
>
> __glibcxx_check_insert(__position);
>- bool __realloc = this->_M_requires_reallocation(this->size() + __n);
>+ _Base_iterator __res;
>+ {
> difference_type __offset = __position.base() - _Base::cbegin();
>- _Base_iterator __res = _Base::insert(__position.base(), __n, __x);
>- if (__realloc)
>- this->_M_invalidate_all();
>- else
>- this->_M_invalidate_after_nth(__offset);
>- this->_M_update_guaranteed_capacity();
>+ _InsertGuard __guard(*this, __offset);
>+ __res = _Base::insert(__position.base(), __n, __x);
>+ __guard._M_active = true;
>+ }
> return { __res, this };
> }
> #else
>@@ -719,14 +767,10 @@ namespace __debug
> insert(iterator __position, size_type __n, const _Tp& __x)
> {
> __glibcxx_check_insert(__position);
>- bool __realloc = this->_M_requires_reallocation(this->size() + __n);
> difference_type __offset = __position.base() - _Base::begin();
>+ _InsertGuard __guard(*this, __offset);
> _Base::insert(__position.base(), __n, __x);
>- if (__realloc)
>- this->_M_invalidate_all();
>- else
>- this->_M_invalidate_after_nth(__offset);
>- this->_M_update_guaranteed_capacity();
>+ __guard._M_active = true;
> }
> #endif
>
>@@ -746,12 +790,10 @@ namespace __debug
> typename __gnu_debug::_Distance_traits<_InputIterator>::__type __dist;
> __glibcxx_check_insert_range(__position, __first, __last, __dist);
>
>- /* Hard to guess if invalidation will occur, because __last
>- - __first can't be calculated in all cases, so we just
>- punt here by checking if it did occur. */
>- _Base_iterator __old_begin = _M_base().begin();
>- difference_type __offset = __position.base() - _Base::cbegin();
> _Base_iterator __res;
>+ {
>+ difference_type __offset = __position.base() - _Base::cbegin();
>+ _InsertGuard __guard(*this, __offset);
> if (__dist.second >= __gnu_debug::__dp_sign)
> __res = _Base::insert(__position.base(),
> __gnu_debug::__unsafe(__first),
>@@ -759,11 +801,8 @@ namespace __debug
> else
> __res = _Base::insert(__position.base(), __first, __last);
>
>- if (_M_base().begin() != __old_begin)
>- this->_M_invalidate_all();
>- else
>- this->_M_invalidate_after_nth(__offset);
>- this->_M_update_guaranteed_capacity();
>+ __guard._M_active = true;
>+ }
> return { __res, this };
> }
> #else
>@@ -775,22 +814,15 @@ namespace __debug
> typename __gnu_debug::_Distance_traits<_InputIterator>::__type __dist;
> __glibcxx_check_insert_range(__position, __first, __last, __dist);
>
>- /* Hard to guess if invalidation will occur, because __last
>- - __first can't be calculated in all cases, so we just
>- punt here by checking if it did occur. */
>- _Base_iterator __old_begin = _M_base().begin();
> difference_type __offset = __position.base() - _Base::begin();
>+ _InsertGuard __guard(*this, __offset);
> if (__dist.second >= __gnu_debug::__dp_sign)
> _Base::insert(__position.base(), __gnu_debug::__unsafe(__first),
> __gnu_debug::__unsafe(__last));
> else
> _Base::insert(__position.base(), __first, __last);
>
>- if (_M_base().begin() != __old_begin)
>- this->_M_invalidate_all();
>- else
>- this->_M_invalidate_after_nth(__offset);
>- this->_M_update_guaranteed_capacity();
>+ __guard._M_active = true;
> }
> #endif
>
>@@ -876,30 +908,20 @@ namespace __debug
> constexpr void
> assign_range(_Rg&& __rg)
> {
>- auto __old_capacity = _Base::capacity();
>- auto __old_size = _Base::size();
>+ _Guard __guard(*this);
> _Base::assign_range(__rg);
>- if (!std::__is_constant_evaluated())
>- {
>- if (_Base::capacity() != __old_capacity)
>- this->_M_invalidate_all();
>- else if (_Base::size() < __old_size)
>- this->_M_invalidate_after_nth(_Base::size());
>- this->_M_update_guaranteed_capacity();
>- }
>+ __guard._M_active = true;
> }
>
> template<__detail::__container_compatible_range<_Tp> _Rg>
> constexpr iterator
> insert_range(const_iterator __pos, _Rg&& __rg)
> {
>- auto __old_capacity = _Base::capacity();
>- auto __res = _Base::insert_range(__pos.base(), __rg);
>- if (!std::__is_constant_evaluated())
>+ _Base_iterator __res;
> {
>- if (_Base::capacity() != __old_capacity)
>- this->_M_invalidate_all();
>- this->_M_update_guaranteed_capacity();
>+ _Guard __guard(*this);
>+ __res = _Base::insert_range(__pos.base(), __rg);
>+ __guard._M_active = true;
> }
> return iterator(__res, this);
> }
>@@ -908,14 +930,9 @@ namespace __debug
> constexpr void
> append_range(_Rg&& __rg)
> {
>- auto __old_capacity = _Base::capacity();
>+ _Guard __guard(*this);
> _Base::append_range(__rg);
>- if (!std::__is_constant_evaluated())
>- {
>- if (_Base::capacity() != __old_capacity)
>- this->_M_invalidate_all();
>- this->_M_update_guaranteed_capacity();
>- }
>+ __guard._M_active = true;
> }
> #endif
>
>@@ -1057,6 +1074,84 @@ _GLIBCXX_END_NAMESPACE_VERSION
>
> namespace __gnu_debug
> {
>+ template<class _Tp, typename _Allocator>
>+ _GLIBCXX20_CONSTEXPR
>+ _SafeVectorGuard<_Tp, _Allocator>::_SafeVectorGuard(
>+ std::__debug::vector<_Tp, _Allocator>& __vector)
>+ : _M_vect(__vector)
>+ , _M_capacity(__vector.capacity())
>+ , _M_size(__vector.size())
>+ , _M_active(false)
>+ { }
>+
>+ template<class _Tp, typename _Allocator>
>+ _GLIBCXX20_CONSTEXPR
>+ _SafeVectorGuard<_Tp, _Allocator>::~_SafeVectorGuard()
>+ {
>+ if (!std::__is_constant_evaluated() && _M_active)
>+ {
>+#ifdef _GLIBCXX_DEBUG_PEDANTIC
>+ if (_M_vect.size() > _M_capacity)
>+#else
>+ if (_M_vect.capacity() != _M_capacity)
>+#endif
I don't understand this condition. What difference does it make, and
why do we want it?
For resize and emplace_back/push_back the two conditions are
equivalent, right? _M_vect.capacity() would not change (i.e.
reallocation would not occur) unless v.size() == v.capacity(),
and in that case v.size() would become greater than capacity.
When are these different?
>+ _M_vect._M_invalidate_all();
>+ else if (_M_vect.size() < _M_size)
>+ _M_vect._M_invalidate_after_nth(_M_vect.size());
>+
>+ _M_vect._M_update_guaranteed_capacity();
>+ }
>+ }
>+
>+#ifdef _GLIBCXX_DEBUG_PEDANTIC
>+ template<class _Tp, typename _Allocator>
>+ _GLIBCXX20_CONSTEXPR
>+ _SafeVectorPedanticGuard<_Tp, _Allocator>::_SafeVectorPedanticGuard(
>+ std::__debug::vector<_Tp, _Allocator>& __vector)
>+ : _M_vect(__vector), _M_active(false)
>+ { }
>+
>+ template<class _Tp, typename _Allocator>
>+ _GLIBCXX20_CONSTEXPR
>+ _SafeVectorPedanticGuard<_Tp, _Allocator>::~_SafeVectorPedanticGuard()
>+ {
>+ if (!std::__is_constant_evaluated() && _M_active)
>+ {
>+ _M_vect._M_invalidate_all();
>+ _M_vect._M_update_guaranteed_capacity();
>+ }
>+ }
>+#endif
>+
>+ template<class _Tp, typename _Allocator>
>+ _GLIBCXX20_CONSTEXPR
>+ _SafeVectorInsertGuard<_Tp, _Allocator>::_SafeVectorInsertGuard(
>+ std::__debug::vector<_Tp, _Allocator>& __vector, difference_type __offset)
>+ : _M_vect(__vector)
>+ , _M_capacity(__vector.capacity())
>+ , _M_offset(__offset)
>+ , _M_active(false)
>+ { }
>+
>+ template<class _Tp, typename _Allocator>
>+ _GLIBCXX20_CONSTEXPR
>+ _SafeVectorInsertGuard<_Tp, _Allocator>::~_SafeVectorInsertGuard()
>+ {
>+ if (!std::__is_constant_evaluated() && _M_active)
>+ {
>+#ifdef _GLIBCXX_DEBUG_PEDANTIC
>+ if (_M_vect.size() > _M_capacity)
>+#else
>+ if (_M_vect.capacity() != _M_capacity)
>+#endif
Same question here.
>+ _M_vect._M_invalidate_all();
>+ else
>+ _M_vect._M_invalidate_after_nth(_M_offset);
>+
>+ _M_vect._M_update_guaranteed_capacity();
>+ }
>+ }
>+
> template<typename _Tp, typename _Alloc>
> struct _Is_contiguous_sequence<std::__debug::vector<_Tp, _Alloc> >
> : std::__true_type
>diff --git a/libstdc++-v3/testsuite/23_containers/vector/cons/destructible_debug_neg.cc b/libstdc++-v3/testsuite/23_containers/vector/cons/destructible_debug_neg.cc
>index 2c9abcdbb91..0a29c0432e6 100644
>--- a/libstdc++-v3/testsuite/23_containers/vector/cons/destructible_debug_neg.cc
>+++ b/libstdc++-v3/testsuite/23_containers/vector/cons/destructible_debug_neg.cc
>@@ -47,4 +47,4 @@ test02()
> // { dg-error "PrivateDtor.* is private" "" { target *-*-* } 0 }
>
> // In Debug Mode the "required from here" errors come from <debug/vector>
>-// { dg-error "required from here" "" { target *-*-* } 182 }
>+// { dg-error "required from here" "" { target *-*-* } 258 }
>diff --git a/libstdc++-v3/testsuite/23_containers/vector/debug/initializer_list.cc b/libstdc++-v3/testsuite/23_containers/vector/debug/initializer_list.cc
>new file mode 100644
>index 00000000000..318f6b98de9
>--- /dev/null
>+++ b/libstdc++-v3/testsuite/23_containers/vector/debug/initializer_list.cc
>@@ -0,0 +1,26 @@
>+// { dg-do compile { target c++11 } }
>+
>+#include <debug/vector>
>+#include <testsuite_hooks.h>
>+
>+void
>+test01()
>+{
>+ __gnu_debug::vector<int> v = { 0, 1, 2, 3, 4, 5 };
>+
>+ auto it1 = v.begin() + 1;
>+ auto it4 = v.begin() + 4;
>+
>+ VERIFY( !it1._M_singular() );
>+ VERIFY( !it4._M_singular() );
>+
>+ v = { 10, 11, 12, 13 };
>+
>+ VERIFY( !it1._M_singular() );
>+ VERIFY( it4._M_singular() );
>+}
>+
>+int main()
>+{
>+ test01();
>+}
>diff --git a/libstdc++-v3/testsuite/23_containers/vector/debug/initializer_list_pedantic.cc b/libstdc++-v3/testsuite/23_containers/vector/debug/initializer_list_pedantic.cc
>new file mode 100644
>index 00000000000..c8b3af25bd1
>--- /dev/null
>+++ b/libstdc++-v3/testsuite/23_containers/vector/debug/initializer_list_pedantic.cc
>@@ -0,0 +1,27 @@
>+// { dg-do compile { target c++11 } }
>+// { dg-options "-D_GLIBCXX_DEBUG_PEDANTIC" }
>+
>+#include <debug/vector>
>+#include <testsuite_hooks.h>
>+
>+void
>+test01()
>+{
>+ __gnu_debug::vector<int> v = { 0, 1, 2, 3, 4, 5 };
>+
>+ auto it1 = v.begin() + 1;
>+ auto it4 = v.begin() + 4;
>+
>+ VERIFY( !it1._M_singular() );
>+ VERIFY( !it4._M_singular() );
>+
>+ v = { 10, 11, 12, 13 };
>+
>+ VERIFY( it1._M_singular() );
>+ VERIFY( it4._M_singular() );
>+}
>+
>+int main()
>+{
>+ test01();
>+}
More information about the Libstdc++
mailing list