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