On 1/27/26 11:31, Jonathan Wakely wrote:
On Tue, 27 Jan 2026 at 08:30, Tomasz Kaminski <[email protected]> wrote:
On Mon, Jan 26, 2026 at 10:25 PM François Dumont <[email protected]> wrote:
Hi
libstdc++: [_GLIBCXX_DEBUG] Make constant evaluation compatible
In a constant evaluation context the _GLIBCXX_DEBUG is working in a
degradated mode where only iterators are keeping a link to their
container,
the container won't have a list of its iterators.
In std::__debug::vector and std::__debug::inplace_vector remove all
calls to
std::is_constant_evaluated and code associated to it when returning
true. The
same code is now used in both contexts.
What are the exact benefits of this change? During constant evaluation we
already
detect all UB caused by access via invalid or past the end pointers, so most of
the
cases are detected.
As this will have non-trivial impact on compile-times of programs operation on
vector at compile time (including c++26) reflection, I would like to see a more
concrete
cost (how much longer a decently size example using reflection compilers) vs
benefits
(examples of situations where this new implementation will detect breach of
library preconditions,
that are not already detected).
In this new version I've added an example of breach.
_GLIBCXX_DEBUG mode is already known to be costly and is documented as
having a performance impact. It seems normal to me that it also has some
impact in consteval context.
I don't know much about the reflection subject but _GLIBCXX_DEBUG is
optional so maybe it won't be usable along with reflection with this
patch. It doesn't sound like a big deal to me but if it is then I'm
ready to cut again all debug check when in consteval mode or when
reflection is activated.
Yes, I share the same concerns. This is a lot of extra code to run
during constant evaluation, for unclear benefit.
It's a lot of extra code to compile in the consteval expressions but
less code written, see the cleanup in <vector> and <inplace_vector>.
Future move of containers like the unordered ones will be much more
transparent for the _GLIBCXX_DEBUG mode.
_GLIBCXX_DEBUG is already adding extra work to the compiler, I would
prefer this extra work to serve a purpose like documented so do minimal
checks just forgetting about tracking container's iterators.
This would allow us to diagnose some uses of invalid iterators, like
the topic of https://cplusplus.github.io/LWG/issue2256
Currently that code Just Works, because there is a valid object at
that location, and the rule about invalidating iterators is only
enforced with debug mode, so not during constant evaluation:
#include <vector>
#include <cassert>
constexpr bool f()
{
typedef std::vector<int> C;
C c = {1, 2, 3, 4};
C::iterator i = c.begin() + 1;
C::iterator j = c.end() - 1;
assert(*i == 2);
assert(*j == 4);
c.erase(c.begin());
return *i == 3; // Why is this not perfectly fine?!
}
This won't be detected in consteval, container's iterators are not tracked.
static_assert(f());
But I don't think I really care about this. There *is* a valid object,
and if there wasn't, it would fail to compile.
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 99a0c41758d..9626d344cbc 100644
--- a/libstdc++-v3/include/debug/functions.h
+++ b/libstdc++-v3/include/debug/functions.h
@@ -60,12 +60,8 @@ namespace __gnu_debug
unsigned int __line,
const char* __function)
{
- if (!std::__is_constant_evaluated())
- {
- __glibcxx_check_valid_range_at(__first, __last,
- __file, __line, __function);
- }
-
+ __glibcxx_check_valid_range_at(__first, __last,
+ __file, __line, __function);
return __first;
}
@@ -193,11 +189,14 @@ namespace __gnu_debug
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 8ef21684650..d693db16b95 100644
--- a/libstdc++-v3/include/debug/helper_functions.h
+++ b/libstdc++-v3/include/debug/helper_functions.h
@@ -116,11 +116,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
@@ -129,10 +129,7 @@ namespace __gnu_debug
_GLIBCXX_CONSTEXPR
inline bool
__check_singular(_Iterator const& __x)
- {
- return ! std::__is_constant_evaluated()
- && __gnu_debug::__check_singular_aux(std::__addressof(__x));
- }
+ { return __gnu_debug::__check_singular_aux(std::__addressof(__x)); }
/** Non-NULL pointers are nonsingular. */
template<typename _Tp>
diff --git a/libstdc++-v3/include/debug/inplace_vector
b/libstdc++-v3/include/debug/inplace_vector
index 750b0a7343c..1b01e0b0541 100644
--- a/libstdc++-v3/include/debug/inplace_vector
+++ b/libstdc++-v3/include/debug/inplace_vector
@@ -412,11 +412,6 @@ namespace __debug
constexpr iterator
emplace(const_iterator __position, _Args&&... __args)
{
- if (std::is_constant_evaluated())
- return iterator(_Base::emplace(__position.base(),
- std::forward<_Args>(__args)...),
- this);
-
__glibcxx_check_insert(__position);
const difference_type __offset = __position.base() - _Base::cbegin();
_Base_iterator __res = _Base::emplace(__position.base(),
@@ -436,10 +431,7 @@ namespace __debug
constexpr iterator
insert(const_iterator __position, size_type __n, const _Tp& __x)
{
- if (std::is_constant_evaluated())
- return iterator(_Base::insert(__position.base(), __n, __x), this);
-
- __glibcxx_check_insert(__position);
+ __glibcxx_check_insert(__position);
const difference_type __offset = __position.base() - _Base::cbegin();
_Base_iterator __res = _Base::insert(__position.base(), __n, __x);
_M_invalidate_after_nth(__offset);
@@ -451,11 +443,6 @@ namespace __debug
insert(const_iterator __position, _InputIterator __first,
_InputIterator __last)
{
- if (std::is_constant_evaluated())
- return iterator(_Base::insert(__position.base(),
- __gnu_debug::__unsafe(__first),
- __gnu_debug::__unsafe(__last)), this);
-
typename __gnu_debug::_Distance_traits<_InputIterator>::__type __dist;
__glibcxx_check_insert_range(__position, __first, __last, __dist);
@@ -469,7 +456,7 @@ namespace __debug
__res = _Base::insert(__position.base(), __first, __last);
_M_invalidate_after_nth(__offset);
- return { __res, this };
+ return iterator(__res, this);
}
template<__detail::__container_compatible_range<_Tp> _Rg>
@@ -488,9 +475,6 @@ namespace __debug
constexpr iterator
insert(const_iterator __position, initializer_list<_Tp> __il)
{
- if (std::is_constant_evaluated())
- return iterator(_Base::insert(__position.base(), __il), this);
-
__glibcxx_check_insert(__position);
const auto __size = size();
difference_type __offset = __position.base() - _Base::begin();
@@ -503,9 +487,6 @@ namespace __debug
constexpr iterator
erase(const_iterator __position)
{
- if (std::is_constant_evaluated())
- return iterator(_Base::erase(__position.base()), this);
-
__glibcxx_check_erase(__position);
difference_type __offset = __position.base() - _Base::cbegin();
_Base_iterator __res = _Base::erase(__position.base());
@@ -516,10 +497,6 @@ namespace __debug
constexpr iterator
erase(const_iterator __first, const_iterator __last)
{
- if (std::is_constant_evaluated())
- return iterator(_Base::erase(__first.base(), __last.base()),
- this);
-
__glibcxx_check_erase_range(__first, __last);
if (__first.base() != __last.base())
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/macros.h
b/libstdc++-v3/include/debug/macros.h
index 84ad6d3fe9b..5d0961dfae4 100644
--- a/libstdc++-v3/include/debug/macros.h
+++ b/libstdc++-v3/include/debug/macros.h
@@ -38,10 +38,22 @@
* the user error and where the error is reported.
*
*/
+namespace __gnu_debug
+{
+ __attribute__((__always_inline__, __visibility__("default")))
+ inline void
+ __glibcxx_fail()
+ { }
+}
#define _GLIBCXX_DEBUG_VERIFY_AT_F(_Cond,_ErrMsg,_File,_Line,_Func) \
do { \
- if (__builtin_expect(!bool(_Cond), false)) \
+ if (std::__is_constant_evaluated())
\
+ {
\
+ if (!bool(_Cond)) \
+ __gnu_debug::__glibcxx_fail(); \
+ }
\
+ else if (__builtin_expect(!bool(_Cond), false)) \
__gnu_debug::_Error_formatter::_S_at(_File, _Line, _Func)
\
._ErrMsg._M_error(); \
} while (false)
diff --git a/libstdc++-v3/include/debug/safe_base.h
b/libstdc++-v3/include/debug/safe_base.h
index 25ac7a4e836..e7fd41cbb0c 100644
--- a/libstdc++-v3/include/debug/safe_base.h
+++ b/libstdc++-v3/include/debug/safe_base.h
@@ -83,37 +83,27 @@ namespace __gnu_debug
{ }
/** Initialize the iterator to reference the sequence pointed to
- * by @p __seq. @p __constant is true when we are initializing a
- * constant iterator, and false if it is a mutable iterator. Note
- * that @p __seq may be NULL, in which case the iterator will be
- * singular. Otherwise, the iterator will reference @p __seq and
- * be nonsingular.
- */
+ * by @p __seq. @p __constant is true when we are initializing a
+ * constant iterator, and false if it is a mutable iterator. Note
+ * that @p __seq may be NULL, in which case the iterator will be
+ * singular. Otherwise, the iterator will reference @p __seq and
+ * be nonsingular. */
_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
- iterator, and false if it is mutable. */
+ * @p __x does. @p __constant is true if this is a constant
+ * iterator, and false if it is mutable. */
_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&
@@ -122,10 +112,9 @@ namespace __gnu_debug
/** 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
- * unattached.
- */
- void
- _M_attach(const _Safe_sequence_base* __seq, bool __constant);
+ * unattached. */
+ _GLIBCXX20_CONSTEXPR void
+ _M_attach_to(const _Safe_sequence_base* __seq, bool __constant);
/** Likewise, but not thread-safe. */
void
@@ -133,22 +122,40 @@ namespace __gnu_debug
bool __constant) _GLIBCXX_USE_NOEXCEPT;
/** Detach the iterator for whatever sequence it is attached to,
- * if any.
- */
+ * if any. */
+ _GLIBCXX20_CONSTEXPR void
+ _M_detach_sequence()
+ {
+ if (std::__is_constant_evaluated())
+ _M_sequence = 0;
+ else
+ _M_detach();
+ }
+
+ private:
+ void
+ _M_attach(const _Safe_sequence_base* __seq, bool __constant);
+
void
_M_detach();
#if !_GLIBCXX_INLINE_VERSION
- private:
- /***************************************************************/
/** Not-const method preserved for abi backward compatibility. */
void
_M_attach(_Safe_sequence_base* __seq, bool __constant);
+ /** Not-const method preserved for abi backward compatibility. */
void
_M_attach_single(_Safe_sequence_base* __seq,
bool __constant) _GLIBCXX_USE_NOEXCEPT;
- /***************************************************************/
+
+ /* Not-constexpr method preserved for abi backward compatibility. */
+ _GLIBCXX_PURE bool
+ _M_singular() const _GLIBCXX_NOEXCEPT;
+
+ /* Not-constexpr method preserved for abi backward compatibility. */
+ _GLIBCXX_PURE bool
+ _M_can_compare(const _Safe_iterator_base& __x) const _GLIBCXX_USE_NOEXCEPT;
#endif
public:
@@ -157,22 +164,23 @@ namespace __gnu_debug
_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; }
/** Is this iterator singular? */
- _GLIBCXX_PURE bool
- _M_singular() const _GLIBCXX_USE_NOEXCEPT;
+ _GLIBCXX20_CONSTEXPR bool
+ _M_is_singular() const _GLIBCXX_USE_NOEXCEPT;
/** Can we compare this iterator to the given iterator @p __x?
- Returns true if both iterators are nonsingular and reference
- the same sequence. */
- _GLIBCXX_PURE bool
- _M_can_compare(const _Safe_iterator_base& __x) const _GLIBCXX_USE_NOEXCEPT;
+ * Returns true if both iterators are nonsingular and reference
+ * the same sequence. */
+ _GLIBCXX20_CONSTEXPR bool
+ _M_is_comparable(const _Safe_iterator_base& __x) const
_GLIBCXX_USE_NOEXCEPT
+ { return _M_sequence == __x._M_sequence; }
/** Invalidate the iterator, making it singular. */
- void
+ _GLIBCXX20_CONSTEXPR void
_M_invalidate()
{ _M_version = 0; }
@@ -194,9 +202,9 @@ namespace __gnu_debug
/** Iterators that derive from _Safe_iterator_base can be determined singular
* or non-singular.
**/
- inline bool
+ inline _GLIBCXX20_CONSTEXPR bool
__check_singular_aux(const _Safe_iterator_base* __x)
- { return __x->_M_singular(); }
+ { return __x->_M_is_singular(); }
/**
* @brief Base class that supports tracking of iterators that
@@ -352,6 +360,25 @@ namespace __gnu_debug
void
_M_detach_single(_Safe_iterator_base* __it) const _GLIBCXX_USE_NOEXCEPT;
};
+
+ inline _GLIBCXX20_CONSTEXPR void
+ _Safe_iterator_base::_M_attach_to(const _Safe_sequence_base* __seq,
+ bool __constant)
+ {
+ if (std::__is_constant_evaluated())
+ {
+ _M_sequence = __seq;
+ _M_version = _M_sequence->_M_version;
+ }
+ else
+ _M_attach(__seq, __constant);
+ }
+
+ inline _GLIBCXX20_CONSTEXPR bool
+ _Safe_iterator_base::
+ _M_is_singular() const _GLIBCXX_USE_NOEXCEPT
+ { return !_M_sequence || _M_version != _M_sequence->_M_version; }
+
} // namespace __gnu_debug
#endif
diff --git a/libstdc++-v3/include/debug/safe_container.h
b/libstdc++-v3/include/debug/safe_container.h
index 32159ba2176..4353f457691 100644
--- a/libstdc++-v3/include/debug/safe_container.h
+++ b/libstdc++-v3/include/debug/safe_container.h
@@ -58,7 +58,10 @@ namespace __gnu_debug
_GLIBCXX20_CONSTEXPR
void
_M_swap_base(const _Safe_container& __x) const noexcept
- { _Base::_M_swap(__x); }
+ {
+ if (!std::__is_constant_evaluated())
+ _Base::_M_swap(__x);
+ }
_GLIBCXX20_CONSTEXPR
_Safe_container(_Safe_container&& __x, const _Alloc&, std::true_type)
@@ -69,13 +72,10 @@ namespace __gnu_debug
_Safe_container(_Safe_container&& __x, const _Alloc& __a,
std::false_type)
: _Safe_container()
{
- if (!std::__is_constant_evaluated())
- {
- if (__x._M_cont().get_allocator() == __a)
- _M_swap_base(__x);
- else
- __x._M_invalidate_all();
- }
+ if (__x._M_cont().get_allocator() == __a)
+ _M_swap_base(__x);
+ else
+ __x._M_invalidate_all();
}
protected:
@@ -106,9 +106,6 @@ namespace __gnu_debug
_Safe_container&
operator=(_Safe_container&& __x) noexcept
{
- if (std::__is_constant_evaluated())
- return *this;
-
if (std::__addressof(__x) == this)
{
// Standard containers have a valid but unspecified value after
diff --git a/libstdc++-v3/include/debug/safe_iterator.h
b/libstdc++-v3/include/debug/safe_iterator.h
index 4da3d2bb3d4..a5349bd9b00 100644
--- a/libstdc++-v3/include/debug/safe_iterator.h
+++ b/libstdc++-v3/include/debug/safe_iterator.h
@@ -40,7 +40,6 @@
#endif
#define _GLIBCXX_DEBUG_VERIFY_OPERANDS(_Lhs, _Rhs, _BadMsgId, _DiffMsgId) \
- if (!std::__is_constant_evaluated()) { \
_GLIBCXX_DEBUG_VERIFY((!_Lhs._M_singular() && !_Rhs._M_singular()) \
|| (_Lhs._M_value_initialized() \
&& _Rhs._M_value_initialized()), \
@@ -50,8 +49,7 @@
_GLIBCXX_DEBUG_VERIFY(_Lhs._M_can_compare(_Rhs), \
_M_message(_DiffMsgId) \
._M_iterator(_Lhs, #_Lhs) \
- ._M_iterator(_Rhs, #_Rhs)); \
- }
+ ._M_iterator(_Rhs, #_Rhs));
#define _GLIBCXX_DEBUG_VERIFY_EQ_OPERANDS(_Lhs, _Rhs) \
_GLIBCXX_DEBUG_VERIFY_OPERANDS(_Lhs, _Rhs, __msg_iter_compare_bad, \
@@ -88,12 +86,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 +102,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 +129,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 +144,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.base()), _Safe_iterator_base()
+ { _M_attach(__x._M_sequence); }
public:
typedef _Iterator iterator_type;
@@ -169,7 +161,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 +173,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,11 +181,8 @@ namespace __gnu_debug
*/
_GLIBCXX20_CONSTEXPR
_Safe_iterator(const _Safe_iterator& __x) _GLIBCXX_NOEXCEPT
- : _Iter_base(__x.base()), _Safe_base()
+ : _Iterator(__x.base()), _Safe_iterator_base()
{
- if (std::__is_constant_evaluated())
- return;
-
// _GLIBCXX_RESOLVE_LIB_DEFECTS
// DR 408. Is vector<reverse_iterator<char*> > forbidden?
_GLIBCXX_DEBUG_VERIFY(!__x._M_singular()
@@ -211,14 +200,8 @@ namespace __gnu_debug
*/
_GLIBCXX20_CONSTEXPR
_Safe_iterator(_Safe_iterator&& __x) noexcept
- : _Iter_base()
+ : _Iterator()
{
- if (std::__is_constant_evaluated())
- {
- base() = __x.base();
- return;
- }
-
_GLIBCXX_DEBUG_VERIFY(!__x._M_singular()
|| __x._M_value_initialized(),
_M_message(__msg_init_copy_singular)
@@ -243,11 +226,8 @@ 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;
-
// _GLIBCXX_RESOLVE_LIB_DEFECTS
// DR 408. Is vector<reverse_iterator<char*> > forbidden?
_GLIBCXX_DEBUG_VERIFY(!__x._M_singular()
@@ -265,12 +245,6 @@ namespace __gnu_debug
_Safe_iterator&
operator=(const _Safe_iterator& __x) _GLIBCXX_NOEXCEPT
{
- if (std::__is_constant_evaluated())
- {
- base() = __x.base();
- return *this;
- }
-
// _GLIBCXX_RESOLVE_LIB_DEFECTS
// DR 408. Is vector<reverse_iterator<char*> > forbidden?
_GLIBCXX_DEBUG_VERIFY(!__x._M_singular()
@@ -279,7 +253,8 @@ namespace __gnu_debug
._M_iterator(*this, "this")
._M_iterator(__x, "other"));
- if (this->_M_sequence && this->_M_sequence == __x._M_sequence)
+ if (!std::__is_constant_evaluated()
+ && this->_M_sequence && this->_M_sequence == __x._M_sequence)
_GLIBCXX20_CONSTEXPR_NON_LITERAL_SCOPE_BEGIN {
__gnu_cxx::__scoped_lock __l(this->_M_get_mutex());
base() = __x.base();
@@ -304,12 +279,6 @@ namespace __gnu_debug
_Safe_iterator&
operator=(_Safe_iterator&& __x) noexcept
{
- if (std::__is_constant_evaluated())
- {
- base() = __x.base();
- return *this;
- }
-
_GLIBCXX_DEBUG_VERIFY(!__x._M_singular()
|| __x._M_value_initialized(),
_M_message(__msg_copy_singular)
@@ -319,7 +288,8 @@ namespace __gnu_debug
if (std::__addressof(__x) == this)
return *this;
- if (this->_M_sequence && this->_M_sequence == __x._M_sequence)
+ if (!std::__is_constant_evaluated()
+ && this->_M_sequence && this->_M_sequence == __x._M_sequence)
_GLIBCXX20_CONSTEXPR_NON_LITERAL_SCOPE_BEGIN {
__gnu_cxx::__scoped_lock __l(this->_M_get_mutex());
base() = __x.base();
@@ -347,12 +317,9 @@ namespace __gnu_debug
reference
operator*() const _GLIBCXX_NOEXCEPT
{
- if (!std::__is_constant_evaluated())
- {
- _GLIBCXX_DEBUG_VERIFY(this->_M_dereferenceable(),
- _M_message(__msg_bad_deref)
- ._M_iterator(*this, "this"));
- }
+ _GLIBCXX_DEBUG_VERIFY(this->_M_dereferenceable(),
+ _M_message(__msg_bad_deref)
+ ._M_iterator(*this, "this"));
return *base();
}
@@ -365,12 +332,9 @@ namespace __gnu_debug
pointer
operator->() const _GLIBCXX_NOEXCEPT
{
- if (!std::__is_constant_evaluated())
- {
- _GLIBCXX_DEBUG_VERIFY(this->_M_dereferenceable(),
- _M_message(__msg_bad_deref)
- ._M_iterator(*this, "this"));
- }
+ _GLIBCXX_DEBUG_VERIFY(this->_M_dereferenceable(),
+ _M_message(__msg_bad_deref)
+ ._M_iterator(*this, "this"));
return base().operator->();
}
@@ -383,19 +347,18 @@ namespace __gnu_debug
_Safe_iterator&
operator++() _GLIBCXX_NOEXCEPT
{
- if (std::__is_constant_evaluated())
- {
- ++base();
- 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 {
- __gnu_cxx::__scoped_lock __l(this->_M_get_mutex());
+ if (std::__is_constant_evaluated())
++base();
- } _GLIBCXX20_CONSTEXPR_NON_LITERAL_SCOPE_END
+ else
+ {
+ _GLIBCXX20_CONSTEXPR_NON_LITERAL_SCOPE_BEGIN {
+ __gnu_cxx::__scoped_lock __l(this->_M_get_mutex());
+ ++base();
+ } _GLIBCXX20_CONSTEXPR_NON_LITERAL_SCOPE_END
+ }
return *this;
}
@@ -407,12 +370,9 @@ namespace __gnu_debug
_Safe_iterator
operator++(int) _GLIBCXX_NOEXCEPT
{
- if (!std::__is_constant_evaluated())
- {
- _GLIBCXX_DEBUG_VERIFY(this->_M_incrementable(),
- _M_message(__msg_bad_inc)
- ._M_iterator(*this, "this"));
- }
+ _GLIBCXX_DEBUG_VERIFY(_M_incrementable(),
+ _M_message(__msg_bad_inc)
+ ._M_iterator(*this, "this"));
_Safe_iterator __ret(*this, _Unchecked());
++*this;
return __ret;
@@ -443,26 +403,40 @@ 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_is_singular(); }
+
+ _GLIBCXX20_CONSTEXPR bool
+ _M_can_compare(const _Safe_iterator_base& __x) const
_GLIBCXX_USE_NOEXCEPT
+ { return this->_M_is_comparable(__x); }
+
/** 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 +445,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 +487,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 +501,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,6 +664,7 @@ namespace __gnu_debug
* @brief Iterator postincrement
* @pre iterator is incrementable
*/
+ _GLIBCXX20_CONSTEXPR
_Safe_iterator
operator++(int) _GLIBCXX_NOEXCEPT
{
@@ -710,19 +685,20 @@ namespace __gnu_debug
_Safe_iterator&
operator--() _GLIBCXX_NOEXCEPT
{
- if (std::__is_constant_evaluated())
- {
- --this->base();
- return *this;
- }
-
_GLIBCXX_DEBUG_VERIFY(this->_M_decrementable(),
_M_message(__msg_bad_dec)
._M_iterator(*this, "this"));
- _GLIBCXX20_CONSTEXPR_NON_LITERAL_SCOPE_BEGIN {
- __gnu_cxx::__scoped_lock __l(this->_M_get_mutex());
+
+ if (std::__is_constant_evaluated())
--this->base();
- } _GLIBCXX20_CONSTEXPR_NON_LITERAL_SCOPE_END
+ else
+ {
+ _GLIBCXX20_CONSTEXPR_NON_LITERAL_SCOPE_BEGIN {
+ __gnu_cxx::__scoped_lock __l(this->_M_get_mutex());
+ --this->base();
+ } _GLIBCXX20_CONSTEXPR_NON_LITERAL_SCOPE_END
+ }
+
return *this;
}
@@ -730,6 +706,7 @@ namespace __gnu_debug
* @brief Iterator postdecrement
* @pre iterator is decrementable
*/
+ _GLIBCXX20_CONSTEXPR
_Safe_iterator
operator--(int) _GLIBCXX_NOEXCEPT
{
@@ -744,7 +721,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 +815,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;
@@ -864,12 +841,9 @@ namespace __gnu_debug
_Safe_iterator
operator++(int) _GLIBCXX_NOEXCEPT
{
- if (!std::__is_constant_evaluated())
- {
- _GLIBCXX_DEBUG_VERIFY(this->_M_incrementable(),
- _M_message(__msg_bad_inc)
- ._M_iterator(*this, "this"));
- }
+ _GLIBCXX_DEBUG_VERIFY(this->_M_incrementable(),
+ _M_message(__msg_bad_inc)
+ ._M_iterator(*this, "this"));
_Safe_iterator __ret(*this, _Unchecked());
++*this;
return __ret;
@@ -896,12 +870,9 @@ namespace __gnu_debug
_Safe_iterator
operator--(int) _GLIBCXX_NOEXCEPT
{
- if (!std::__is_constant_evaluated())
- {
- _GLIBCXX_DEBUG_VERIFY(this->_M_decrementable(),
- _M_message(__msg_bad_dec)
- ._M_iterator(*this, "this"));
- }
+ _GLIBCXX_DEBUG_VERIFY(this->_M_decrementable(),
+ _M_message(__msg_bad_dec)
+ ._M_iterator(*this, "this"));
_Safe_iterator __ret(*this, _Unchecked());
--*this;
return __ret;
@@ -913,13 +884,10 @@ namespace __gnu_debug
reference
operator[](difference_type __n) const _GLIBCXX_NOEXCEPT
{
- if (!std::__is_constant_evaluated())
- {
- _GLIBCXX_DEBUG_VERIFY(this->_M_can_advance(__n)
- && this->_M_can_advance(__n + 1),
- _M_message(__msg_iter_subscript_oob)
- ._M_iterator(*this)._M_integer(__n));
- }
+ _GLIBCXX_DEBUG_VERIFY(this->_M_can_advance(__n)
+ && this->_M_can_advance(__n + 1),
+ _M_message(__msg_iter_subscript_oob)
+ ._M_iterator(*this)._M_integer(__n));
return this->base()[__n];
}
@@ -927,19 +895,18 @@ namespace __gnu_debug
_Safe_iterator&
operator+=(difference_type __n) _GLIBCXX_NOEXCEPT
{
- if (std::__is_constant_evaluated())
- {
- this->base() += __n;
- return *this;
- }
-
_GLIBCXX_DEBUG_VERIFY(this->_M_can_advance(__n),
_M_message(__msg_advance_oob)
._M_iterator(*this)._M_integer(__n));
- _GLIBCXX20_CONSTEXPR_NON_LITERAL_SCOPE_BEGIN {
- __gnu_cxx::__scoped_lock __l(this->_M_get_mutex());
+ if (std::__is_constant_evaluated())
this->base() += __n;
- } _GLIBCXX20_CONSTEXPR_NON_LITERAL_SCOPE_END
+ else
+ {
+ _GLIBCXX20_CONSTEXPR_NON_LITERAL_SCOPE_BEGIN {
+ __gnu_cxx::__scoped_lock __l(this->_M_get_mutex());
+ this->base() += __n;
+ } _GLIBCXX20_CONSTEXPR_NON_LITERAL_SCOPE_END
+ }
return *this;
}
@@ -947,19 +914,18 @@ namespace __gnu_debug
_Safe_iterator&
operator-=(difference_type __n) _GLIBCXX_NOEXCEPT
{
- if (std::__is_constant_evaluated())
- {
- this->base() -= __n;
- return *this;
- }
-
_GLIBCXX_DEBUG_VERIFY(this->_M_can_advance(-__n),
_M_message(__msg_retreat_oob)
._M_iterator(*this)._M_integer(__n));
- _GLIBCXX20_CONSTEXPR_NON_LITERAL_SCOPE_BEGIN {
- __gnu_cxx::__scoped_lock __l(this->_M_get_mutex());
+ if (std::__is_constant_evaluated())
this->base() -= __n;
- } _GLIBCXX20_CONSTEXPR_NON_LITERAL_SCOPE_END
+ else
+ {
+ _GLIBCXX20_CONSTEXPR_NON_LITERAL_SCOPE_BEGIN {
+ __gnu_cxx::__scoped_lock __l(this->_M_get_mutex());
+ this->base() -= __n;
+ } _GLIBCXX20_CONSTEXPR_NON_LITERAL_SCOPE_END
+ }
return *this;
}
@@ -983,6 +949,7 @@ namespace __gnu_debug
}
#else
_GLIBCXX_NODISCARD
+ _GLIBCXX20_CONSTEXPR
friend bool
operator<(const _Self& __lhs, const _Self& __rhs) _GLIBCXX_NOEXCEPT
{
@@ -991,6 +958,7 @@ namespace __gnu_debug
}
_GLIBCXX_NODISCARD
+ _GLIBCXX20_CONSTEXPR
friend bool
operator<(const _Self& __lhs, const _OtherSelf& __rhs) _GLIBCXX_NOEXCEPT
{
@@ -999,6 +967,7 @@ namespace __gnu_debug
}
_GLIBCXX_NODISCARD
+ _GLIBCXX20_CONSTEXPR
friend bool
operator<=(const _Self& __lhs, const _Self& __rhs) _GLIBCXX_NOEXCEPT
{
@@ -1007,6 +976,7 @@ namespace __gnu_debug
}
_GLIBCXX_NODISCARD
+ _GLIBCXX20_CONSTEXPR
friend bool
operator<=(const _Self& __lhs, const _OtherSelf& __rhs) _GLIBCXX_NOEXCEPT
{
@@ -1015,6 +985,7 @@ namespace __gnu_debug
}
_GLIBCXX_NODISCARD
+ _GLIBCXX20_CONSTEXPR
friend bool
operator>(const _Self& __lhs, const _Self& __rhs) _GLIBCXX_NOEXCEPT
{
@@ -1023,6 +994,7 @@ namespace __gnu_debug
}
_GLIBCXX_NODISCARD
+ _GLIBCXX20_CONSTEXPR
friend bool
operator>(const _Self& __lhs, const _OtherSelf& __rhs) _GLIBCXX_NOEXCEPT
{
@@ -1031,6 +1003,7 @@ namespace __gnu_debug
}
_GLIBCXX_NODISCARD
+ _GLIBCXX20_CONSTEXPR
friend bool
operator>=(const _Self& __lhs, const _Self& __rhs) _GLIBCXX_NOEXCEPT
{
@@ -1039,6 +1012,7 @@ namespace __gnu_debug
}
_GLIBCXX_NODISCARD
+ _GLIBCXX20_CONSTEXPR
friend bool
operator>=(const _Self& __lhs, const _OtherSelf& __rhs) _GLIBCXX_NOEXCEPT
{
@@ -1074,12 +1048,9 @@ namespace __gnu_debug
friend _Self
operator+(const _Self& __x, difference_type __n) _GLIBCXX_NOEXCEPT
{
- if (!std::__is_constant_evaluated())
- {
- _GLIBCXX_DEBUG_VERIFY(__x._M_can_advance(__n),
- _M_message(__msg_advance_oob)
- ._M_iterator(__x)._M_integer(__n));
- }
+ _GLIBCXX_DEBUG_VERIFY(__x._M_can_advance(__n),
+ _M_message(__msg_advance_oob)
+ ._M_iterator(__x)._M_integer(__n));
return _Safe_iterator(__x.base() + __n, __x._M_sequence);
}
@@ -1088,12 +1059,9 @@ namespace __gnu_debug
friend _Self
operator+(difference_type __n, const _Self& __x) _GLIBCXX_NOEXCEPT
{
- if (!std::__is_constant_evaluated())
- {
- _GLIBCXX_DEBUG_VERIFY(__x._M_can_advance(__n),
- _M_message(__msg_advance_oob)
- ._M_iterator(__x)._M_integer(__n));
- }
+ _GLIBCXX_DEBUG_VERIFY(__x._M_can_advance(__n),
+ _M_message(__msg_advance_oob)
+ ._M_iterator(__x)._M_integer(__n));
return _Safe_iterator(__n + __x.base(), __x._M_sequence);
}
@@ -1102,12 +1070,9 @@ namespace __gnu_debug
friend _Self
operator-(const _Self& __x, difference_type __n) _GLIBCXX_NOEXCEPT
{
- if (!std::__is_constant_evaluated())
- {
- _GLIBCXX_DEBUG_VERIFY(__x._M_can_advance(-__n),
- _M_message(__msg_retreat_oob)
- ._M_iterator(__x)._M_integer(__n));
- }
+ _GLIBCXX_DEBUG_VERIFY(__x._M_can_advance(-__n),
+ _M_message(__msg_retreat_oob)
+ ._M_iterator(__x)._M_integer(__n));
return _Safe_iterator(__x.base() - __n, __x._M_sequence);
}
};
@@ -1121,12 +1086,7 @@ namespace __gnu_debug
const _Safe_iterator<_Iterator, _Sequence,
_Category>& __last,
typename _Distance_traits<_Iterator>::__type& __dist)
- {
- if (std::__is_constant_evaluated())
- return true;
-
- return __first._M_valid_range(__last, __dist);
- }
+ { return __first._M_valid_range(__last, __dist); }
template<typename _Iterator, typename _Sequence, typename _Category>
_GLIBCXX20_CONSTEXPR
@@ -1136,9 +1096,6 @@ namespace __gnu_debug
const _Safe_iterator<_Iterator, _Sequence,
_Category>& __last)
{
- if (std::__is_constant_evaluated())
- return true;
-
typename _Distance_traits<_Iterator>::__type __dist;
return __first._M_valid_range(__last, __dist);
}
@@ -1149,12 +1106,7 @@ namespace __gnu_debug
inline bool
__can_advance(const _Safe_iterator<_Iterator, _Sequence, _Category>& __it,
_Size __n)
- {
- if (std::__is_constant_evaluated())
- return true;
-
- return __it._M_can_advance(__n);
- }
+ { return __it._M_can_advance(__n); }
template<typename _Iterator, typename _Sequence, typename _Category,
typename _Diff>
@@ -1163,12 +1115,7 @@ namespace __gnu_debug
__can_advance(const _Safe_iterator<_Iterator, _Sequence, _Category>& __it,
const std::pair<_Diff, _Distance_precision>& __dist,
int __way)
- {
- if (std::__is_constant_evaluated())
- return true;
-
- return __it._M_can_advance(__dist, __way);
- }
+ { return __it._M_can_advance(__dist, __way); }
template<typename _Iterator, typename _Sequence>
_GLIBCXX20_CONSTEXPR _Iterator
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..391ddb5cde1 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;
@@ -87,7 +84,7 @@ namespace __gnu_debug
_Safe_local_iterator(const _Safe_local_iterator& __x,
_Unchecked) noexcept
- : _Iter_base(__x.base())
+ : _Iterator(__x.base())
{ _M_attach(__x._M_safe_container()); }
public:
@@ -99,7 +96,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 +107,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.base())
{
// _GLIBCXX_RESOLVE_LIB_DEFECTS
// DR 408. Is vector<reverse_iterator<char*> > forbidden?
@@ -134,7 +131,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 +154,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 +237,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 +250,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 +264,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 +279,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 +315,39 @@ namespace __gnu_debug
*/
operator _Iterator() const { return *this; }
+ /** Is this iterator singular? */
+ _GLIBCXX20_CONSTEXPR bool
+ _M_singular() const noexcept
+ { return this->_M_is_singular(); }
+
+ _GLIBCXX20_CONSTEXPR bool
+ _M_can_compare(const _Safe_iterator_base& __x) const noexcept
+ { return this->_M_is_comparable(__x); }
+
/** Attach iterator to the given unordered container. */
- void
+ _GLIBCXX20_CONSTEXPR void
_M_attach(const _Safe_unordered_container_base* __cont)
- { _Safe_base::_M_attach(__cont, _S_constant()); }
+ { _Safe_local_iterator_base::_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()); }
+ { _Safe_local_iterator_base::_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
diff --git a/libstdc++-v3/include/debug/safe_sequence.h
b/libstdc++-v3/include/debug/safe_sequence.h
index e7658bb26a7..4415f689c9f 100644
--- a/libstdc++-v3/include/debug/safe_sequence.h
+++ b/libstdc++-v3/include/debug/safe_sequence.h
@@ -110,6 +110,10 @@ namespace __gnu_debug
template<typename _Sequence>
class _Safe_sequence : public _Safe_sequence_base
{
+ template<typename _Predicate>
+ void
+ _M_invalidate_if_impl(_Predicate __pred) const;
+
public:
/** Invalidates all iterators @c x that reference this sequence,
are not singular, and for which @c __pred(x) returns @c
@@ -117,7 +121,13 @@ namespace __gnu_debug
in the safe ones. */
template<typename _Predicate>
_GLIBCXX20_CONSTEXPR void
- _M_invalidate_if(_Predicate __pred) const;
+ _M_invalidate_if(_Predicate __pred) const
+ {
+ if (std::__is_constant_evaluated())
+ return;
+
+ _M_invalidate_if_impl(__pred);
+ }
/** Transfers all iterators @c x that reference @c from sequence,
are not singular, and for which @c __pred(x) returns @c
diff --git a/libstdc++-v3/include/debug/safe_sequence.tcc
b/libstdc++-v3/include/debug/safe_sequence.tcc
index 884478fad9d..f55767258be 100644
--- a/libstdc++-v3/include/debug/safe_sequence.tcc
+++ b/libstdc++-v3/include/debug/safe_sequence.tcc
@@ -33,13 +33,10 @@ namespace __gnu_debug
{
template<typename _Sequence>
template<typename _Predicate>
- _GLIBCXX20_CONSTEXPR void
+ void
_Safe_sequence<_Sequence>::
- _M_invalidate_if(_Predicate __pred) const
+ _M_invalidate_if_impl(_Predicate __pred) const
{
- if (std::__is_constant_evaluated())
- return;
-
typedef typename _Sequence::iterator iterator;
typedef typename _Sequence::const_iterator const_iterator;
diff --git a/libstdc++-v3/include/debug/safe_unordered_base.h
b/libstdc++-v3/include/debug/safe_unordered_base.h
index 603ceff9a86..427067aaf4e 100644
--- a/libstdc++-v3/include/debug/safe_unordered_base.h
+++ b/libstdc++-v3/include/debug/safe_unordered_base.h
@@ -74,9 +74,9 @@ namespace __gnu_debug
iterator, and false if it is mutable. */
_Safe_local_iterator_base(const _Safe_local_iterator_base& __x,
bool __constant)
- { this->_M_attach(__x._M_safe_container(), __constant); }
+ { _M_attach(__x._M_safe_container(), __constant); }
- ~_Safe_local_iterator_base() { this->_M_detach(); }
+ ~_Safe_local_iterator_base() { _M_detach(); }
/** Attaches this iterator to the given container, detaching it
* from whatever container it was attached to originally. If the
diff --git a/libstdc++-v3/include/debug/vector
b/libstdc++-v3/include/debug/vector
index 61e5ff78a7a..ca9c9169226 100644
--- a/libstdc++-v3/include/debug/vector
+++ b/libstdc++-v3/include/debug/vector
@@ -103,7 +103,7 @@ namespace __gnu_debug
size_type _M_guaranteed_capacity;
- bool
+ _GLIBCXX20_CONSTEXPR bool
_M_requires_reallocation(size_type __elements) const _GLIBCXX_NOEXCEPT
{ return __elements > _M_seq().capacity(); }
@@ -213,8 +213,8 @@ namespace __debug
_GLIBCXX20_CONSTEXPR
vector(_InputIterator __first, _InputIterator __last,
const _Allocator& __a = _Allocator())
- : _Base(__gnu_debug::__base(std::__is_constant_evaluated() ? __first
- : __glibcxx_check_valid_constructor_range(__first, __last)),
+ : _Base(__gnu_debug::__base(
+ __glibcxx_check_valid_constructor_range(__first, __last)),
__gnu_debug::__base(__last), __a) { }
#if __cplusplus < 201103L
@@ -277,11 +277,8 @@ namespace __debug
operator=(initializer_list<value_type> __l)
{
_Base::operator=(__l);
- if (!std::__is_constant_evaluated())
- {
- this->_M_invalidate_all();
- this->_M_update_guaranteed_capacity();
- }
+ this->_M_invalidate_all();
+ this->_M_update_guaranteed_capacity();
return *this;
}
#endif
@@ -296,10 +293,6 @@ namespace __debug
void
assign(_InputIterator __first, _InputIterator __last)
{
- if (std::__is_constant_evaluated())
- return _Base::assign(__gnu_debug::__unsafe(__first),
- __gnu_debug::__unsafe(__last));
-
typename __gnu_debug::_Distance_traits<_InputIterator>::__type __dist;
__glibcxx_check_valid_range2(__first, __last, __dist);
@@ -318,11 +311,8 @@ namespace __debug
assign(size_type __n, const _Tp& __u)
{
_Base::assign(__n, __u);
- if (!std::__is_constant_evaluated())
- {
- this->_M_invalidate_all();
- this->_M_update_guaranteed_capacity();
- }
+ this->_M_invalidate_all();
+ this->_M_update_guaranteed_capacity();
}
#if __cplusplus >= 201103L
@@ -331,11 +321,8 @@ namespace __debug
assign(initializer_list<value_type> __l)
{
_Base::assign(__l);
- if (!std::__is_constant_evaluated())
- {
- this->_M_invalidate_all();
- this->_M_update_guaranteed_capacity();
- }
+ this->_M_invalidate_all();
+ this->_M_update_guaranteed_capacity();
}
#endif
@@ -425,9 +412,6 @@ namespace __debug
void
resize(size_type __sz)
{
- 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);
@@ -441,9 +425,6 @@ namespace __debug
void
resize(size_type __sz, const _Tp& __c)
{
- 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);
@@ -471,9 +452,6 @@ namespace __debug
void
shrink_to_fit()
{
- if (std::__is_constant_evaluated())
- return _Base::shrink_to_fit();
-
if (_Base::_M_shrink_to_fit())
{
this->_M_guaranteed_capacity = _Base::capacity();
@@ -487,9 +465,6 @@ namespace __debug
size_type
capacity() const _GLIBCXX_NOEXCEPT
{
- if (std::__is_constant_evaluated())
- return _Base::capacity();
-
#ifdef _GLIBCXX_DEBUG_PEDANTIC
return this->_M_guaranteed_capacity;
#else
@@ -503,9 +478,6 @@ namespace __debug
void
reserve(size_type __n)
{
- if (std::__is_constant_evaluated())
- return _Base::reserve(__n);
-
bool __realloc = this->_M_requires_reallocation(__n);
_Base::reserve(__n);
if (__n > this->_M_guaranteed_capacity)
@@ -580,9 +552,6 @@ namespace __debug
void
push_back(const _Tp& __x)
{
- if (std::__is_constant_evaluated())
- return _Base::push_back(__x);
-
bool __realloc = this->_M_requires_reallocation(this->size() + 1);
_Base::push_back(__x);
if (__realloc)
@@ -607,9 +576,6 @@ namespace __debug
#endif
emplace_back(_Args&&... __args)
{
- if (std::__is_constant_evaluated())
- return _Base::emplace_back(std::forward<_Args>(__args)...);
-
bool __realloc = this->_M_requires_reallocation(this->size() + 1);
_Base::emplace_back(std::forward<_Args>(__args)...);
if (__realloc)
@@ -625,11 +591,8 @@ namespace __debug
void
pop_back() _GLIBCXX_NOEXCEPT
{
- if (!std::__is_constant_evaluated())
- {
- __glibcxx_check_nonempty();
- this->_M_invalidate_if(_Equal(--_Base::end()));
- }
+ __glibcxx_check_nonempty();
+ this->_M_invalidate_if(_Equal(--_Base::end()));
_Base::pop_back();
}
@@ -639,11 +602,6 @@ namespace __debug
iterator
emplace(const_iterator __position, _Args&&... __args)
{
- if (std::__is_constant_evaluated())
- return iterator(_Base::emplace(__position.base(),
- std::forward<_Args>(__args)...),
- this);
-
__glibcxx_check_insert(__position);
bool __realloc = this->_M_requires_reallocation(this->size() + 1);
difference_type __offset = __position.base() - _Base::cbegin();
@@ -666,9 +624,6 @@ namespace __debug
insert(iterator __position, const _Tp& __x)
#endif
{
- if (std::__is_constant_evaluated())
- 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();
@@ -700,9 +655,6 @@ namespace __debug
iterator
insert(const_iterator __position, size_type __n, const _Tp& __x)
{
- if (std::__is_constant_evaluated())
- 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();
@@ -738,11 +690,6 @@ namespace __debug
insert(const_iterator __position,
_InputIterator __first, _InputIterator __last)
{
- if (std::__is_constant_evaluated())
- return iterator(_Base::insert(__position.base(),
- __gnu_debug::__unsafe(__first),
- __gnu_debug::__unsafe(__last)), this);
-
typename __gnu_debug::_Distance_traits<_InputIterator>::__type __dist;
__glibcxx_check_insert_range(__position, __first, __last, __dist);
@@ -802,9 +749,6 @@ namespace __debug
erase(iterator __position)
#endif
{
- if (std::__is_constant_evaluated())
- return iterator(_Base::erase(__position.base()), this);
-
__glibcxx_check_erase(__position);
difference_type __offset = __position.base() - _Base::begin();
_Base_iterator __res = _Base::erase(__position.base());
@@ -820,9 +764,6 @@ namespace __debug
erase(iterator __first, iterator __last)
#endif
{
- if (std::__is_constant_evaluated())
- return iterator(_Base::erase(__first.base(), __last.base()), this);
-
// _GLIBCXX_RESOLVE_LIB_DEFECTS
// 151. can't currently clear() empty container
__glibcxx_check_erase_range(__first, __last);
@@ -848,8 +789,7 @@ namespace __debug
swap(vector& __x)
_GLIBCXX_NOEXCEPT_IF( noexcept(declval<_Base&>().swap(__x)) )
{
- if (!std::__is_constant_evaluated())
- _Safe::_M_swap(__x);
+ _Safe::_M_swap(__x);
_Base::swap(__x);
std::swap(this->_M_guaranteed_capacity, __x._M_guaranteed_capacity);
}
@@ -859,8 +799,7 @@ namespace __debug
clear() _GLIBCXX_NOEXCEPT
{
_Base::clear();
- if (!std::__is_constant_evaluated())
- this->_M_invalidate_all();
+ this->_M_invalidate_all();
}
_GLIBCXX20_CONSTEXPR
@@ -879,14 +818,11 @@ namespace __debug
auto __old_capacity = _Base::capacity();
auto __old_size = _Base::size();
_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();
- }
+ 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();
}
template<__detail::__container_compatible_range<_Tp> _Rg>
@@ -895,12 +831,9 @@ namespace __debug
{
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();
- }
+ if (_Base::capacity() != __old_capacity)
+ this->_M_invalidate_all();
+ this->_M_update_guaranteed_capacity();
return iterator(__res, this);
}
@@ -910,17 +843,14 @@ namespace __debug
{
auto __old_capacity = _Base::capacity();
_Base::append_range(__rg);
- if (!std::__is_constant_evaluated())
- {
- if (_Base::capacity() != __old_capacity)
- this->_M_invalidate_all();
- this->_M_update_guaranteed_capacity();
- }
+ if (_Base::capacity() != __old_capacity)
+ this->_M_invalidate_all();
+ this->_M_update_guaranteed_capacity();
}
#endif
private:
- void
+ _GLIBCXX20_CONSTEXPR void
_M_invalidate_after_nth(difference_type __n) _GLIBCXX_NOEXCEPT
{
typedef __gnu_debug::_After_nth_from<_Base_const_iterator> _After_nth;
diff --git a/libstdc++-v3/src/c++11/debug.cc b/libstdc++-v3/src/c++11/debug.cc
index 3e6f286bc0a..a79dab9497d 100644
--- a/libstdc++-v3/src/c++11/debug.cc
+++ b/libstdc++-v3/src/c++11/debug.cc
@@ -346,7 +346,7 @@ namespace __gnu_debug
{
_Safe_iterator_base* __old = __iter;
__iter = __iter->_M_next;
- if (__old->_M_singular())
+ if (__old->_M_is_singular())
__old->_M_detach_single();
}
@@ -354,7 +354,7 @@ namespace __gnu_debug
{
_Safe_iterator_base* __old = __iter2;
__iter2 = __iter2->_M_next;
- if (__old->_M_singular())
+ if (__old->_M_is_singular())
__old->_M_detach_single();
}
}
@@ -462,7 +462,7 @@ namespace __gnu_debug
__it->_M_unlink();
if (_M_const_iterators == __it)
_M_const_iterators = __it->_M_next;
- if (_M_iterators == __it)
+ else if (_M_iterators == __it)
_M_iterators = __it->_M_next;
}
@@ -541,15 +541,17 @@ namespace __gnu_debug
_M_next = 0;
}
+#if !_GLIBCXX_INLINE_VERSION
bool
_Safe_iterator_base::
_M_singular() const noexcept
- { return !_M_sequence || _M_version != _M_sequence->_M_version; }
+ { return _M_is_singular(); }
bool
_Safe_iterator_base::
_M_can_compare(const _Safe_iterator_base& __x) const noexcept
- { return _M_sequence == __x._M_sequence; }
+ { return _M_is_comparable(__x); }
+#endif
__gnu_cxx::__mutex&
_Safe_iterator_base::
@@ -711,7 +713,7 @@ namespace __gnu_debug
__it->_M_unlink();
if (_M_const_local_iterators == __it)
_M_const_local_iterators = __it->_M_next;
- if (_M_local_iterators == __it)
+ else if (_M_local_iterators == __it)
_M_local_iterators = __it->_M_next;
}
diff --git
a/libstdc++-v3/testsuite/23_containers/vector/debug/consteval_erase_neg.cc
b/libstdc++-v3/testsuite/23_containers/vector/debug/consteval_erase_neg.cc
new file mode 100644
index 00000000000..601fa08ba1d
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/vector/debug/consteval_erase_neg.cc
@@ -0,0 +1,24 @@
+// { dg-do compile { target c++20 } }
+// { dg-require-debug-mode "" }
+
+#include <vector>
+#include <testsuite_hooks.h>
+
+constexpr bool test01()
+{
+ std::vector<int> v1, v2;
+
+ for (int i = 0; i != 10; ++i)
+ {
+ v1.push_back(i);
+ v2.push_back(i);
+ }
+
+ v1.erase(v2.begin()); // { dg-error "in 'constexpr' expansion of" }
+ return true;
+}
+
+static_assert( test01() );
+
+// { dg-prune-output "non-constant condition for static assertion" }
+// { dg-prune-output "call to non-'constexpr' function" }
diff --git a/libstdc++-v3/testsuite/23_containers/vector/debug/erase_neg.cc
b/libstdc++-v3/testsuite/23_containers/vector/debug/erase_neg.cc
new file mode 100644
index 00000000000..ff792eca00e
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/vector/debug/erase_neg.cc
@@ -0,0 +1,25 @@
+// { dg-do run { xfail *-*-* } }
+// { dg-require-debug-mode "" }
+
+#include <vector>
+#include <testsuite_hooks.h>
+
+bool test01()
+{
+ std::vector<int> v1, v2;
+
+ for (int i = 0; i != 10; ++i)
+ {
+ v1.push_back(i);
+ v2.push_back(i);
+ }
+
+ v1.erase(v2.begin()); // Invalid iterator.
+ return true;
+}
+
+int main()
+{
+ test01();
+ return 0;
+}