[PATCH][_GLIBCXX_DEBUG] Enhance __gnu_debug::vector iterator invalidation

François Dumont frs.dumont@gmail.com
Fri Jul 10 09:26:31 GMT 2026


Thanks for confirming Standard behavior and here is the updated patch then:

     libstdc++: [_GLIBCXX_DEBUG] Enhance std::__debug::vector iterator 
invalidation

     Rework the way std::__debug::vector's iterators are being 
invalidated. Use a RAII
     approach so that iterators are invalidated at guard destruction 
based on the state
     of the container.

     libstdc++-v3/ChangeLog:

             * include/debug/assertions.h [_GLIBCXX_DEBUG_STD_C]: New macro.
             * include/debug/vector (_Safe_vector<_Tp, _Allocator>): 
Update template parameters.
             (_Safe_vector::_M_seq): Remove const qualification.
             (_Safe_vector::_M_requires_reallocation): Remove.
             (_Safe_vector::_Guard): New.
             (vector::_ResizeInvalidationPolicy): New.
             (vector::_InvalidateAllPolicy): New.
             (vector::_InsertInvalidationPolicy): New.
             (vector::_ReallocInvalidationPolicy): New.
             (vector::_ResizeGuard): New.
             (vector::_AssignGuard): New.
             (vector::_InsertGuard): New.
             (vector::_ReallocGuard): New.
             (vector): Adapt methods to use new guard types.
             * testsuite/23_containers/vector/capacity/shrink_to_fit.cc: 
Adapt check, size shall
             be lower-or-equal to capacity, not strictly lower.
             * 
testsuite/23_containers/vector/cons/destructible_debug_neg.cc: Adapt 
error line
             number.
             * testsuite/23_containers/vector/debug/initializer_list.cc: 
New test case.

Tested under Linux x86_64 _GLIBCXX_DEBUG, C++98 and default modes.

Ok to commit ?

François

On 7/7/26 15:40, Jonathan Wakely wrote:
> On Sun, 31 May 2026 at 22:17 +0200, François Dumont wrote:
>>
>> On 5/28/26 13:46, Jonathan Wakely wrote:
>>> 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 :-)
>>
>> In this message:
>>
>> https://gcc.gnu.org/pipermail/libstdc++/2025-November/064301.html
>>
>> You said:
>>
>> Is it too aggressive to invalidate all iterators?
>>
>> I know the generic Sequence requirements say that assign(i, j)
>> invalidates all iterators, but I think maybe that's a defect.
>>
>> As std::vector is also a Sequence I thought you were talking about 
>> both inplace_vector and vector.
>
> I was only talking about inplace_vector, not all sequences.
>
> And I did raise this with LWG and I was convinced by Tim Song and
> Tomasz that I'm wrong. The invalidation rules for inplace_vector
> should be the same as for vector, and it makes sense to invalidate all
> iterators on assignment.
>
> Tim pointed out that the objects have been overwritten, so they're not
> the "same" elements after the assignment.
>
> So pointers to the old elements are still pointers to something, but
> not the same elements. Iterators are not pointers, and should be
> invalidated.
>
> Tomasz pointed out that some assignments are implemented via trivial
> copies (i.e. memcpy) and so logically we actually replace the objects
> with new obejcts, i.e. the lifetime of the old object ends and a new
> object begins its lifetime in the same storage.
>
> So we do not want to relax the invalidation rules for assignment (this
> applies to your inplace_vector patch as well as this one).
>
>
>> Maybe I over interpreted it but I also think that when you are 
>> assigning a vector to some new content the iterators do not have to 
>> be invalidated.
>>
>> Reading this email again I think I'll have to consider the problem of 
>> the end iterator, in a future patch...
>>
>>>> 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.
>>
>> Yes, I wonder if I could use only 1 implementation for both but I 
>> think it would make this implementation more complicated to get it 
>> right.
>>
>> Ideally we should have a 4th implementation just invalidating all 
>> iterators in case of reallocation. I preferred to use 
>> _SafeVectorGuard (_ResizeGuard) in this case, which is fine to use 
>> when size if always increased like in push_back or emplace_back.
>>
>>>
>>> Would it be more clear to have _ResizeGuard, _AssignGuard (which
>>> changes behaviour for pedantic vs non-pedantic), and _InsertGuard?
>>>
>> I've adopted those names.
>>
>> And doing so I changed the type of guard used in assign_range and 
>> insert_range.
>>
>>>>
>>>> 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.
>>
>> Yes, looks better. Only _ResizeGuard looks a little bit surprising in 
>> push_back/emplace_back/append_Range.
>>
>> Maybe I should define _ReallocGuard for those methods, even it would 
>> just be another alias of _SafeVectorGuard.
>>
>>>
>>>> +#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?
>>
>> When _GLIBCXX_DEBUG_PEDANTIC _M_vect.capacity() returns a 'guaranteed 
>> capacity' and not the actual underlying vector capacity.
>>
>> This guaranteed capacity can change on emplace_back/push_back. The 
>> problem is that it is updated later in the guard destructor, on the 
>> call to _M_update_guaranteed_capacity().
>>
>> Thinking about it to reply I realized that I should not preserve 
>> original code order and just update guaranteed capacity first so that 
>> I only need (_M_vect.capacity() != _M_capacity) check.
>>
>>>
>>>> +        _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();
>>>> +}
>>>
>> Here is the new patch.
>>
>> Tested under Linux x86_64 w/o _GLIBCXX_DEBUG mode.
>>
>> Ok to commit ?
>>
>> 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 56645d1e92c..ad79ec00919 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,81 @@ namespace __gnu_debug
>>       _M_guaranteed_capacity = _M_seq().size();
>>       }
>>     };
>> +
>> +  /** @brief Guard class for iterators of vector invalidation.
>> +   *
>> +   * This guard invalidates on destroy, if activated, all iterators if
>> +   * reallocation took place and all iterators after updated size 
>> otherwise.
>> +   */
>> +  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
>> +  /** @brief Guard class for iterators of vector invalidation.
>> +   *
>> +   * This guard invalidates on destroy, if activated, all iterators
>> +   * no matter what happenned to the vector.
>> +   */
>> +  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
>> +
>> +  /** @brief Guard class for iterators of vector invalidation.
>> +   *
>> +   * This guard invalidates on destroy, if activated, all iterators if
>> +   * reallocation took place and all iterators after an offset 
>> otherwise.
>> +   */
>> +  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();
>> +    };
>> }
>>
>> namespace std _GLIBCXX_VISIBILITY(default)
>> @@ -128,14 +200,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> 
>> _ResizeGuard;
>> +#ifdef _GLIBCXX_DEBUG_PEDANTIC
>> +      typedef __gnu_debug::_SafeVectorPedanticGuard<_Tp, _Allocator>
>> +    _AssignGuard;
>> +#else
>> +      typedef _ResizeGuard _AssignGuard;
>> +#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 +367,9 @@ namespace __debug
>>       vector&
>>       operator=(initializer_list<value_type> __l)
>>       {
>> +    _AssignGuard __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 +391,23 @@ namespace __debug
>>       typename __gnu_debug::_Distance_traits<_InputIterator>::__type 
>> __dist;
>>       __glibcxx_check_valid_range2(__first, __last, __dist);
>>
>> +      _AssignGuard __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)
>>       {
>> +    _AssignGuard __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 +415,9 @@ namespace __debug
>>       void
>>       assign(initializer_list<value_type> __l)
>>       {
>> +    _AssignGuard __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 +510,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);
>> +    _ResizeGuard __guard(*this);
>>     _Base::resize(__sz);
>> -    if (__realloc)
>> -      this->_M_invalidate_all();
>> -    this->_M_update_guaranteed_capacity();
>> +    __guard._M_active = true;
>>       }
>>
>>       _GLIBCXX20_CONSTEXPR
>> @@ -444,25 +522,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);
>> +    _ResizeGuard __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);
>> +    _ResizeGuard __guard(*this);
>>     _Base::resize(__sz, __c);
>> -    if (__realloc)
>> -      this->_M_invalidate_all();
>> -    this->_M_update_guaranteed_capacity();
>> +    __guard._M_active = true;
>>       }
>> #endif
>>
>> @@ -506,7 +576,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 +653,9 @@ namespace __debug
>>     if (std::__is_constant_evaluated())
>>       return _Base::push_back(__x);
>>
>> -    bool __realloc = this->_M_requires_reallocation(this->size() + 1);
>> +    _ResizeGuard __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 +678,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);
>> +      _ResizeGuard __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 +711,14 @@ namespace __debug
>>                 this);
>>
>>       __glibcxx_check_insert(__position);
>> -      bool __realloc = this->_M_requires_reallocation(this->size() + 
>> 1);
>> -      difference_type __offset = __position.base() - _Base::cbegin();
>> -      _Base_iterator __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();
>> +      _Base_iterator __res;
>> +      {
>> +        difference_type __offset = __position.base() - _Base::cbegin();
>> +        _InsertGuard __guard(*this, __offset);
>> +        __res = _Base::emplace(__position.base(),
>> +                   std::forward<_Args>(__args)...);
>> +        __guard._M_active = true;
>> +      }
>>       return { __res, this };
>>     }
>> #endif
>> @@ -670,14 +735,13 @@ namespace __debug
>>       return iterator(_Base::insert(__position.base(), __x), this);
>>
>>     __glibcxx_check_insert(__position);
>> -    bool __realloc = this->_M_requires_reallocation(this->size() + 1);
>> -    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();
>> +    _Base_iterator __res;
>> +    {
>> +      difference_type __offset = __position.base() - _Base::begin();
>> +      _InsertGuard __guard(*this, __offset);
>> +      __res = _Base::insert(__position.base(), __x);
>> +      __guard._M_active = true;
>> +    }
>>     return iterator(__res, this);
>>       }
>>
>> @@ -704,14 +768,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);
>> -    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();
>> +    _Base_iterator __res;
>> +    {
>> +      difference_type __offset = __position.base() - _Base::cbegin();
>> +      _InsertGuard __guard(*this, __offset);
>> +      __res = _Base::insert(__position.base(), __n, __x);
>> +      __guard._M_active = true;
>> +    }
>>     return { __res, this };
>>       }
>> #else
>> @@ -719,14 +782,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,24 +805,19 @@ 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;
>> -      if (__dist.second >= __gnu_debug::__dp_sign)
>> -        __res = _Base::insert(__position.base(),
>> -                  __gnu_debug::__unsafe(__first),
>> -                  __gnu_debug::__unsafe(__last));
>> -      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();
>> +      {
>> +        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),
>> +                    __gnu_debug::__unsafe(__last));
>> +        else
>> +          __res = _Base::insert(__position.base(), __first, __last);
>> +
>> +        __guard._M_active = true;
>> +      }
>>       return { __res, this };
>>     }
>> #else
>> @@ -775,22 +829,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,31 +923,22 @@ namespace __debug
>>     constexpr void
>>     assign_range(_Rg&& __rg)
>>     {
>> -      auto __old_capacity = _Base::capacity();
>> -      auto __old_size = _Base::size();
>> +      _AssignGuard __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())
>> -        {
>> -          if (_Base::capacity() != __old_capacity)
>> -        this->_M_invalidate_all();
>> -          this->_M_update_guaranteed_capacity();
>> -        }
>> +      _Base_iterator __res;
>> +      {
>> +        difference_type __offset = __pos.base() - _Base::cbegin();
>> +        _InsertGuard __guard(*this, __offset);
>> +        __res = _Base::insert_range(__pos.base(), __rg);
>> +        __guard._M_active = true;
>> +      }
>>       return iterator(__res, this);
>>     }
>>
>> @@ -908,14 +946,9 @@ namespace __debug
>>     constexpr void
>>     append_range(_Rg&& __rg)
>>     {
>> -      auto __old_capacity = _Base::capacity();
>> +      _ResizeGuard __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 +1090,76 @@ _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)
>> +    {
>> +      _M_vect._M_update_guaranteed_capacity();
>> +
>> +      if (_M_vect.capacity() != _M_capacity)
>> +        _M_vect._M_invalidate_all();
>> +      else if (_M_vect.size() < _M_size)
>> +        _M_vect._M_invalidate_after_nth(_M_vect.size());
>> +    }
>> +    }
>> +
>> +#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_update_guaranteed_capacity();
>> +      _M_vect._M_invalidate_all();
>> +    }
>> +    }
>> +#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)
>> +    {
>> +      _M_vect._M_update_guaranteed_capacity();
>> +
>> +      if (_M_vect.capacity() != _M_capacity)
>> +        _M_vect._M_invalidate_all();
>> +      else
>> +        _M_vect._M_invalidate_after_nth(_M_offset);
>> +    }
>> +    }
>> +
>>   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..ccd5dc38e33 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 *-*-* } 273 }
>> 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();
>> +}
>
-------------- next part --------------
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 56645d1e92c..6b665dbf244 100644
--- a/libstdc++-v3/include/debug/vector
+++ b/libstdc++-v3/include/debug/vector
@@ -51,15 +51,17 @@ namespace __gnu_debug
    * detecting code which relies on non-portable implementation details of
    * the libstdc++ reallocation policy.
    */
-  template<typename _SafeSequence,
-	   typename _BaseSequence>
+  template<typename _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;
+      typedef typename _StdVector::difference_type difference_type;
 
       _GLIBCXX20_CONSTEXPR
-      const _SafeSequence&
-      _M_seq() const { return *static_cast<const _SafeSequence*>(this); }
+      _SafeSequence&
+      _M_seq() { return *static_cast<_SafeSequence*>(this); }
 
     protected:
       _GLIBCXX20_CONSTEXPR
@@ -103,10 +105,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
@@ -114,6 +112,31 @@ namespace __gnu_debug
 	if (_M_seq().size() > _M_guaranteed_capacity)
 	  _M_guaranteed_capacity = _M_seq().size();
       }
+
+      template<typename _InvalidationPolicy>
+	struct _Guard
+	{
+	  bool _M_active;
+
+	  _GLIBCXX20_CONSTEXPR
+	  _Guard(_Safe_vector& __vector, difference_type __offset = 0)
+	  : _M_active(false), _M_vector(__vector)
+	  , _M_invalidation_policy(__vector._M_seq(), __offset) { }
+
+	  _GLIBCXX20_CONSTEXPR
+	  ~_Guard()
+	  {
+	    if (!std::__is_constant_evaluated() && _M_active)
+	      {
+		_M_vector._M_update_guaranteed_capacity();
+		_M_invalidation_policy(_M_vector._M_seq());
+	      }
+	  }
+
+	private:
+	  _Safe_vector& _M_vector;
+	  _InvalidationPolicy _M_invalidation_policy;
+	};
     };
 }
 
@@ -128,14 +151,93 @@ 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;
+
+    public:
+      typedef typename _Base::size_type			size_type;
+      typedef typename _Base::difference_type		difference_type;
+
+    private:
+      struct _ResizeInvalidationPolicy
+      {
+	size_type _M_capacity, _M_size;
+
+	_GLIBCXX20_CONSTEXPR
+	_ResizeInvalidationPolicy(const vector& __vector, difference_type)
+	: _M_capacity(__vector.capacity()), _M_size(__vector.size()) { }
+
+	void
+	operator()(vector& __vector) const _GLIBCXX_NOEXCEPT
+	{
+	  if (__vector.capacity() != _M_capacity)
+	    __vector._M_invalidate_all();
+	  else if (__vector.size() < _M_size)
+	    __vector._M_invalidate_after_nth(__vector.size());
+	}
+      };
+
+      struct _InvalidateAllPolicy
+      {
+	_GLIBCXX20_CONSTEXPR
+	_InvalidateAllPolicy(const vector&, difference_type) { }
+
+	void
+	operator()(vector& __vector) const _GLIBCXX_NOEXCEPT
+	{ __vector._M_invalidate_all(); }
+      };
+
+      struct _InsertInvalidationPolicy
+      {
+	size_type _M_capacity;
+	difference_type _M_offset;
+
+	_GLIBCXX20_CONSTEXPR
+	_InsertInvalidationPolicy(const vector& __vector,
+				  difference_type __offset)
+	: _M_capacity(__vector.capacity()), _M_offset(__offset) { }
+
+	void
+	operator()(vector& __vector) const _GLIBCXX_NOEXCEPT
+	{
+	  if (__vector.capacity() != _M_capacity)
+	    __vector._M_invalidate_all();
+	  else
+	    __vector._M_invalidate_after_nth(_M_offset);
+	}
+      };
+
+      struct _ReallocInvalidationPolicy
+      {
+	size_type _M_capacity;
+
+	_GLIBCXX20_CONSTEXPR
+	_ReallocInvalidationPolicy(const vector& __vector, difference_type)
+	: _M_capacity(__vector.capacity()) { }
+
+	void
+	operator()(vector& __vector) const _GLIBCXX_NOEXCEPT
+	{
+	  if (__vector.capacity() != _M_capacity)
+	    __vector._M_invalidate_all();
+	}
+      };
+
+      typedef typename _Safe_vector::
+	template _Guard<_ResizeInvalidationPolicy> _ResizeGuard;
+
+      typedef typename _Safe_vector::
+	template _Guard<_InvalidateAllPolicy> _AssignGuard;
+
+      typedef typename _Safe_vector::
+	template _Guard<_InsertInvalidationPolicy> _InsertGuard;
+
+      typedef typename _Safe_vector::
+	template _Guard<_ReallocInvalidationPolicy> _ReallocGuard;
 
       typedef typename _Base::iterator		_Base_iterator;
       typedef typename _Base::const_iterator	_Base_const_iterator;
@@ -163,9 +265,6 @@ namespace __debug
       typedef __gnu_debug::_Safe_iterator<
 	_Base_const_iterator, vector>			const_iterator;
 
-      typedef typename _Base::size_type			size_type;
-      typedef typename _Base::difference_type		difference_type;
-
       typedef _Tp					value_type;
       typedef _Allocator				allocator_type;
       typedef typename _Base::pointer			pointer;
@@ -276,12 +375,9 @@ namespace __debug
       vector&
       operator=(initializer_list<value_type> __l)
       {
+	_AssignGuard __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 +399,23 @@ namespace __debug
 	  typename __gnu_debug::_Distance_traits<_InputIterator>::__type __dist;
 	  __glibcxx_check_valid_range2(__first, __last, __dist);
 
+	  _AssignGuard __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)
       {
+	_AssignGuard __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 +423,9 @@ namespace __debug
       void
       assign(initializer_list<value_type> __l)
       {
+	_AssignGuard __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 +518,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);
+	_ResizeGuard __guard(*this);
 	_Base::resize(__sz);
-	if (__realloc)
-	  this->_M_invalidate_all();
-	this->_M_update_guaranteed_capacity();
+	__guard._M_active = true;
       }
 
       _GLIBCXX20_CONSTEXPR
@@ -444,25 +530,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);
+	_ResizeGuard __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);
+	_ResizeGuard __guard(*this);
 	_Base::resize(__sz, __c);
-	if (__realloc)
-	  this->_M_invalidate_all();
-	this->_M_update_guaranteed_capacity();
+	__guard._M_active = true;
       }
 #endif
 
@@ -506,7 +584,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 +661,9 @@ namespace __debug
 	if (std::__is_constant_evaluated())
 	  return _Base::push_back(__x);
 
-	bool __realloc = this->_M_requires_reallocation(this->size() + 1);
+	_ReallocGuard __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 +686,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);
+	  _ReallocGuard __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 +719,15 @@ namespace __debug
 			    this);
 
 	  __glibcxx_check_insert(__position);
-	  bool __realloc = this->_M_requires_reallocation(this->size() + 1);
 	  difference_type __offset = __position.base() - _Base::cbegin();
-	  _Base_iterator __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();
+	  _Base_iterator __res;
+	  {
+	    // Scoped guard to avoid invalidation of the returned iterator.
+	    _InsertGuard __guard(*this, __offset);
+	    __res = _Base::emplace(__position.base(),
+				   std::forward<_Args>(__args)...);
+	    __guard._M_active = true;
+	  }
 	  return { __res, this };
 	}
 #endif
@@ -670,14 +744,14 @@ namespace __debug
 	  return iterator(_Base::insert(__position.base(), __x), this);
 
 	__glibcxx_check_insert(__position);
-	bool __realloc = this->_M_requires_reallocation(this->size() + 1);
 	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();
+	_Base_iterator __res;
+	{
+	  // Scoped guard to avoid invalidation of the returned iterator.
+	  _InsertGuard __guard(*this, __offset);
+	  __res = _Base::insert(__position.base(), __x);
+	  __guard._M_active = true;
+	}
 	return iterator(__res, this);
       }
 
@@ -704,14 +778,14 @@ namespace __debug
 	  return iterator(_Base::insert(__position.base(), __n, __x), this);
 
 	__glibcxx_check_insert(__position);
-	bool __realloc = this->_M_requires_reallocation(this->size() + __n);
 	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();
+	_Base_iterator __res;
+	{
+	  // Scoped guard to avoid invalidation of the returned iterator.
+	  _InsertGuard __guard(*this, __offset);
+	  __res = _Base::insert(__position.base(), __n, __x);
+	  __guard._M_active = true;
+	}
 	return { __res, this };
       }
 #else
@@ -719,14 +793,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,24 +816,20 @@ 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;
-	  if (__dist.second >= __gnu_debug::__dp_sign)
-	    __res = _Base::insert(__position.base(),
-				  __gnu_debug::__unsafe(__first),
-				  __gnu_debug::__unsafe(__last));
-	  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();
+	  {
+	    // Scoped guard to avoid invalidation of the returned iterator.
+	    _InsertGuard __guard(*this, __offset);
+	    if (__dist.second >= __gnu_debug::__dp_sign)
+	      __res = _Base::insert(__position.base(),
+				    __gnu_debug::__unsafe(__first),
+				    __gnu_debug::__unsafe(__last));
+	    else
+	      __res = _Base::insert(__position.base(), __first, __last);
+
+	    __guard._M_active = true;
+	  }
 	  return { __res, this };
 	}
 #else
@@ -775,22 +841,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,31 +935,23 @@ namespace __debug
 	constexpr void
 	assign_range(_Rg&& __rg)
 	{
-	  auto __old_capacity = _Base::capacity();
-	  auto __old_size = _Base::size();
+	  _AssignGuard __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())
-	    {
-	      if (_Base::capacity() != __old_capacity)
-		this->_M_invalidate_all();
-	      this->_M_update_guaranteed_capacity();
-	    }
+	  difference_type __offset = __pos.base() - _Base::cbegin();
+	  _Base_iterator __res;
+	  {
+	    // Scoped guard to avoid invalidation of the returned iterator.
+	    _InsertGuard __guard(*this, __offset);
+	    __res = _Base::insert_range(__pos.base(), __rg);
+	    __guard._M_active = true;
+	  }
 	  return iterator(__res, this);
 	}
 
@@ -908,14 +959,9 @@ namespace __debug
 	constexpr void
 	append_range(_Rg&& __rg)
 	{
-	  auto __old_capacity = _Base::capacity();
+	  _ReallocGuard __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
 
diff --git a/libstdc++-v3/testsuite/23_containers/vector/capacity/shrink_to_fit.cc b/libstdc++-v3/testsuite/23_containers/vector/capacity/shrink_to_fit.cc
index d4aa4d89b56..6ca1ac8822a 100644
--- a/libstdc++-v3/testsuite/23_containers/vector/capacity/shrink_to_fit.cc
+++ b/libstdc++-v3/testsuite/23_containers/vector/capacity/shrink_to_fit.cc
@@ -28,7 +28,7 @@ void test01()
   std::vector<int> v(100);
   v.push_back(1);
   v.push_back(1);
-  VERIFY( v.size() < v.capacity() );
+  VERIFY( v.size() <= v.capacity() );
   v.shrink_to_fit();
 #ifdef __glibcxx_allocate_at_least
   unsigned limit = __STDCPP_DEFAULT_NEW_ALIGNMENT__ / sizeof(int);
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..048c26f47c6 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 *-*-* } 281 }
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..67146290d8a
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/vector/debug/initializer_list.cc
@@ -0,0 +1,26 @@
+// { dg-do run { 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();
+}


More information about the Libstdc++ mailing list