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).
Regards,
Tomasz
Issues will be reported thanks to an invalid call to a not-constexpr
> __gnu_debug::__glibcxx_fail() function.
>
> libstdc++-v3/ChangeLog:
>
> * include/debug/forward_list (_Sequence_traits<>::_S_size):
> Declare as C++20
> constexpr.
> * include/debug/functions.h
> (__check_valid_range<_Ite>): Remove
> std::__is_constant_evaluated check.
> (__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++22 constexpr.
> (__check_singular<_Ite>(_Ite const&)): Remove
> std::__is_constant_evaluated check.
> * include/debug/inplace_vector: Remove all calls to
> std::is_contant_evaluated().
> * include/debug/list (_Sequence_traits<>::_S_size): Declare
> as C++20 constexpr.
> * include/debug/macros.h (__gnu_debug::__glibcxx_fail): New.
> (_GLIBCXX_DEBUG_VERIFY_AT_F): Add
> std::__is_constant_evaluated section.
> * include/debug/safe_base.h
> (_Safe_iterator_base::_M_attach_to): New.
> (_Safe_iterator_base::_M_detach_sequence): New.
> (_Safe_iterator_base(const _Safe_sequence_base*, bool): Remove
> __is_constant_evaluated check and call _M_attach_to.
> (_Safe_iterator_base(const _Safe_iterator_base&, bool)):
> Likewise.
> (~_Safe_iterator_base()): Remove __is_constant_evaluated
> check and call
> _M_detach_sequence.
> (_Safe_iterator_base::_M_is_singular): New.
> (_Safe_iterator_base::_M_is_comparable): New.
> (__check_singular_aux(const _Safe_iterator_base*)): Declare
> as C++20 constexpr
> and call _M_is_singular.
> * include/debug/safe_container.h
> (_Safe_container::_M_swap_base): Declare as
> C++20 constexpr and skip operation if in constant
> evaluation context.
> (_Safe_container(_Safe_container&&, const _Alloc&,
> std::false_type)): Remove
> __is_constant_evaluated check.
> (_Safe_container::operator=(_Safe_container<>&&)): Likewise.
> * include/debug/safe_iterator.h
> (_GLIBCXX_DEBUG_VERIFY_OPERANDS): Likewise.
> (_BeforeBeginHelper<>::_S_Is): Declare as C++20 constexpr.
> (_BeforeBeginHelper<>::_S_Is_Beginnest): Declare as C++20
> constexpr.
> (_Sequence_traits<>::_S_size): Declare as C++20 constexpr.
> (_Safe_iterator::_Iter_base, _Safe_iterator::_Safe_base):
> Remove.
> (_Safe_iterator(const _Safe_iterator&, _Unchecked)): Remove
> __is_constant_evaluated
> check.
> (_Safe_iterator(const _Safe_iterator&)): Likewise.
> (_Safe_iterator(_Safe_iterator&&)): Likewise.
> (_Safe_iterator<>::operator=(const _Safe_iterator&)): Adapt
> use of __is_constant_evaluated
> to avoid __scoped_lock instantiation.
> (_Safe_iterator<>::operator=(_Safe_iterator&&)): Likewise.
> (_Safe_iterator<>::operator++()): Likewise.
> (_Safe_iterator<>::operator*()): Remove
> __is_constant_evaluated check.
> (_Safe_iterator<>::operator->()): Likewise.
> (_Safe_iterator<>::operator++(int)): Likewise.
> (_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_sequence().
> (_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--()): Adapt use of
> __is_constant_evaluated to avoid
> __scoped_lock instantiation.
> (_Safe_iterator<>::operator+=(difference_type)): Likewise.
> (_Safe_iterator<>::operator-=(difference_type)): Likewise.
> (_Safe_iterator<>::operator--(int)): Declare as C++20
> constexpr.
> (_Safe_iterator<>::_M_decrementable()): Likewise.
> (_Safe_iterator<>::operator[](difference_type)): 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<>&, 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.
> (__valid_range<>): Likewise.
> (__can_advance<>): 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<>::_M_singular): New.
> (_Safe_local_iterator<>::_M_can_compare(const
> _Safe_iterator_base&)): New.
> (_Safe_local_iterator<>::_M_attach): Declare C++20
> constexpr, use base class
> _M_attach_to.
> * include/debug/safe_sequence.h
> (_Safe_sequence<>::_M_invalidate_if_impl): New.
> (_Safe_sequence<>::_M_invalidate_if): Call later if not
> __is_constant_evaluated.
> * include/debug/safe_sequence.tcc: Rename _M_invalidate_if
> into
> _M_invalidate_if_impl and not C++20 constexpr.
> * include/debug/safe_unordered_base.h: Remove useless this->.
> * include/debug/vector: Adapt, remove all use of
> std::__is_constant_evaluated.
> * src/c++11/debug.cc
> (_Safe_sequence_base::_M_detach_singular()): Use new
> _M_is_singular.
> (_Safe_sequence_base::_M_detach_single(_Safe_iterator_base* it)):
> Do not check if it equals _M_iterators if it was equal to
> _M_const_iterators.
> (_Safe_iterator_base::_M_singular): Use _M_is_singular.
> (_Safe_iterator_base::_M_singular)[_GLIBCXX_INLINE_VERSION]: Remove.
> (_Safe_iterator_base::_M_can_compare): Use _M_is_comparable.
> (_Safe_iterator_base::_M_can_compare)[_GLIBCXX_INLINE_VERSION]: Remove.
>
> (_Safe_unordered_container_base::_M_detach_local_single(_Safe_iterator_base*)):
> Do not check if it equals _M_local_iterators if it was equal
> to
> _M_const_local_iterators.
>
> PR: https://forge.sourceware.org/gcc/gcc-TEST/pulls/136
>
> I noticed on the PR that some bot is running tests and spotted some
> regressions that are now fixed.
>
> I run some tests locally and requested an access to the compiler farm.
>
> François
>
>