Hi

Patch rebased and ready to review.

This is the 1st commit of this PR:

https://forge.sourceware.org/gcc/gcc-TEST/pulls/136

    libstdc++: [_GLIBCXX_DEBUG] Make constant evaluation compatible

    Inline the most basic _GLIBCXX_DEBUG iterator checks _M_singular and _M_can_compare.     In addition to being an optimization it also make those usable in a constant evaluated
    context.

    Provide also a C++20 constexpr _Safe_iterator_base _M_attach_to and _M_detach_sequence     to call instead of respectively _M_attach and _M_detach that will serve maybe later
    to have some _GLIBCXX_DEBUG checks in constexpr expressions.

    Thanks to those changes make most of _GLIBCXX_DEBUG checks C++20 constexpr.

    libstdc++-v3/ChangeLog:

            * include/debug/forward_list (_Sequence_traits::_S_size): Declare as C++20
            constexpr.
            * include/debug/functions.h
            (__foreign_iterator): Declare as C++20 constexpr and add std::__is_constant_evaluated
            check.
            * include/debug/helper_functions.h (__check_singular_aux): Declare as C++20 constexpr.
            * include/debug/list (_Sequence_traits::_S_size): Likewise.
            * include/debug/safe_base.h
            (_Safe_iterator_base::_M_attach_to): New, C++20 constexpr.
            (_Safe_iterator_base(const _Safe_sequence_base*, bool)): Adapt to use latter without
            __is_constant_evaluated check.
            (_Safe_iterator_base(const _Safe_iterator_base&, bool)): Likewise.             (_Safe_iterator_base::_M_detach_sequence): New, C++20 constexpr.             (~_Safe_iterator_base): Adapt to use latter without __is_constant_evaluated check.
            (_Safe_iterator_base::_M_singular): Move private.
            (_Safe_iterator_base::_M_can_compare): Move private.
            (__check_singular_aux(const _Safe_iterator_base*)): Declare as C++20 constexpr and
            implement as such.
            * include/debug/safe_iterator.h
            (_BeforeBeginHelper::_S_Is): Declare as C++20 constexpr.
            (_BeforeBeginHelper::_S_Is_Beginnest): Likewise.
            (_Sequence_traits::_S_size): Likewise.
            (_Safe_iterator::_Iter_base, _Safe_iterator::_Safe_base): Remove.             (_Safe_iterator(const _Safe_iterator&, _Unchecked)): Delegate to correct base classes
            constructors.
            (_Safe_iterator::_M_singular): New, C++20 constexpr.
            (_Safe_iterator::_M_can_compare(const _Safe_iterator_base&)): New, C++20 constexpr.             (_Safe_iterator::_M_attach): Declare as C++20 constexpr, use base class
            _M_attach_to().
            (_Safe_iterator::_M_detach): New, C++20 constexpr, use base class _M_detach_sequence().             (_Safe_iterator::_M_dereferenceable): Declare as C++20 constexpr.
            (_Safe_iterator::_M_before_dereferenceable): Likewise.
            (_Safe_iterator::_M_incrementable): Likewise.
            (_Safe_iterator::_M_value_initialized): Likewise.
            (_Safe_iterator::_M_can_advance): Likewise.
            (_Safe_iterator::_M_valid_range): Likewise.
            (_Safe_iterator::_M_get_sequence): Likewise.
            (_Safe_iterator::_M_get_distance_from_begin): Likewise.
            (_Safe_iterator::_M_get_distance_to_end): Likewise.
            (_Safe_iterator::_M_is_end): Likewise.
            (_Safe_iterator::_M_is_before_begin): Likewise.
            (_Safe_iterator::_M_is_beginnest): Likewise.
            (_Safe_iterator::operator++(int)):
            Declare C++20 constexpr and add __is_constant_evaluated to skip debug check.
            (_Safe_iterator::operator--(int)): Likewise.
            (_Safe_iterator::_M_decrementable): Declare as C++20 constexpr.
            (_Safe_iterator::_M_valid_range): Declare as C++20 constexpr.
            (operator<(const _Safe_iterator&, const _Safe_iterator&)): Likewise.             (operator<=(const _Safe_iterator&, const _Safe_iterator&)): Likewise.             (operator>(const _Safe_iterator&, const _Safe_iterator&)): Likewise.             (operator>=(const _Safe_iterator&, const _Safe_iterator&)): Likewise.
            (operator+(const _Safe_iterator&, difference_type)): Likewise.
            (operator+(difference_type, const _Safe_iterator&)): Likewise.
            (operator-(const _Safe_iterator&, difference_type)): Likewise.
            (operator-(difference_type, const _Safe_iterator&)): Likewise.
            * include/debug/safe_iterator.tcc: Adapt method with C++20 constexpr declaration.
            * include/debug/safe_local_iterator.h
            (_Safe_local_iterator::_Iter_base, _Safe_local_iterator::_Safe_base): Remove.             (_Safe_local_iterator(const _Safe_local_iterator&, _Unchecked)): Delegate to the correct
            base classes constructors.
            (_Safe_local_iterator::_M_singular): New.
            (_Safe_local_iterator::_M_can_compare(const _Safe_iterator_base&)): New.

Tested under Linux x86_64 _GLIBCXX_DEBUG mode.

Ok to commit ?

François

On 4/2/26 08:46, Jonathan Wakely wrote:
Please ping for review after GCC 16 is released.

On Thu, 2 Apr 2026, 07:44 Jonathan Wakely, <[email protected]> wrote:

    This needs to wait for GCC 17

    On Thu, 2 Apr 2026, 06:24 François Dumont, <[email protected]>
    wrote:

        As part of my patch to do some _GLIBCXX_DEBUG checks in constant
        evaluation context:

        https://gcc.gnu.org/pipermail/libstdc++/2026-January/065132.html

        was also an occasion to optimize this mode for the most basic
        checks on
        iterators that are singularity and comparability. Those can
        now be
        inlined instead of going through a library call.

        In this patch I've isolated just those bits that won't have
        any impact
        on constant evaluation. It will just call new _M_attach_to and
        _M_detach_sequence that are doing nothing if in constant
        evaluation.

        As you'll see it also does some code simplifications and mark
        many
        function as C++20 constexpr.


             libstdc++: [_GLIBCXX_DEBUG] Make constant evaluation
        compatible

             Inline the most basic _GLIBCXX_DEBUG iterator checks
        _M_singular
        and _M_can_compare.
             In addition to being an optimization it also make those
        usable in a
        constant evaluated
             context.

             Provide also a C++20 constexpr _Safe_iterator_base
        _M_attach_to and
        _M_detach_sequence
             to call instead of respectively _M_attach and _M_detach
        that will
        serve maybe later
             to have some _GLIBCXX_DEBUG checks in constexpr expressions.

             Thanks to those changes make most of _GLIBCXX_DEBUG
        checks C++20
        constexpr.

             libstdc++-v3/ChangeLog:

                     * include/debug/forward_list
        (_Sequence_traits<>::_S_size):
        Declare as C++20
                     constexpr.
                     * include/debug/functions.h
                     (__foreign_iterator): Declare as C++20 constexpr
        and add
        std::__is_constant_evaluated
                     check.
                     * include/debug/helper_functions.h
        (__check_singular_aux):
        Declare as C++20 constexpr.
                     * include/debug/list
        (_Sequence_traits<>::_S_size): Likewise.
                     * include/debug/safe_base.h
                     (_Safe_iterator_base::_M_attach_to): New, C++20
        constexpr.
                     (_Safe_iterator_base(const _Safe_sequence_base*,
        bool):
        Adapt to use latter without
                     __is_constant_evaluated check.
                     (_Safe_iterator_base(const _Safe_iterator_base&,
        bool)):
        Likewise.
                     (_Safe_iterator_base::_M_detach_sequence): New,
        C++20
        constexpr.
                     (~_Safe_iterator_base()): Adapt to use latter
        without
        __is_constant_evaluated check.
                     (_Safe_iterator_base::_M_singular): Move private.
                     (_Safe_iterator_base::_M_can_compare): Move private.
                     (__check_singular_aux(const
        _Safe_iterator_base*)): Declare
        as C++20 constexpr and
                     implement as such.
                     * include/debug/safe_iterator.h
                     (_BeforeBeginHelper<>::_S_Is): Declare as C++20
        constexpr.
        (_BeforeBeginHelper<>::_S_Is_Beginnest): Likewise.
                     (_Sequence_traits<>::_S_size): Likewise.
                     (_Safe_iterator::_Iter_base,
        _Safe_iterator::_Safe_base):
        Remove.
                     (_Safe_iterator(const _Safe_iterator&, _Unchecked)):
        Delegate to correct base classes
                     constructors.
                     (_Safe_iterator::_M_singular()): New, C++20
        constexpr.
                     (_Safe_iterator::_M_can_compare(const
        _Safe_iterator_base&)): New, C++20 constexpr.
                     (_Safe_iterator::_M_attach()): Declare as C++20
        constexpr,
        use base class
                     _M_attach_to().
                     (_Safe_iterator::_M_detach()): New, C++20
        constexpr, use
        base class _M_detach_sequence().
                     (_Safe_iterator::_M_dereferenceable): Declare as
        C++20
        constexpr.
                     (_Safe_iterator::_M_before_dereferenceable):
        Likewise.
                     (_Safe_iterator::_M_incrementable): Likewise.
                     (_Safe_iterator::_M_value_initialized): Likewise.
                     (_Safe_iterator::_M_can_advance): Likewise.
                     (_Safe_iterator::_M_valid_range): Likewise.
                     (_Safe_iterator::_M_get_sequence): Likewise.
                     (_Safe_iterator::_M_get_distance_from_begin):
        Likewise.
                     (_Safe_iterator::_M_get_distance_to_end): Likewise.
                     (_Safe_iterator::_M_is_end): Likewise.
                     (_Safe_iterator::_M_is_before_begin): Likewise.
                     (_Safe_iterator::_M_is_beginnest): Likewise.
                     (_Safe_iterator::operator++(int)):
                     Declare C++20 constexpr and add
        __is_constant_evaluated to
        skip debug check.
                     (_Safe_iterator::operator--(int)): Likewise.
                     (_Safe_iterator::_M_decrementable): Declare as
        C++20 constexpr.
                     (_Safe_iterator::_M_valid_range): Declare as
        C++20 constexpr.
                     (operator<(const _Safe_iterator&, const
        _Safe_iterator&)):
        Likewise.
                     (operator<=(const _Safe_iterator&, const
        _Safe_iterator&)):
        Likewise.
                     (operator>(const _Safe_iterator&, const
        _Safe_iterator&)):
        Likewise.
                     (operator>=(const _Safe_iterator&, const
        _Safe_iterator&)):
        Likewise.
                     (operator+(const _Safe_iterator&,
        difference_type)): Likewise.
                     (operator+(difference_type, const
        _Safe_iterator&)): Likewise.
                     (operator-(const _Safe_iterator&,
        difference_type)): Likewise.
                     (operator-(difference_type, const
        _Safe_iterator&)): Likewise.
                     * include/debug/safe_iterator.tcc: Adapt method
        with C++20
        constexpr declaration.
                     * include/debug/safe_local_iterator.h
                     (_Safe_local_iterator::_Iter_base,
        _Safe_local_iterator::_Safe_base): Remove.
                     (_Safe_local_iterator(const _Safe_local_iterator&,
        _Unchecked)): Delegate to the correct
                     base classes constructors.
                     (_Safe_local_iterator::_M_singular): New.
                     (_Safe_local_iterator::_M_can_compare(const
        _Safe_iterator_base&)): New.

        Tested under Linux x86_64 _GLIBCXX_DEBUG mode.

        Ok to commit ?

        François
diff --git a/libstdc++-v3/include/debug/forward_list 
b/libstdc++-v3/include/debug/forward_list
index 7d615978000..9a53de8afe2 100644
--- a/libstdc++-v3/include/debug/forward_list
+++ b/libstdc++-v3/include/debug/forward_list
@@ -1030,7 +1030,7 @@ namespace __gnu_debug
     {
       typedef typename std::__debug::forward_list<_Tp, _Alloc>::iterator _It;
 
-      static typename _Distance_traits<_It>::__type
+      static _GLIBCXX20_CONSTEXPR typename _Distance_traits<_It>::__type
       _S_size(const std::__debug::forward_list<_Tp, _Alloc>& __seq)
       {
        return __seq.empty()
diff --git a/libstdc++-v3/include/debug/functions.h 
b/libstdc++-v3/include/debug/functions.h
index d2acba34ef2..33add47f6cf 100644
--- a/libstdc++-v3/include/debug/functions.h
+++ b/libstdc++-v3/include/debug/functions.h
@@ -203,11 +203,14 @@ namespace __gnu_debug
 #if __cplusplus < 201103L
   template<typename _Iterator, typename _Sequence, typename _Category,
           typename _InputIterator>
-    inline bool
+    inline _GLIBCXX20_CONSTEXPR bool
     __foreign_iterator(
        const _Safe_iterator<_Iterator, _Sequence, _Category>& __it,
        _InputIterator __other, _InputIterator __other_end)
     {
+      if (std::__is_constant_evaluated())
+       return true;
+
       typedef typename std::__is_integer<_InputIterator>::__type _Integral;
       return __foreign_iterator_aux(__it, __other, __other_end, _Integral());
     }
diff --git a/libstdc++-v3/include/debug/helper_functions.h 
b/libstdc++-v3/include/debug/helper_functions.h
index 0bd5a1cbdf4..8e3e56ea3b4 100644
--- a/libstdc++-v3/include/debug/helper_functions.h
+++ b/libstdc++-v3/include/debug/helper_functions.h
@@ -124,11 +124,11 @@ namespace __gnu_debug
     }
 
   // An arbitrary iterator pointer is not singular.
-  inline bool
+  inline _GLIBCXX20_CONSTEXPR bool
   __check_singular_aux(const void*) { return false; }
 
   // Defined in <debug/safe_base.h>
-  bool
+  _GLIBCXX20_CONSTEXPR bool
   __check_singular_aux(const class _Safe_iterator_base*);
 
   // We may have an iterator that derives from _Safe_iterator_base but isn't
diff --git a/libstdc++-v3/include/debug/list b/libstdc++-v3/include/debug/list
index d06e9e4c2f8..368128cc5a8 100644
--- a/libstdc++-v3/include/debug/list
+++ b/libstdc++-v3/include/debug/list
@@ -1063,7 +1063,7 @@ namespace __gnu_debug
     {
       typedef typename std::__debug::list<_Tp, _Alloc>::iterator _It;
 
-      static typename _Distance_traits<_It>::__type
+      static _GLIBCXX20_CONSTEXPR typename _Distance_traits<_It>::__type
       _S_size(const std::__debug::list<_Tp, _Alloc>& __seq)
       {
        return __seq.empty()
diff --git a/libstdc++-v3/include/debug/safe_base.h 
b/libstdc++-v3/include/debug/safe_base.h
index 25ac7a4e836..d038364be67 100644
--- a/libstdc++-v3/include/debug/safe_base.h
+++ b/libstdc++-v3/include/debug/safe_base.h
@@ -92,10 +92,7 @@ namespace __gnu_debug
     _GLIBCXX20_CONSTEXPR
     _Safe_iterator_base(const _Safe_sequence_base* __seq, bool __constant)
     : _M_sequence(0), _M_version(0), _M_prior(0), _M_next(0)
-    {
-      if (!std::__is_constant_evaluated())
-       this->_M_attach(__seq, __constant);
-    }
+    { _M_attach_to(__seq, __constant); }
 
     /** Initializes the iterator to reference the same sequence that
        @p __x does. @p __constant is true if this is a constant
@@ -103,22 +100,17 @@ namespace __gnu_debug
     _GLIBCXX20_CONSTEXPR
     _Safe_iterator_base(const _Safe_iterator_base& __x, bool __constant)
     : _M_sequence(0), _M_version(0), _M_prior(0), _M_next(0)
-    {
-      if (!std::__is_constant_evaluated())
-       this->_M_attach(__x._M_sequence, __constant);
-    }
+    { _M_attach_to(__x._M_sequence, __constant); }
 
     _GLIBCXX20_CONSTEXPR
     ~_Safe_iterator_base()
-    {
-      if (!std::__is_constant_evaluated())
-       this->_M_detach();
-    }
+    { _M_detach_sequence(); }
 
     /** For use in _Safe_iterator. */
     __gnu_cxx::__mutex&
     _M_get_mutex() _GLIBCXX_USE_NOEXCEPT;
 
+  private:
     /** Attaches this iterator to the given sequence, detaching it
      * from whatever sequence it was attached to originally. If the
      * new sequence is the NULL pointer, the iterator is left
@@ -127,17 +119,37 @@ namespace __gnu_debug
     void
     _M_attach(const _Safe_sequence_base* __seq, bool __constant);
 
+  protected:
     /** Likewise, but not thread-safe. */
     void
     _M_attach_single(const _Safe_sequence_base* __seq,
                     bool __constant) _GLIBCXX_USE_NOEXCEPT;
 
+    /** Like _M_attach but C++20 constexpr. */
+    _GLIBCXX20_CONSTEXPR void
+    _M_attach_to(const _Safe_sequence_base* __seq, bool __constant);
+
+  private:
     /** Detach the iterator for whatever sequence it is attached to,
      * if any.
     */
     void
     _M_detach();
 
+  public:
+    /** Likewise, but not thread-safe. */
+    void
+    _M_detach_single() _GLIBCXX_USE_NOEXCEPT;
+
+  protected:
+    /** Like _M_detach but C++20 constexpr. */
+    _GLIBCXX20_CONSTEXPR void
+    _M_detach_sequence()
+    {
+      if (!std::__is_constant_evaluated())
+       _M_detach();
+    }
+
 #if !_GLIBCXX_INLINE_VERSION
   private:
     /***************************************************************/
@@ -152,15 +164,12 @@ namespace __gnu_debug
 #endif
 
   public:
-    /** Likewise, but not thread-safe. */
-    void
-    _M_detach_single() _GLIBCXX_USE_NOEXCEPT;
-
     /** Determines if we are attached to the given sequence. */
-    bool
+    _GLIBCXX20_CONSTEXPR bool
     _M_attached_to(const _Safe_sequence_base* __seq) const
     { return _M_sequence == __seq; }
 
+  private:
     /** Is this iterator singular? */
     _GLIBCXX_PURE bool
     _M_singular() const _GLIBCXX_USE_NOEXCEPT;
@@ -171,8 +180,9 @@ namespace __gnu_debug
     _GLIBCXX_PURE bool
     _M_can_compare(const _Safe_iterator_base& __x) const _GLIBCXX_USE_NOEXCEPT;
 
+  public:
     /** Invalidate the iterator, making it singular. */
-    void
+    _GLIBCXX20_CONSTEXPR void
     _M_invalidate()
     { _M_version = 0; }
 
@@ -191,13 +201,6 @@ namespace __gnu_debug
     }
   };
 
-  /** Iterators that derive from _Safe_iterator_base can be determined singular
-   *  or non-singular.
-   **/
-  inline bool
-  __check_singular_aux(const _Safe_iterator_base* __x)
-  { return __x->_M_singular(); }
-
   /**
    * @brief Base class that supports tracking of iterators that
    * reference a sequence.
@@ -352,6 +355,24 @@ namespace __gnu_debug
     void
     _M_detach_single(_Safe_iterator_base* __it) const _GLIBCXX_USE_NOEXCEPT;
   };
-} // namespace __gnu_debug
 
+  /** Iterators that derive from _Safe_iterator_base can be determined singular
+   *  or non-singular.
+   **/
+  inline _GLIBCXX20_CONSTEXPR bool
+  __check_singular_aux(const _Safe_iterator_base* __x)
+  {
+    return
+      !__x->_M_sequence || __x->_M_version != __x->_M_sequence->_M_version;
+  }
+
+  inline _GLIBCXX20_CONSTEXPR void
+  _Safe_iterator_base::_M_attach_to(const _Safe_sequence_base* __seq,
+                                   bool __constant)
+  {
+    if (!std::__is_constant_evaluated())
+      _M_attach(__seq, __constant);
+  }
+
+} // namespace __gnu_debug
 #endif
diff --git a/libstdc++-v3/include/debug/safe_iterator.h 
b/libstdc++-v3/include/debug/safe_iterator.h
index 4da3d2bb3d4..bf17ccb8046 100644
--- a/libstdc++-v3/include/debug/safe_iterator.h
+++ b/libstdc++-v3/include/debug/safe_iterator.h
@@ -88,12 +88,12 @@ namespace __gnu_debug
     struct _BeforeBeginHelper
     {
       template<typename _Iterator, typename _Category>
-       static bool
+       static _GLIBCXX20_CONSTEXPR bool
        _S_Is(const _Safe_iterator<_Iterator, _Sequence, _Category>&)
        { return false; }
 
       template<typename _Iterator, typename _Category>
-       static bool
+       static _GLIBCXX20_CONSTEXPR bool
        _S_Is_Beginnest(const _Safe_iterator<_Iterator, _Sequence, _Category>& 
__it)
        { return __it.base() == __it._M_get_sequence()->_M_base().begin(); }
     };
@@ -104,7 +104,7 @@ namespace __gnu_debug
     {
       typedef _Distance_traits<typename _Sequence::iterator> _DistTraits;
 
-      static typename _DistTraits::__type
+      static _GLIBCXX20_CONSTEXPR typename _DistTraits::__type
       _S_size(const _Sequence& __seq)
       { return std::make_pair(__seq.size(), __dp_exact); }
     };
@@ -131,9 +131,6 @@ namespace __gnu_debug
     : private _Iterator,
       public _Safe_iterator_base
     {
-      typedef _Iterator _Iter_base;
-      typedef _Safe_iterator_base _Safe_base;
-
       typedef std::iterator_traits<_Iterator> _Traits;
 
     protected:
@@ -149,11 +146,8 @@ namespace __gnu_debug
 
       _GLIBCXX20_CONSTEXPR
       _Safe_iterator(const _Safe_iterator& __x, _Unchecked) _GLIBCXX_NOEXCEPT
-      : _Iter_base(__x.base()), _Safe_base()
-      {
-       if (!std::__is_constant_evaluated())
-         _M_attach(__x._M_sequence);
-      }
+      : _Iterator(__x), _Safe_iterator_base(__x, _S_constant())
+      { }
 
     public:
       typedef _Iterator                                        iterator_type;
@@ -169,7 +163,7 @@ namespace __gnu_debug
 
       /// @post the iterator is singular and unattached
       _GLIBCXX20_CONSTEXPR
-      _Safe_iterator() _GLIBCXX_NOEXCEPT : _Iter_base() { }
+      _Safe_iterator() _GLIBCXX_NOEXCEPT : _Iterator() { }
 
       /**
        * @brief Safe iterator construction from an unsafe iterator and
@@ -181,7 +175,7 @@ namespace __gnu_debug
       _GLIBCXX20_CONSTEXPR
       _Safe_iterator(_Iterator __i, const _Safe_sequence_base* __seq)
       _GLIBCXX_NOEXCEPT
-      : _Iter_base(__i), _Safe_base(__seq, _S_constant())
+      : _Iterator(__i), _Safe_iterator_base(__seq, _S_constant())
       { }
 
       /**
@@ -189,7 +183,7 @@ namespace __gnu_debug
        */
       _GLIBCXX20_CONSTEXPR
       _Safe_iterator(const _Safe_iterator& __x) _GLIBCXX_NOEXCEPT
-      : _Iter_base(__x.base()), _Safe_base()
+      : _Iterator(__x), _Safe_iterator_base()
       {
        if (std::__is_constant_evaluated())
          return;
@@ -211,7 +205,7 @@ namespace __gnu_debug
        */
       _GLIBCXX20_CONSTEXPR
       _Safe_iterator(_Safe_iterator&& __x) noexcept
-      : _Iter_base()
+      : _Iterator()
       {
        if (std::__is_constant_evaluated())
          {
@@ -243,7 +237,7 @@ namespace __gnu_debug
              std::__are_same<_MutableIterator, _OtherIterator>::__value,
                               _Category>::__type>& __x)
        _GLIBCXX_NOEXCEPT
-       : _Iter_base(__x.base())
+       : _Iterator(__x.base())
        {
          if (std::__is_constant_evaluated())
            return;
@@ -389,7 +383,7 @@ namespace __gnu_debug
            return *this;
          }
 
-       _GLIBCXX_DEBUG_VERIFY(this->_M_incrementable(),
+       _GLIBCXX_DEBUG_VERIFY(_M_incrementable(),
                              _M_message(__msg_bad_inc)
                              ._M_iterator(*this, "this"));
        _GLIBCXX20_CONSTEXPR_NON_LITERAL_SCOPE_BEGIN {
@@ -409,7 +403,7 @@ namespace __gnu_debug
       {
        if (!std::__is_constant_evaluated())
          {
-           _GLIBCXX_DEBUG_VERIFY(this->_M_incrementable(),
+           _GLIBCXX_DEBUG_VERIFY(_M_incrementable(),
                                  _M_message(__msg_bad_inc)
                                  ._M_iterator(*this, "this"));
          }
@@ -443,26 +437,43 @@ namespace __gnu_debug
       _GLIBCXX20_CONSTEXPR
       operator _Iterator() const _GLIBCXX_NOEXCEPT { return *this; }
 
+      /** Is this iterator singular? */
+      _GLIBCXX20_CONSTEXPR bool
+      _M_singular() const _GLIBCXX_USE_NOEXCEPT
+      {
+       return
+         !this->_M_sequence || _M_version != this->_M_sequence->_M_version;
+      }
+
+      _GLIBCXX20_CONSTEXPR bool
+      _M_can_compare(const _Safe_iterator_base& __x) const 
_GLIBCXX_USE_NOEXCEPT
+      { return this->_M_sequence == __x._M_sequence; }
+
       /** Attach iterator to the given sequence. */
-      void
+      _GLIBCXX20_CONSTEXPR void
       _M_attach(const _Safe_sequence_base* __seq)
-      { _Safe_base::_M_attach(__seq, _S_constant()); }
+      { this->_M_attach_to(__seq, _S_constant()); }
 
       /** Likewise, but not thread-safe. */
       void
       _M_attach_single(const _Safe_sequence_base* __seq)
-      { _Safe_base::_M_attach_single(__seq, _S_constant()); }
+      { this->_M_attach_single(__seq, _S_constant()); }
+
+      /** Detach iterator from the sequence. */
+      _GLIBCXX20_CONSTEXPR void
+      _M_detach()
+      { this->_M_detach_sequence(); }
 
       /// Is the iterator dereferenceable?
-      bool
+      _GLIBCXX20_CONSTEXPR bool
       _M_dereferenceable() const
-      { return !this->_M_singular() && !_M_is_end() && !_M_is_before_begin(); }
+      { return !_M_singular() && !_M_is_end() && !_M_is_before_begin(); }
 
       /// Is the iterator before a dereferenceable one?
-      bool
+      _GLIBCXX20_CONSTEXPR bool
       _M_before_dereferenceable() const
       {
-       if (this->_M_incrementable())
+       if (_M_incrementable())
        {
          _Iterator __base = base();
          return ++__base != _M_get_sequence()->_M_base().end();
@@ -471,33 +482,33 @@ namespace __gnu_debug
       }
 
       /// Is the iterator incrementable?
-      bool
+      _GLIBCXX20_CONSTEXPR bool
       _M_incrementable() const
-      { return !this->_M_singular() && !_M_is_end(); }
+      { return !_M_singular() && !_M_is_end(); }
 
       /// Is the iterator value-initialized?
-      bool
+      _GLIBCXX20_CONSTEXPR bool
       _M_value_initialized() const
-      { return _M_version == 0 && base() == _Iter_base(); }
+      { return _M_version == 0 && base() == _Iterator(); }
 
       // Can we advance the iterator @p __n steps (@p __n may be negative)
-      bool
+      _GLIBCXX20_CONSTEXPR bool
       _M_can_advance(difference_type __n, bool __strict = false) const;
 
       // Can we advance the iterator using @p __dist in @p __way direction.
       template<typename _Diff>
-       bool
+       _GLIBCXX20_CONSTEXPR bool
        _M_can_advance(const std::pair<_Diff, _Distance_precision>& __dist,
                       int __way) const;
 
       // Is the iterator range [*this, __rhs) valid?
-      bool
+      _GLIBCXX20_CONSTEXPR bool
       _M_valid_range(const _Safe_iterator& __rhs,
                     std::pair<difference_type, _Distance_precision>& __dist,
                     bool __check_dereferenceable = true) const;
 
       // The sequence this iterator references.
-      typename __gnu_cxx::__conditional_type<
+      _GLIBCXX20_CONSTEXPR typename __gnu_cxx::__conditional_type<
        _IsConstant::__value, const _Sequence*, _Sequence*>::__type
       _M_get_sequence() const
       {
@@ -513,11 +524,11 @@ namespace __gnu_debug
       _M_get_distance_to(const _Safe_iterator& __rhs) const;
 
       // Get distance from sequence begin up to *this.
-      typename _Distance_traits<_Iterator>::__type
+      _GLIBCXX20_CONSTEXPR typename _Distance_traits<_Iterator>::__type
       _M_get_distance_from_begin() const;
 
       // Get distance from *this to sequence end.
-      typename _Distance_traits<_Iterator>::__type
+      _GLIBCXX20_CONSTEXPR typename _Distance_traits<_Iterator>::__type
       _M_get_distance_to_end() const;
 
       /// Is this iterator equal to the sequence's begin() iterator?
@@ -527,19 +538,19 @@ namespace __gnu_debug
       { return base() == _M_get_sequence()->_M_base().begin(); }
 
       /// Is this iterator equal to the sequence's end() iterator?
-      bool
+      _GLIBCXX20_CONSTEXPR bool
       _M_is_end() const
       { return base() == _M_get_sequence()->_M_base().end(); }
 
       /// Is this iterator equal to the sequence's before_begin() iterator if
       /// any?
-      bool
+      _GLIBCXX20_CONSTEXPR bool
       _M_is_before_begin() const
       { return _BeforeBeginHelper<_Sequence>::_S_Is(*this); }
 
       /// Is this iterator equal to the sequence's before_begin() iterator if
       /// any or begin() otherwise?
-      bool
+      _GLIBCXX20_CONSTEXPR bool
       _M_is_beginnest() const
       { return _BeforeBeginHelper<_Sequence>::_S_Is_Beginnest(*this); }
 
@@ -690,12 +701,16 @@ namespace __gnu_debug
        *  @brief Iterator postincrement
        *  @pre iterator is incrementable
        */
+      _GLIBCXX20_CONSTEXPR
       _Safe_iterator
       operator++(int) _GLIBCXX_NOEXCEPT
       {
-       _GLIBCXX_DEBUG_VERIFY(this->_M_incrementable(),
-                             _M_message(__msg_bad_inc)
-                             ._M_iterator(*this, "this"));
+       if (!std::__is_constant_evaluated())
+         {
+           _GLIBCXX_DEBUG_VERIFY(this->_M_incrementable(),
+                                 _M_message(__msg_bad_inc)
+                                 ._M_iterator(*this, "this"));
+         }
        _Safe_iterator __ret(*this, _Unchecked());
        ++*this;
        return __ret;
@@ -730,12 +745,16 @@ namespace __gnu_debug
        *  @brief Iterator postdecrement
        *  @pre iterator is decrementable
        */
+      _GLIBCXX20_CONSTEXPR
       _Safe_iterator
       operator--(int) _GLIBCXX_NOEXCEPT
       {
-       _GLIBCXX_DEBUG_VERIFY(this->_M_decrementable(),
-                             _M_message(__msg_bad_dec)
-                             ._M_iterator(*this, "this"));
+       if (!std::__is_constant_evaluated())
+         {
+           _GLIBCXX_DEBUG_VERIFY(this->_M_decrementable(),
+                                 _M_message(__msg_bad_dec)
+                                 ._M_iterator(*this, "this"));
+         }
        _Safe_iterator __ret(*this, _Unchecked());
        --*this;
        return __ret;
@@ -744,7 +763,7 @@ namespace __gnu_debug
       // ------ Utilities ------
 
       // Is the iterator decrementable?
-      bool
+      _GLIBCXX20_CONSTEXPR bool
       _M_decrementable() const
       { return !this->_M_singular() && !this->_M_is_begin(); }
     };
@@ -838,7 +857,7 @@ namespace __gnu_debug
 #endif
 
       // Is the iterator range [*this, __rhs) valid?
-      bool
+      _GLIBCXX20_CONSTEXPR bool
       _M_valid_range(const _Safe_iterator& __rhs,
                     std::pair<difference_type,
                               _Distance_precision>& __dist) const;
@@ -983,6 +1002,7 @@ namespace __gnu_debug
       }
 #else
       _GLIBCXX_NODISCARD
+      _GLIBCXX20_CONSTEXPR
       friend bool
       operator<(const _Self& __lhs, const _Self& __rhs) _GLIBCXX_NOEXCEPT
       {
@@ -991,6 +1011,7 @@ namespace __gnu_debug
       }
 
       _GLIBCXX_NODISCARD
+      _GLIBCXX20_CONSTEXPR
       friend bool
       operator<(const _Self& __lhs, const _OtherSelf& __rhs) _GLIBCXX_NOEXCEPT
       {
@@ -999,6 +1020,7 @@ namespace __gnu_debug
       }
 
       _GLIBCXX_NODISCARD
+      _GLIBCXX20_CONSTEXPR
       friend bool
       operator<=(const _Self& __lhs, const _Self& __rhs) _GLIBCXX_NOEXCEPT
       {
@@ -1007,6 +1029,7 @@ namespace __gnu_debug
       }
 
       _GLIBCXX_NODISCARD
+      _GLIBCXX20_CONSTEXPR
       friend bool
       operator<=(const _Self& __lhs, const _OtherSelf& __rhs) _GLIBCXX_NOEXCEPT
       {
@@ -1015,6 +1038,7 @@ namespace __gnu_debug
       }
 
       _GLIBCXX_NODISCARD
+      _GLIBCXX20_CONSTEXPR
       friend bool
       operator>(const _Self& __lhs, const _Self& __rhs) _GLIBCXX_NOEXCEPT
       {
@@ -1023,6 +1047,7 @@ namespace __gnu_debug
       }
 
       _GLIBCXX_NODISCARD
+      _GLIBCXX20_CONSTEXPR
       friend bool
       operator>(const _Self& __lhs, const _OtherSelf& __rhs) _GLIBCXX_NOEXCEPT
       {
@@ -1031,6 +1056,7 @@ namespace __gnu_debug
       }
 
       _GLIBCXX_NODISCARD
+      _GLIBCXX20_CONSTEXPR
       friend bool
       operator>=(const _Self& __lhs, const _Self& __rhs) _GLIBCXX_NOEXCEPT
       {
@@ -1039,6 +1065,7 @@ namespace __gnu_debug
       }
 
       _GLIBCXX_NODISCARD
+      _GLIBCXX20_CONSTEXPR
       friend bool
       operator>=(const _Self& __lhs, const _OtherSelf& __rhs) _GLIBCXX_NOEXCEPT
       {
@@ -1149,7 +1176,7 @@ namespace __gnu_debug
     inline bool
     __can_advance(const _Safe_iterator<_Iterator, _Sequence, _Category>& __it,
                  _Size __n)
-    { 
+    {
       if (std::__is_constant_evaluated())
        return true;
 
@@ -1166,7 +1193,7 @@ namespace __gnu_debug
     {
       if (std::__is_constant_evaluated())
        return true;
-    
+
       return __it._M_can_advance(__dist, __way);
     }
 
diff --git a/libstdc++-v3/include/debug/safe_iterator.tcc 
b/libstdc++-v3/include/debug/safe_iterator.tcc
index 715eceb92f3..3a4bc106ae5 100644
--- a/libstdc++-v3/include/debug/safe_iterator.tcc
+++ b/libstdc++-v3/include/debug/safe_iterator.tcc
@@ -34,7 +34,7 @@
 namespace __gnu_debug
 {
   template<typename _Iterator, typename _Sequence, typename _Category>
-    typename _Distance_traits<_Iterator>::__type
+    _GLIBCXX20_CONSTEXPR typename _Distance_traits<_Iterator>::__type
     _Safe_iterator<_Iterator, _Sequence, _Category>::
     _M_get_distance_from_begin() const
     {
@@ -58,7 +58,7 @@ namespace __gnu_debug
     }
 
   template<typename _Iterator, typename _Sequence, typename _Category>
-    typename _Distance_traits<_Iterator>::__type
+    _GLIBCXX20_CONSTEXPR typename _Distance_traits<_Iterator>::__type
     _Safe_iterator<_Iterator, _Sequence, _Category>::
     _M_get_distance_to_end() const
     {
@@ -82,7 +82,7 @@ namespace __gnu_debug
     }
 
   template<typename _Iterator, typename _Sequence, typename _Category>
-    bool
+    _GLIBCXX20_CONSTEXPR bool
     _Safe_iterator<_Iterator, _Sequence, _Category>::
     _M_can_advance(difference_type __n, bool __strict) const
     {
@@ -109,7 +109,7 @@ namespace __gnu_debug
 
   template<typename _Iterator, typename _Sequence, typename _Category>
     template<typename _Diff>
-      bool
+      _GLIBCXX20_CONSTEXPR bool
       _Safe_iterator<_Iterator, _Sequence, _Category>::
       _M_can_advance(const std::pair<_Diff, _Distance_precision>& __dist,
                     int __way) const
@@ -191,7 +191,7 @@ namespace __gnu_debug
     }
 
   template<typename _Iterator, typename _Sequence, typename _Category>
-    bool
+    _GLIBCXX20_CONSTEXPR bool
     _Safe_iterator<_Iterator, _Sequence, _Category>::
     _M_valid_range(const _Safe_iterator& __rhs,
                   std::pair<difference_type, _Distance_precision>& __dist,
@@ -221,7 +221,7 @@ namespace __gnu_debug
     }
 
   template<typename _Iterator, typename _Sequence>
-    bool
+    _GLIBCXX20_CONSTEXPR bool
     _Safe_iterator<_Iterator, _Sequence, std::random_access_iterator_tag>::
     _M_valid_range(const _Safe_iterator& __rhs,
                   std::pair<difference_type,
diff --git a/libstdc++-v3/include/debug/safe_local_iterator.h 
b/libstdc++-v3/include/debug/safe_local_iterator.h
index d37168a040b..e4579506b57 100644
--- a/libstdc++-v3/include/debug/safe_local_iterator.h
+++ b/libstdc++-v3/include/debug/safe_local_iterator.h
@@ -65,9 +65,6 @@ namespace __gnu_debug
     : private _Iterator
     , public _Safe_local_iterator_base
     {
-      typedef _Iterator _Iter_base;
-      typedef _Safe_local_iterator_base _Safe_base;
-
       typedef typename _UContainer::size_type size_type;
 
       typedef std::iterator_traits<_Iterator> _Traits;
@@ -85,10 +82,9 @@ namespace __gnu_debug
 
       struct _Unchecked { };
 
-      _Safe_local_iterator(const _Safe_local_iterator& __x,
-                          _Unchecked) noexcept
-      : _Iter_base(__x.base())
-      { _M_attach(__x._M_safe_container()); }
+      _Safe_local_iterator(const _Safe_local_iterator& __x, _Unchecked) 
noexcept
+      : _Iterator(__x), _Safe_local_iterator_base(__x, _S_constant())
+      { }
 
     public:
       typedef _Iterator                                        iterator_type;
@@ -99,7 +95,7 @@ namespace __gnu_debug
       typedef typename _Traits::pointer                        pointer;
 
       /// @post the iterator is singular and unattached
-      _Safe_local_iterator() noexcept : _Iter_base() { }
+      _Safe_local_iterator() noexcept : _Iterator() { }
 
       /**
        * @brief Safe iterator construction from an unsafe iterator and
@@ -110,14 +106,14 @@ namespace __gnu_debug
        */
       _Safe_local_iterator(_Iterator __i,
                           const _Safe_unordered_container_base* __cont)
-      : _Iter_base(__i), _Safe_base(__cont, _S_constant())
+      : _Iterator(__i), _Safe_local_iterator_base(__cont, _S_constant())
       { }
 
       /**
        * @brief Copy construction.
        */
       _Safe_local_iterator(const _Safe_local_iterator& __x) noexcept
-      : _Iter_base(__x.base())
+      : _Iterator(__x)
       {
        // _GLIBCXX_RESOLVE_LIB_DEFECTS
        // DR 408. Is vector<reverse_iterator<char*> > forbidden?
@@ -134,7 +130,7 @@ namespace __gnu_debug
        * @post __x is singular and unattached
        */
       _Safe_local_iterator(_Safe_local_iterator&& __x) noexcept
-      : _Iter_base()
+      : _Iterator()
       {
        _GLIBCXX_DEBUG_VERIFY(!__x._M_singular()
                              || __x._M_value_initialized(),
@@ -157,7 +153,7 @@ namespace __gnu_debug
          typename __gnu_cxx::__enable_if<_IsConstant::__value &&
            std::__are_same<_MutableIterator, _OtherIterator>::__value,
                                          _UContainer>::__type>& __x) noexcept
-       : _Iter_base(__x.base())
+       : _Iterator(__x.base())
        {
          // _GLIBCXX_RESOLVE_LIB_DEFECTS
          // DR 408. Is vector<reverse_iterator<char*> > forbidden?
@@ -240,7 +236,7 @@ namespace __gnu_debug
       reference
       operator*() const
       {
-       _GLIBCXX_DEBUG_VERIFY(this->_M_dereferenceable(),
+       _GLIBCXX_DEBUG_VERIFY(_M_dereferenceable(),
                              _M_message(__msg_bad_deref)
                              ._M_iterator(*this, "this"));
        return *base();
@@ -253,7 +249,7 @@ namespace __gnu_debug
       pointer
       operator->() const
       {
-       _GLIBCXX_DEBUG_VERIFY(this->_M_dereferenceable(),
+       _GLIBCXX_DEBUG_VERIFY(_M_dereferenceable(),
                              _M_message(__msg_bad_deref)
                              ._M_iterator(*this, "this"));
        return base().operator->();
@@ -267,7 +263,7 @@ namespace __gnu_debug
       _Safe_local_iterator&
       operator++()
       {
-       _GLIBCXX_DEBUG_VERIFY(this->_M_incrementable(),
+       _GLIBCXX_DEBUG_VERIFY(_M_incrementable(),
                              _M_message(__msg_bad_inc)
                              ._M_iterator(*this, "this"));
        __gnu_cxx::__scoped_lock __l(this->_M_get_mutex());
@@ -282,7 +278,7 @@ namespace __gnu_debug
       _Safe_local_iterator
       operator++(int)
       {
-       _GLIBCXX_DEBUG_VERIFY(this->_M_incrementable(),
+       _GLIBCXX_DEBUG_VERIFY(_M_incrementable(),
                              _M_message(__msg_bad_inc)
                              ._M_iterator(*this, "this"));
        _Safe_local_iterator __ret(*this, _Unchecked{});
@@ -318,30 +314,42 @@ namespace __gnu_debug
        */
       operator _Iterator() const { return *this; }
 
+      /** Is this iterator singular? */
+      _GLIBCXX20_CONSTEXPR bool
+      _M_singular() const noexcept
+      {
+       return
+         !this->_M_sequence || _M_version != this->_M_sequence->_M_version;
+      }
+
+      _GLIBCXX20_CONSTEXPR bool
+      _M_can_compare(const _Safe_iterator_base& __x) const noexcept
+      { return this->_M_sequence == __x._M_sequence; }
+
       /** Attach iterator to the given unordered container. */
       void
       _M_attach(const _Safe_unordered_container_base* __cont)
-      { _Safe_base::_M_attach(__cont, _S_constant()); }
+      { this->_M_attach(__cont, _S_constant()); }
 
       /** Likewise, but not thread-safe. */
       void
       _M_attach_single(const _Safe_unordered_container_base* __cont)
-      { _Safe_base::_M_attach_single(__cont, _S_constant()); }
+      { this->_M_attach_single(__cont, _S_constant()); }
 
       /// Is the iterator dereferenceable?
       bool
       _M_dereferenceable() const
-      { return !this->_M_singular() && !_M_is_end(); }
+      { return !_M_singular() && !_M_is_end(); }
 
       /// Is the iterator incrementable?
       bool
       _M_incrementable() const
-      { return !this->_M_singular() && !_M_is_end(); }
+      { return !_M_singular() && !_M_is_end(); }
 
       /// Is the iterator value-initialized?
       bool
       _M_value_initialized() const
-      { return _M_version == 0 && base() == _Iter_base{}; }
+      { return _M_version == 0 && base() == _Iterator{}; }
 
       // Is the iterator range [*this, __rhs) valid?
       bool

Reply via email to