libstdc++: Make __gnu_debug::vector usable in constant expressions [PR109536]
Checks
Context |
Check |
Description |
linaro-tcwg-bot/tcwg_gcc_build--master-arm |
success
|
Testing passed
|
linaro-tcwg-bot/tcwg_gcc_build--master-aarch64 |
success
|
Testing passed
|
linaro-tcwg-bot/tcwg_gcc_check--master-aarch64 |
fail
|
Testing failed
|
linaro-tcwg-bot/tcwg_gcc_check--master-arm |
fail
|
Testing failed
|
Commit Message
Any comments on this approach?
-- >8 --
This makes constexpr std::vector (mostly) work in Debug Mode. All safe
iterator instrumentation and checking is disabled during constant
evaluation, because it requires mutex locks and calls to non-inline
functions defined in libstdc++.so. It should be OK to disable the safety
checks, because most UB should be detected during constant evaluation
anyway.
We could try to enable the full checking in constexpr, but it would mean
wrapping all the non-inline functions like _M_attach with an inline
_M_constexpr_attach that does the iterator housekeeping inline without
mutex locks when calling for constant evaluation, and calls the
non-inline function at runtime. That could be done in future if we find
that we've lost safety or useful checking by disabling the safe
iterators.
There are a few test failures in C++20 mode, which I'm unable to
explain. The _Safe_iterator::operator++() member gives errors for using
non-constexpr functions during constant evaluation, even though those
functions are guarded by std::is_constant_evaluated() checks. The same
code works fine for C++23 and up.
libstdc++-v3/ChangeLog:
PR libstdc++/109536
* include/bits/c++config (__glibcxx_constexpr_assert): Remove
macro.
* include/bits/stl_algobase.h (__niter_base, __copy_move_a)
(__copy_move_backward_a, __fill_a, __fill_n_a, __equal_aux)
(__lexicographical_compare_aux): Add constexpr to overloads for
debug mode iterators.
* include/debug/helper_functions.h (__unsafe): Add constexpr.
* include/debug/macros.h (_GLIBCXX_DEBUG_VERIFY_COND_AT): Remove
macro, folding it into ...
(_GLIBCXX_DEBUG_VERIFY_AT_F): ... here. Do not use
__glibcxx_constexpr_assert.
* include/debug/safe_base.h (_Safe_iterator_base): Add constexpr
to some member functions. Omit attaching, detaching and checking
operations during constant evaluation.
* include/debug/safe_container.h (_Safe_container): Likewise.
* include/debug/safe_iterator.h (_Safe_iterator): Likewise.
* include/debug/safe_iterator.tcc (__niter_base, __copy_move_a)
(__copy_move_backward_a, __fill_a, __fill_n_a, __equal_aux)
(__lexicographical_compare_aux): Add constexpr.
* include/debug/vector (_Safe_vector, vector): Add constexpr.
Omit safe iterator operations during constant evaluation.
* testsuite/23_containers/vector/bool/capacity/constexpr.cc:
Remove dg-xfail-if for debug mode.
* testsuite/23_containers/vector/bool/cmp_c++20.cc: Likewise.
* testsuite/23_containers/vector/bool/cons/constexpr.cc:
Likewise.
* testsuite/23_containers/vector/bool/element_access/1.cc:
Likewise.
* testsuite/23_containers/vector/bool/element_access/constexpr.cc:
Likewise.
* testsuite/23_containers/vector/bool/modifiers/assign/constexpr.cc:
Likewise.
* testsuite/23_containers/vector/bool/modifiers/constexpr.cc:
Likewise.
* testsuite/23_containers/vector/bool/modifiers/swap/constexpr.cc:
Likewise.
* testsuite/23_containers/vector/capacity/constexpr.cc:
Likewise.
* testsuite/23_containers/vector/cmp_c++20.cc: Likewise.
* testsuite/23_containers/vector/cons/constexpr.cc: Likewise.
* testsuite/23_containers/vector/data_access/constexpr.cc:
Likewise.
* testsuite/23_containers/vector/element_access/constexpr.cc:
Likewise.
* testsuite/23_containers/vector/modifiers/assign/constexpr.cc:
Likewise.
* testsuite/23_containers/vector/modifiers/constexpr.cc:
Likewise.
* testsuite/23_containers/vector/modifiers/swap/constexpr.cc:
Likewise.
---
libstdc++-v3/include/bits/c++config | 9 -
libstdc++-v3/include/bits/stl_algobase.h | 15 ++
libstdc++-v3/include/debug/helper_functions.h | 1 +
libstdc++-v3/include/debug/macros.h | 9 +-
libstdc++-v3/include/debug/safe_base.h | 35 +++-
libstdc++-v3/include/debug/safe_container.h | 15 +-
libstdc++-v3/include/debug/safe_iterator.h | 186 +++++++++++++++---
libstdc++-v3/include/debug/safe_iterator.tcc | 15 ++
libstdc++-v3/include/debug/vector | 146 ++++++++++++--
.../vector/bool/capacity/constexpr.cc | 1 -
.../23_containers/vector/bool/cmp_c++20.cc | 1 -
.../vector/bool/cons/constexpr.cc | 1 -
.../vector/bool/element_access/1.cc | 1 -
.../vector/bool/element_access/constexpr.cc | 1 -
.../vector/bool/modifiers/assign/constexpr.cc | 1 -
.../vector/bool/modifiers/constexpr.cc | 1 -
.../vector/bool/modifiers/swap/constexpr.cc | 3 +-
.../vector/capacity/constexpr.cc | 1 -
.../23_containers/vector/cmp_c++20.cc | 1 -
.../23_containers/vector/cons/constexpr.cc | 1 -
.../vector/data_access/constexpr.cc | 1 -
.../vector/element_access/constexpr.cc | 1 -
.../vector/modifiers/assign/constexpr.cc | 1 -
.../vector/modifiers/constexpr.cc | 1 -
.../vector/modifiers/swap/constexpr.cc | 1 -
25 files changed, 369 insertions(+), 80 deletions(-)
Comments
On Wed, 6 Dec 2023 at 14:30, Jonathan Wakely wrote:
>
> Any comments on this approach?
Pushed to trunk now.
>
> -- >8 --
>
> This makes constexpr std::vector (mostly) work in Debug Mode. All safe
> iterator instrumentation and checking is disabled during constant
> evaluation, because it requires mutex locks and calls to non-inline
> functions defined in libstdc++.so. It should be OK to disable the safety
> checks, because most UB should be detected during constant evaluation
> anyway.
>
> We could try to enable the full checking in constexpr, but it would mean
> wrapping all the non-inline functions like _M_attach with an inline
> _M_constexpr_attach that does the iterator housekeeping inline without
> mutex locks when calling for constant evaluation, and calls the
> non-inline function at runtime. That could be done in future if we find
> that we've lost safety or useful checking by disabling the safe
> iterators.
>
> There are a few test failures in C++20 mode, which I'm unable to
> explain. The _Safe_iterator::operator++() member gives errors for using
> non-constexpr functions during constant evaluation, even though those
> functions are guarded by std::is_constant_evaluated() checks. The same
> code works fine for C++23 and up.
>
> libstdc++-v3/ChangeLog:
>
> PR libstdc++/109536
> * include/bits/c++config (__glibcxx_constexpr_assert): Remove
> macro.
> * include/bits/stl_algobase.h (__niter_base, __copy_move_a)
> (__copy_move_backward_a, __fill_a, __fill_n_a, __equal_aux)
> (__lexicographical_compare_aux): Add constexpr to overloads for
> debug mode iterators.
> * include/debug/helper_functions.h (__unsafe): Add constexpr.
> * include/debug/macros.h (_GLIBCXX_DEBUG_VERIFY_COND_AT): Remove
> macro, folding it into ...
> (_GLIBCXX_DEBUG_VERIFY_AT_F): ... here. Do not use
> __glibcxx_constexpr_assert.
> * include/debug/safe_base.h (_Safe_iterator_base): Add constexpr
> to some member functions. Omit attaching, detaching and checking
> operations during constant evaluation.
> * include/debug/safe_container.h (_Safe_container): Likewise.
> * include/debug/safe_iterator.h (_Safe_iterator): Likewise.
> * include/debug/safe_iterator.tcc (__niter_base, __copy_move_a)
> (__copy_move_backward_a, __fill_a, __fill_n_a, __equal_aux)
> (__lexicographical_compare_aux): Add constexpr.
> * include/debug/vector (_Safe_vector, vector): Add constexpr.
> Omit safe iterator operations during constant evaluation.
> * testsuite/23_containers/vector/bool/capacity/constexpr.cc:
> Remove dg-xfail-if for debug mode.
> * testsuite/23_containers/vector/bool/cmp_c++20.cc: Likewise.
> * testsuite/23_containers/vector/bool/cons/constexpr.cc:
> Likewise.
> * testsuite/23_containers/vector/bool/element_access/1.cc:
> Likewise.
> * testsuite/23_containers/vector/bool/element_access/constexpr.cc:
> Likewise.
> * testsuite/23_containers/vector/bool/modifiers/assign/constexpr.cc:
> Likewise.
> * testsuite/23_containers/vector/bool/modifiers/constexpr.cc:
> Likewise.
> * testsuite/23_containers/vector/bool/modifiers/swap/constexpr.cc:
> Likewise.
> * testsuite/23_containers/vector/capacity/constexpr.cc:
> Likewise.
> * testsuite/23_containers/vector/cmp_c++20.cc: Likewise.
> * testsuite/23_containers/vector/cons/constexpr.cc: Likewise.
> * testsuite/23_containers/vector/data_access/constexpr.cc:
> Likewise.
> * testsuite/23_containers/vector/element_access/constexpr.cc:
> Likewise.
> * testsuite/23_containers/vector/modifiers/assign/constexpr.cc:
> Likewise.
> * testsuite/23_containers/vector/modifiers/constexpr.cc:
> Likewise.
> * testsuite/23_containers/vector/modifiers/swap/constexpr.cc:
> Likewise.
> ---
> libstdc++-v3/include/bits/c++config | 9 -
> libstdc++-v3/include/bits/stl_algobase.h | 15 ++
> libstdc++-v3/include/debug/helper_functions.h | 1 +
> libstdc++-v3/include/debug/macros.h | 9 +-
> libstdc++-v3/include/debug/safe_base.h | 35 +++-
> libstdc++-v3/include/debug/safe_container.h | 15 +-
> libstdc++-v3/include/debug/safe_iterator.h | 186 +++++++++++++++---
> libstdc++-v3/include/debug/safe_iterator.tcc | 15 ++
> libstdc++-v3/include/debug/vector | 146 ++++++++++++--
> .../vector/bool/capacity/constexpr.cc | 1 -
> .../23_containers/vector/bool/cmp_c++20.cc | 1 -
> .../vector/bool/cons/constexpr.cc | 1 -
> .../vector/bool/element_access/1.cc | 1 -
> .../vector/bool/element_access/constexpr.cc | 1 -
> .../vector/bool/modifiers/assign/constexpr.cc | 1 -
> .../vector/bool/modifiers/constexpr.cc | 1 -
> .../vector/bool/modifiers/swap/constexpr.cc | 3 +-
> .../vector/capacity/constexpr.cc | 1 -
> .../23_containers/vector/cmp_c++20.cc | 1 -
> .../23_containers/vector/cons/constexpr.cc | 1 -
> .../vector/data_access/constexpr.cc | 1 -
> .../vector/element_access/constexpr.cc | 1 -
> .../vector/modifiers/assign/constexpr.cc | 1 -
> .../vector/modifiers/constexpr.cc | 1 -
> .../vector/modifiers/swap/constexpr.cc | 1 -
> 25 files changed, 369 insertions(+), 80 deletions(-)
>
> diff --git a/libstdc++-v3/include/bits/c++config b/libstdc++-v3/include/bits/c++config
> index 284d24d933f..13d416845c3 100644
> --- a/libstdc++-v3/include/bits/c++config
> +++ b/libstdc++-v3/include/bits/c++config
> @@ -565,15 +565,6 @@ namespace std
> # define _GLIBCXX_EXTERN_TEMPLATE -1
> #endif
>
> -
> -#if _GLIBCXX_HAVE_IS_CONSTANT_EVALUATED
> -# define __glibcxx_constexpr_assert(cond) \
> - if (std::__is_constant_evaluated() && !bool(cond)) \
> - __builtin_unreachable() /* precondition violation detected! */
> -#else
> -# define __glibcxx_constexpr_assert(unevaluated)
> -#endif
> -
> #undef _GLIBCXX_VERBOSE_ASSERT
>
> // Assert.
> diff --git a/libstdc++-v3/include/bits/stl_algobase.h b/libstdc++-v3/include/bits/stl_algobase.h
> index 01ca4496dfd..77d0ee7bcf5 100644
> --- a/libstdc++-v3/include/bits/stl_algobase.h
> +++ b/libstdc++-v3/include/bits/stl_algobase.h
> @@ -318,6 +318,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> { return __it; }
>
> template<typename _Ite, typename _Seq>
> + _GLIBCXX20_CONSTEXPR
> _Ite
> __niter_base(const ::__gnu_debug::_Safe_iterator<_Ite, _Seq,
> std::random_access_iterator_tag>&);
> @@ -545,6 +546,7 @@ _GLIBCXX_END_NAMESPACE_CONTAINER
>
> template<bool _IsMove,
> typename _Ite, typename _Seq, typename _Cat, typename _OI>
> + _GLIBCXX20_CONSTEXPR
> _OI
> __copy_move_a(const ::__gnu_debug::_Safe_iterator<_Ite, _Seq, _Cat>&,
> const ::__gnu_debug::_Safe_iterator<_Ite, _Seq, _Cat>&,
> @@ -552,6 +554,7 @@ _GLIBCXX_END_NAMESPACE_CONTAINER
>
> template<bool _IsMove,
> typename _II, typename _Ite, typename _Seq, typename _Cat>
> + _GLIBCXX20_CONSTEXPR
> __gnu_debug::_Safe_iterator<_Ite, _Seq, _Cat>
> __copy_move_a(_II, _II,
> const ::__gnu_debug::_Safe_iterator<_Ite, _Seq, _Cat>&);
> @@ -559,6 +562,7 @@ _GLIBCXX_END_NAMESPACE_CONTAINER
> template<bool _IsMove,
> typename _IIte, typename _ISeq, typename _ICat,
> typename _OIte, typename _OSeq, typename _OCat>
> + _GLIBCXX20_CONSTEXPR
> ::__gnu_debug::_Safe_iterator<_OIte, _OSeq, _OCat>
> __copy_move_a(const ::__gnu_debug::_Safe_iterator<_IIte, _ISeq, _ICat>&,
> const ::__gnu_debug::_Safe_iterator<_IIte, _ISeq, _ICat>&,
> @@ -812,6 +816,7 @@ _GLIBCXX_END_NAMESPACE_CONTAINER
>
> template<bool _IsMove,
> typename _Ite, typename _Seq, typename _Cat, typename _OI>
> + _GLIBCXX20_CONSTEXPR
> _OI
> __copy_move_backward_a(
> const ::__gnu_debug::_Safe_iterator<_Ite, _Seq, _Cat>&,
> @@ -820,6 +825,7 @@ _GLIBCXX_END_NAMESPACE_CONTAINER
>
> template<bool _IsMove,
> typename _II, typename _Ite, typename _Seq, typename _Cat>
> + _GLIBCXX20_CONSTEXPR
> __gnu_debug::_Safe_iterator<_Ite, _Seq, _Cat>
> __copy_move_backward_a(_II, _II,
> const ::__gnu_debug::_Safe_iterator<_Ite, _Seq, _Cat>&);
> @@ -827,6 +833,7 @@ _GLIBCXX_END_NAMESPACE_CONTAINER
> template<bool _IsMove,
> typename _IIte, typename _ISeq, typename _ICat,
> typename _OIte, typename _OSeq, typename _OCat>
> + _GLIBCXX20_CONSTEXPR
> ::__gnu_debug::_Safe_iterator<_OIte, _OSeq, _OCat>
> __copy_move_backward_a(
> const ::__gnu_debug::_Safe_iterator<_IIte, _ISeq, _ICat>&,
> @@ -977,6 +984,7 @@ _GLIBCXX_END_NAMESPACE_CONTAINER
> { std::__fill_a1(__first, __last, __value); }
>
> template<typename _Ite, typename _Seq, typename _Cat, typename _Tp>
> + _GLIBCXX20_CONSTEXPR
> void
> __fill_a(const ::__gnu_debug::_Safe_iterator<_Ite, _Seq, _Cat>&,
> const ::__gnu_debug::_Safe_iterator<_Ite, _Seq, _Cat>&,
> @@ -1082,6 +1090,7 @@ _GLIBCXX_END_NAMESPACE_CONTAINER
>
> template<typename _Ite, typename _Seq, typename _Cat, typename _Size,
> typename _Tp>
> + _GLIBCXX20_CONSTEXPR
> ::__gnu_debug::_Safe_iterator<_Ite, _Seq, _Cat>
> __fill_n_a(const ::__gnu_debug::_Safe_iterator<_Ite, _Seq, _Cat>& __first,
> _Size __n, const _Tp& __value,
> @@ -1230,18 +1239,21 @@ _GLIBCXX_END_NAMESPACE_CONTAINER
> }
>
> template<typename _II1, typename _Seq1, typename _Cat1, typename _II2>
> + _GLIBCXX20_CONSTEXPR
> bool
> __equal_aux(const ::__gnu_debug::_Safe_iterator<_II1, _Seq1, _Cat1>&,
> const ::__gnu_debug::_Safe_iterator<_II1, _Seq1, _Cat1>&,
> _II2);
>
> template<typename _II1, typename _II2, typename _Seq2, typename _Cat2>
> + _GLIBCXX20_CONSTEXPR
> bool
> __equal_aux(_II1, _II1,
> const ::__gnu_debug::_Safe_iterator<_II2, _Seq2, _Cat2>&);
>
> template<typename _II1, typename _Seq1, typename _Cat1,
> typename _II2, typename _Seq2, typename _Cat2>
> + _GLIBCXX20_CONSTEXPR
> bool
> __equal_aux(const ::__gnu_debug::_Safe_iterator<_II1, _Seq1, _Cat1>&,
> const ::__gnu_debug::_Safe_iterator<_II1, _Seq1, _Cat1>&,
> @@ -1430,6 +1442,7 @@ _GLIBCXX_END_NAMESPACE_CONTAINER
>
> template<typename _Iter1, typename _Seq1, typename _Cat1,
> typename _II2>
> + _GLIBCXX20_CONSTEXPR
> bool
> __lexicographical_compare_aux(
> const ::__gnu_debug::_Safe_iterator<_Iter1, _Seq1, _Cat1>&,
> @@ -1438,6 +1451,7 @@ _GLIBCXX_END_NAMESPACE_CONTAINER
>
> template<typename _II1,
> typename _Iter2, typename _Seq2, typename _Cat2>
> + _GLIBCXX20_CONSTEXPR
> bool
> __lexicographical_compare_aux(
> _II1, _II1,
> @@ -1446,6 +1460,7 @@ _GLIBCXX_END_NAMESPACE_CONTAINER
>
> template<typename _Iter1, typename _Seq1, typename _Cat1,
> typename _Iter2, typename _Seq2, typename _Cat2>
> + _GLIBCXX20_CONSTEXPR
> bool
> __lexicographical_compare_aux(
> const ::__gnu_debug::_Safe_iterator<_Iter1, _Seq1, _Cat1>&,
> diff --git a/libstdc++-v3/include/debug/helper_functions.h b/libstdc++-v3/include/debug/helper_functions.h
> index 052b36b484c..4b76cb00f9a 100644
> --- a/libstdc++-v3/include/debug/helper_functions.h
> +++ b/libstdc++-v3/include/debug/helper_functions.h
> @@ -324,6 +324,7 @@ namespace __gnu_debug
>
> /* Remove debug mode safe iterator layer, if any. */
> template<typename _Iterator>
> + _GLIBCXX_CONSTEXPR
> inline _Iterator
> __unsafe(_Iterator __it)
> { return __it; }
> diff --git a/libstdc++-v3/include/debug/macros.h b/libstdc++-v3/include/debug/macros.h
> index 0fef0a006fc..4a3d0f2ea84 100644
> --- a/libstdc++-v3/include/debug/macros.h
> +++ b/libstdc++-v3/include/debug/macros.h
> @@ -38,15 +38,12 @@
> * the user error and where the error is reported.
> *
> */
> -#define _GLIBCXX_DEBUG_VERIFY_COND_AT(_Cond,_ErrMsg,_File,_Line,_Func) \
> - if (__builtin_expect(!bool(_Cond), false)) \
> - __gnu_debug::_Error_formatter::_S_at(_File, _Line, _Func) \
> - ._ErrMsg._M_error()
>
> #define _GLIBCXX_DEBUG_VERIFY_AT_F(_Cond,_ErrMsg,_File,_Line,_Func) \
> do { \
> - __glibcxx_constexpr_assert(_Cond); \
> - _GLIBCXX_DEBUG_VERIFY_COND_AT(_Cond,_ErrMsg,_File,_Line,_Func); \
> + if (__builtin_expect(!bool(_Cond), false)) \
> + __gnu_debug::_Error_formatter::_S_at(_File, _Line, _Func) \
> + ._ErrMsg._M_error(); \
> } while (false)
>
> #define _GLIBCXX_DEBUG_VERIFY_AT(_Cond,_ErrMsg,_File,_Line) \
> diff --git a/libstdc++-v3/include/debug/safe_base.h b/libstdc++-v3/include/debug/safe_base.h
> index 1dfa9f68b65..d9c17b52b48 100644
> --- a/libstdc++-v3/include/debug/safe_base.h
> +++ b/libstdc++-v3/include/debug/safe_base.h
> @@ -75,6 +75,7 @@ namespace __gnu_debug
>
> protected:
> /** Initializes the iterator and makes it singular. */
> + _GLIBCXX20_CONSTEXPR
> _Safe_iterator_base()
> : _M_sequence(0), _M_version(0), _M_prior(0), _M_next(0)
> { }
> @@ -86,18 +87,31 @@ namespace __gnu_debug
> * 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)
> - { this->_M_attach(const_cast<_Safe_sequence_base*>(__seq), __constant); }
> + {
> + if (!std::__is_constant_evaluated())
> + this->_M_attach(const_cast<_Safe_sequence_base*>(__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. */
> + _GLIBCXX20_CONSTEXPR
> _Safe_iterator_base(const _Safe_iterator_base& __x, bool __constant)
> : _M_sequence(0), _M_version(0), _M_prior(0), _M_next(0)
> - { this->_M_attach(__x._M_sequence, __constant); }
> + {
> + if (!std::__is_constant_evaluated())
> + this->_M_attach(__x._M_sequence, __constant);
> + }
>
> - ~_Safe_iterator_base() { this->_M_detach(); }
> + _GLIBCXX20_CONSTEXPR
> + ~_Safe_iterator_base()
> + {
> + if (!std::__is_constant_evaluated())
> + this->_M_detach();
> + }
>
> /** For use in _Safe_iterator. */
> __gnu_cxx::__mutex&
> @@ -201,24 +215,34 @@ namespace __gnu_debug
>
> protected:
> // Initialize with a version number of 1 and no iterators
> + _GLIBCXX20_CONSTEXPR
> _Safe_sequence_base() _GLIBCXX_NOEXCEPT
> : _M_iterators(0), _M_const_iterators(0), _M_version(1)
> { }
>
> #if __cplusplus >= 201103L
> + _GLIBCXX20_CONSTEXPR
> _Safe_sequence_base(const _Safe_sequence_base&) noexcept
> : _Safe_sequence_base() { }
>
> // Move constructor swap iterators.
> + _GLIBCXX20_CONSTEXPR
> _Safe_sequence_base(_Safe_sequence_base&& __seq) noexcept
> : _Safe_sequence_base()
> - { _M_swap(__seq); }
> + {
> + if (!std::__is_constant_evaluated())
> + _M_swap(__seq);
> + }
> #endif
>
> /** Notify all iterators that reference this sequence that the
> sequence is being destroyed. */
> + _GLIBCXX20_CONSTEXPR
> ~_Safe_sequence_base()
> - { this->_M_detach_all(); }
> + {
> + if (!std::__is_constant_evaluated())
> + this->_M_detach_all();
> + }
>
> /** Detach all iterators, leaving them singular. */
> void
> @@ -244,6 +268,7 @@ namespace __gnu_debug
> * operation is complete all iterators that originally referenced
> * one container now reference the other container.
> */
> + _GLIBCXX20_CONSTEXPR
> void
> _M_swap(_Safe_sequence_base& __x) _GLIBCXX_USE_NOEXCEPT;
>
> diff --git a/libstdc++-v3/include/debug/safe_container.h b/libstdc++-v3/include/debug/safe_container.h
> index 0d8f64740b0..636156af9f5 100644
> --- a/libstdc++-v3/include/debug/safe_container.h
> +++ b/libstdc++-v3/include/debug/safe_container.h
> @@ -43,6 +43,7 @@ namespace __gnu_debug
> {
> typedef _SafeBase<_SafeContainer> _Base;
>
> + _GLIBCXX20_CONSTEXPR
> _SafeContainer&
> _M_cont() _GLIBCXX_NOEXCEPT
> { return *static_cast<_SafeContainer*>(this); }
> @@ -54,20 +55,23 @@ namespace __gnu_debug
> _Safe_container(_Safe_container&&) = default;
>
> private:
> + _GLIBCXX20_CONSTEXPR
> _Safe_container(_Safe_container&& __x, const _Alloc&, std::true_type)
> : _Safe_container(std::move(__x))
> { }
>
> + _GLIBCXX20_CONSTEXPR
> _Safe_container(_Safe_container&& __x, const _Alloc& __a, std::false_type)
> : _Safe_container()
> {
> if (__x._M_cont().get_allocator() == __a)
> _Base::_M_swap(__x);
> - else
> + else if (!std::__is_constant_evaluated())
> __x._M_invalidate_all();
> }
>
> protected:
> + _GLIBCXX20_CONSTEXPR
> _Safe_container(_Safe_container&& __x, const _Alloc& __a)
> : _Safe_container(std::move(__x), __a,
> typename std::allocator_traits<_Alloc>::is_always_equal{})
> @@ -75,17 +79,23 @@ namespace __gnu_debug
> #endif
>
> // Copy assignment invalidate all iterators.
> + _GLIBCXX20_CONSTEXPR
> _Safe_container&
> operator=(const _Safe_container&) _GLIBCXX_NOEXCEPT
> {
> - this->_M_invalidate_all();
> + if (!std::__is_constant_evaluated())
> + this->_M_invalidate_all();
> return *this;
> }
>
> #if __cplusplus >= 201103L
> + _GLIBCXX20_CONSTEXPR
> _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
> @@ -113,6 +123,7 @@ namespace __gnu_debug
> return *this;
> }
>
> + _GLIBCXX20_CONSTEXPR
> void
> _M_swap(_Safe_container& __x) noexcept
> {
> diff --git a/libstdc++-v3/include/debug/safe_iterator.h b/libstdc++-v3/include/debug/safe_iterator.h
> index 693192b3ea9..26f008982f8 100644
> --- a/libstdc++-v3/include/debug/safe_iterator.h
> +++ b/libstdc++-v3/include/debug/safe_iterator.h
> @@ -40,6 +40,7 @@
> #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()), \
> @@ -49,7 +50,8 @@
> _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, \
> @@ -131,9 +133,13 @@ namespace __gnu_debug
>
> struct _Unchecked { };
>
> + _GLIBCXX20_CONSTEXPR
> _Safe_iterator(const _Safe_iterator& __x, _Unchecked) _GLIBCXX_NOEXCEPT
> : _Iter_base(__x.base()), _Safe_base()
> - { _M_attach(__x._M_sequence); }
> + {
> + if (!std::__is_constant_evaluated())
> + _M_attach(__x._M_sequence);
> + }
>
> public:
> typedef _Iterator iterator_type;
> @@ -148,6 +154,7 @@ namespace __gnu_debug
> #endif
>
> /// @post the iterator is singular and unattached
> + _GLIBCXX20_CONSTEXPR
> _Safe_iterator() _GLIBCXX_NOEXCEPT : _Iter_base() { }
>
> /**
> @@ -157,6 +164,7 @@ namespace __gnu_debug
> * @pre @p seq is not NULL
> * @post this is not singular
> */
> + _GLIBCXX20_CONSTEXPR
> _Safe_iterator(_Iterator __i, const _Safe_sequence_base* __seq)
> _GLIBCXX_NOEXCEPT
> : _Iter_base(__i), _Safe_base(__seq, _S_constant())
> @@ -165,9 +173,13 @@ namespace __gnu_debug
> /**
> * @brief Copy construction.
> */
> + _GLIBCXX20_CONSTEXPR
> _Safe_iterator(const _Safe_iterator& __x) _GLIBCXX_NOEXCEPT
> : _Iter_base(__x.base()), _Safe_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()
> @@ -183,9 +195,16 @@ namespace __gnu_debug
> * @brief Move construction.
> * @post __x is singular and unattached
> */
> + _GLIBCXX20_CONSTEXPR
> _Safe_iterator(_Safe_iterator&& __x) noexcept
> : _Iter_base()
> {
> + 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)
> @@ -203,6 +222,7 @@ namespace __gnu_debug
> * constant iterator.
> */
> template<typename _MutableIterator>
> + _GLIBCXX20_CONSTEXPR
> _Safe_iterator(
> const _Safe_iterator<_MutableIterator, _Sequence,
> typename __gnu_cxx::__enable_if<_IsConstant::__value &&
> @@ -211,6 +231,9 @@ namespace __gnu_debug
> _GLIBCXX_NOEXCEPT
> : _Iter_base(__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()
> @@ -224,9 +247,16 @@ namespace __gnu_debug
> /**
> * @brief Copy assignment.
> */
> + _GLIBCXX20_CONSTEXPR
> _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()
> @@ -256,9 +286,16 @@ namespace __gnu_debug
> * @brief Move assignment.
> * @post __x is singular and unattached
> */
> + _GLIBCXX20_CONSTEXPR
> _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)
> @@ -292,12 +329,16 @@ namespace __gnu_debug
> * @pre iterator is dereferenceable
> */
> _GLIBCXX_NODISCARD
> + _GLIBCXX20_CONSTEXPR
> reference
> operator*() const _GLIBCXX_NOEXCEPT
> {
> - _GLIBCXX_DEBUG_VERIFY(this->_M_dereferenceable(),
> - _M_message(__msg_bad_deref)
> - ._M_iterator(*this, "this"));
> + if (!std::__is_constant_evaluated())
> + {
> + _GLIBCXX_DEBUG_VERIFY(this->_M_dereferenceable(),
> + _M_message(__msg_bad_deref)
> + ._M_iterator(*this, "this"));
> + }
> return *base();
> }
>
> @@ -306,12 +347,16 @@ namespace __gnu_debug
> * @pre iterator is dereferenceable
> */
> _GLIBCXX_NODISCARD
> + _GLIBCXX20_CONSTEXPR
> pointer
> operator->() const _GLIBCXX_NOEXCEPT
> {
> - _GLIBCXX_DEBUG_VERIFY(this->_M_dereferenceable(),
> - _M_message(__msg_bad_deref)
> - ._M_iterator(*this, "this"));
> + if (!std::__is_constant_evaluated())
> + {
> + _GLIBCXX_DEBUG_VERIFY(this->_M_dereferenceable(),
> + _M_message(__msg_bad_deref)
> + ._M_iterator(*this, "this"));
> + }
> return base().operator->();
> }
>
> @@ -320,9 +365,16 @@ namespace __gnu_debug
> * @brief Iterator preincrement
> * @pre iterator is incrementable
> */
> + _GLIBCXX20_CONSTEXPR
> _Safe_iterator&
> operator++() _GLIBCXX_NOEXCEPT
> {
> + if (std::__is_constant_evaluated())
> + {
> + ++base();
> + return *this;
> + }
> +
> _GLIBCXX_DEBUG_VERIFY(this->_M_incrementable(),
> _M_message(__msg_bad_inc)
> ._M_iterator(*this, "this"));
> @@ -335,12 +387,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;
> @@ -356,9 +412,11 @@ namespace __gnu_debug
> /**
> * @brief Return the underlying iterator
> */
> + _GLIBCXX20_CONSTEXPR
> _Iterator&
> base() _GLIBCXX_NOEXCEPT { return *this; }
>
> + _GLIBCXX20_CONSTEXPR
> const _Iterator&
> base() const _GLIBCXX_NOEXCEPT { return *this; }
>
> @@ -366,6 +424,7 @@ namespace __gnu_debug
> * @brief Conversion to underlying non-debug iterator to allow
> * better interaction with non-debug containers.
> */
> + _GLIBCXX20_CONSTEXPR
> operator _Iterator() const _GLIBCXX_NOEXCEPT { return *this; }
>
> /** Attach iterator to the given sequence. */
> @@ -440,6 +499,7 @@ namespace __gnu_debug
> _M_get_distance_to_end() const;
>
> /// Is this iterator equal to the sequence's begin() iterator?
> + _GLIBCXX20_CONSTEXPR
> bool
> _M_is_begin() const
> { return base() == _M_get_sequence()->_M_base().begin(); }
> @@ -466,6 +526,7 @@ namespace __gnu_debug
> typedef _Safe_iterator<_Iterator, _Sequence, iterator_category> _Self;
>
> _GLIBCXX_NODISCARD
> + _GLIBCXX20_CONSTEXPR
> friend bool
> operator==(const _Self& __lhs, const _Self& __rhs) _GLIBCXX_NOEXCEPT
> {
> @@ -475,6 +536,7 @@ namespace __gnu_debug
>
> template<typename _IteR>
> _GLIBCXX_NODISCARD
> + _GLIBCXX20_CONSTEXPR
> friend bool
> operator==(const _Self& __lhs,
> const _Safe_iterator<_IteR, _Sequence, iterator_category>& __rhs)
> @@ -518,6 +580,7 @@ namespace __gnu_debug
>
> typedef typename _Safe_base::_Unchecked _Unchecked;
>
> + _GLIBCXX20_CONSTEXPR
> _Safe_iterator(const _Safe_iterator& __x,
> _Unchecked __unchecked) _GLIBCXX_NOEXCEPT
> : _Safe_base(__x, __unchecked)
> @@ -525,6 +588,7 @@ namespace __gnu_debug
>
> public:
> /// @post the iterator is singular and unattached
> + _GLIBCXX20_CONSTEXPR
> _Safe_iterator() _GLIBCXX_NOEXCEPT { }
>
> /**
> @@ -534,6 +598,7 @@ namespace __gnu_debug
> * @pre @p seq is not NULL
> * @post this is not singular
> */
> + _GLIBCXX20_CONSTEXPR
> _Safe_iterator(_Iterator __i, const _Safe_sequence_base* __seq)
> _GLIBCXX_NOEXCEPT
> : _Safe_base(__i, __seq)
> @@ -542,12 +607,14 @@ namespace __gnu_debug
> /**
> * @brief Copy construction.
> */
> + _GLIBCXX20_CONSTEXPR
> _Safe_iterator(const _Safe_iterator& __x) _GLIBCXX_NOEXCEPT
> : _Safe_base(__x)
> { }
>
> #if __cplusplus >= 201103L
> /** @brief Move construction. */
> + _GLIBCXX20_CONSTEXPR
> _Safe_iterator(_Safe_iterator&&) = default;
> #endif
>
> @@ -556,6 +623,7 @@ namespace __gnu_debug
> * constant iterator.
> */
> template<typename _MutableIterator>
> + _GLIBCXX20_CONSTEXPR
> _Safe_iterator(
> const _Safe_iterator<_MutableIterator, _Sequence,
> typename __gnu_cxx::__enable_if<_Safe_base::_IsConstant::__value &&
> @@ -588,6 +656,7 @@ namespace __gnu_debug
> * @brief Iterator preincrement
> * @pre iterator is incrementable
> */
> + _GLIBCXX20_CONSTEXPR
> _Safe_iterator&
> operator++() _GLIBCXX_NOEXCEPT
> {
> @@ -615,9 +684,16 @@ namespace __gnu_debug
> * @brief Iterator predecrement
> * @pre iterator is decrementable
> */
> + _GLIBCXX20_CONSTEXPR
> _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"));
> @@ -663,6 +739,8 @@ namespace __gnu_debug
> std::random_access_iterator_tag> _OtherSelf;
>
> typedef typename _Safe_base::_Unchecked _Unchecked;
> +
> + _GLIBCXX20_CONSTEXPR
> _Safe_iterator(const _Safe_iterator& __x,
> _Unchecked __unchecked) _GLIBCXX_NOEXCEPT
> : _Safe_base(__x, __unchecked)
> @@ -673,6 +751,7 @@ namespace __gnu_debug
> typedef typename _Safe_base::reference reference;
>
> /// @post the iterator is singular and unattached
> + _GLIBCXX20_CONSTEXPR
> _Safe_iterator() _GLIBCXX_NOEXCEPT { }
>
> /**
> @@ -682,6 +761,7 @@ namespace __gnu_debug
> * @pre @p seq is not NULL
> * @post this is not singular
> */
> + _GLIBCXX20_CONSTEXPR
> _Safe_iterator(_Iterator __i, const _Safe_sequence_base* __seq)
> _GLIBCXX_NOEXCEPT
> : _Safe_base(__i, __seq)
> @@ -690,6 +770,7 @@ namespace __gnu_debug
> /**
> * @brief Copy construction.
> */
> + _GLIBCXX20_CONSTEXPR
> _Safe_iterator(const _Safe_iterator& __x) _GLIBCXX_NOEXCEPT
> : _Safe_base(__x)
> { }
> @@ -704,6 +785,7 @@ namespace __gnu_debug
> * constant iterator.
> */
> template<typename _MutableIterator>
> + _GLIBCXX20_CONSTEXPR
> _Safe_iterator(
> const _Safe_iterator<_MutableIterator, _Sequence,
> typename __gnu_cxx::__enable_if<_Safe_base::_IsConstant::__value &&
> @@ -742,6 +824,7 @@ namespace __gnu_debug
> * @brief Iterator preincrement
> * @pre iterator is incrementable
> */
> + _GLIBCXX20_CONSTEXPR
> _Safe_iterator&
> operator++() _GLIBCXX_NOEXCEPT
> {
> @@ -753,12 +836,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;
> @@ -769,6 +856,7 @@ namespace __gnu_debug
> * @brief Iterator predecrement
> * @pre iterator is decrementable
> */
> + _GLIBCXX20_CONSTEXPR
> _Safe_iterator&
> operator--() _GLIBCXX_NOEXCEPT
> {
> @@ -780,12 +868,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;
> @@ -793,19 +885,30 @@ namespace __gnu_debug
>
> // ------ Random access iterator requirements ------
> _GLIBCXX_NODISCARD
> + _GLIBCXX20_CONSTEXPR
> reference
> operator[](difference_type __n) const _GLIBCXX_NOEXCEPT
> {
> - _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));
> + 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));
> + }
> return this->base()[__n];
> }
>
> + _GLIBCXX20_CONSTEXPR
> _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));
> @@ -814,9 +917,16 @@ namespace __gnu_debug
> return *this;
> }
>
> + _GLIBCXX20_CONSTEXPR
> _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));
> @@ -827,6 +937,7 @@ namespace __gnu_debug
>
> #if __cpp_lib_three_way_comparison
> [[nodiscard]]
> + _GLIBCXX20_CONSTEXPR
> friend auto
> operator<=>(const _Self& __lhs, const _Self& __rhs) noexcept
> {
> @@ -835,6 +946,7 @@ namespace __gnu_debug
> }
>
> [[nodiscard]]
> + _GLIBCXX20_CONSTEXPR
> friend auto
> operator<=>(const _Self& __lhs, const _OtherSelf& __rhs) noexcept
> {
> @@ -912,6 +1024,7 @@ namespace __gnu_debug
> // operators but also operator- must accept mixed iterator/const_iterator
> // parameters.
> _GLIBCXX_NODISCARD
> + _GLIBCXX20_CONSTEXPR
> friend difference_type
> operator-(const _Self& __lhs, const _OtherSelf& __rhs) _GLIBCXX_NOEXCEPT
> {
> @@ -920,6 +1033,7 @@ namespace __gnu_debug
> }
>
> _GLIBCXX_NODISCARD
> + _GLIBCXX20_CONSTEXPR
> friend difference_type
> operator-(const _Self& __lhs, const _Self& __rhs) _GLIBCXX_NOEXCEPT
> {
> @@ -928,32 +1042,44 @@ namespace __gnu_debug
> }
>
> _GLIBCXX_NODISCARD
> + _GLIBCXX20_CONSTEXPR
> friend _Self
> operator+(const _Self& __x, difference_type __n) _GLIBCXX_NOEXCEPT
> {
> - _GLIBCXX_DEBUG_VERIFY(__x._M_can_advance(__n),
> - _M_message(__msg_advance_oob)
> - ._M_iterator(__x)._M_integer(__n));
> + if (!std::__is_constant_evaluated())
> + {
> + _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);
> }
>
> _GLIBCXX_NODISCARD
> + _GLIBCXX20_CONSTEXPR
> friend _Self
> operator+(difference_type __n, const _Self& __x) _GLIBCXX_NOEXCEPT
> {
> - _GLIBCXX_DEBUG_VERIFY(__x._M_can_advance(__n),
> - _M_message(__msg_advance_oob)
> - ._M_iterator(__x)._M_integer(__n));
> + if (!std::__is_constant_evaluated())
> + {
> + _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);
> }
>
> _GLIBCXX_NODISCARD
> + _GLIBCXX20_CONSTEXPR
> friend _Self
> operator-(const _Self& __x, difference_type __n) _GLIBCXX_NOEXCEPT
> {
> - _GLIBCXX_DEBUG_VERIFY(__x._M_can_advance(-__n),
> - _M_message(__msg_retreat_oob)
> - ._M_iterator(__x)._M_integer(__n));
> + if (!std::__is_constant_evaluated())
> + {
> + _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);
> }
> };
> diff --git a/libstdc++-v3/include/debug/safe_iterator.tcc b/libstdc++-v3/include/debug/safe_iterator.tcc
> index 170229ad2f1..0bb3dd017b9 100644
> --- a/libstdc++-v3/include/debug/safe_iterator.tcc
> +++ b/libstdc++-v3/include/debug/safe_iterator.tcc
> @@ -236,6 +236,7 @@ namespace std _GLIBCXX_VISIBILITY(default)
> _GLIBCXX_BEGIN_NAMESPACE_VERSION
>
> template<typename _Ite, typename _Seq>
> + _GLIBCXX20_CONSTEXPR
> _Ite
> __niter_base(const ::__gnu_debug::_Safe_iterator<_Ite, _Seq,
> std::random_access_iterator_tag>& __it)
> @@ -243,6 +244,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>
> template<bool _IsMove,
> typename _Ite, typename _Seq, typename _Cat, typename _OI>
> + _GLIBCXX20_CONSTEXPR
> _OI
> __copy_move_a(
> const ::__gnu_debug::_Safe_iterator<_Ite, _Seq, _Cat>& __first,
> @@ -262,6 +264,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>
> template<bool _IsMove,
> typename _II, typename _Ite, typename _Seq, typename _Cat>
> + _GLIBCXX20_CONSTEXPR
> __gnu_debug::_Safe_iterator<_Ite, _Seq, _Cat>
> __copy_move_a(_II __first, _II __last,
> const ::__gnu_debug::_Safe_iterator<_Ite, _Seq, _Cat>& __result)
> @@ -282,6 +285,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> template<bool _IsMove,
> typename _IIte, typename _ISeq, typename _ICat,
> typename _OIte, typename _OSeq, typename _OCat>
> + _GLIBCXX20_CONSTEXPR
> ::__gnu_debug::_Safe_iterator<_OIte, _OSeq, _OCat>
> __copy_move_a(
> const ::__gnu_debug::_Safe_iterator<_IIte, _ISeq, _ICat>& __first,
> @@ -310,6 +314,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>
> template<bool _IsMove,
> typename _Ite, typename _Seq, typename _Cat, typename _OI>
> + _GLIBCXX20_CONSTEXPR
> _OI
> __copy_move_backward_a(
> const ::__gnu_debug::_Safe_iterator<_Ite, _Seq, _Cat>& __first,
> @@ -329,6 +334,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>
> template<bool _IsMove,
> typename _II, typename _Ite, typename _Seq, typename _Cat>
> + _GLIBCXX20_CONSTEXPR
> __gnu_debug::_Safe_iterator<_Ite, _Seq, _Cat>
> __copy_move_backward_a(_II __first, _II __last,
> const ::__gnu_debug::_Safe_iterator<_Ite, _Seq, _Cat>& __result)
> @@ -350,6 +356,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> template<bool _IsMove,
> typename _IIte, typename _ISeq, typename _ICat,
> typename _OIte, typename _OSeq, typename _OCat>
> + _GLIBCXX20_CONSTEXPR
> ::__gnu_debug::_Safe_iterator<_OIte, _OSeq, _OCat>
> __copy_move_backward_a(
> const ::__gnu_debug::_Safe_iterator<_IIte, _ISeq, _ICat>& __first,
> @@ -377,6 +384,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> }
>
> template<typename _Ite, typename _Seq, typename _Cat, typename _Tp>
> + _GLIBCXX20_CONSTEXPR
> void
> __fill_a(const ::__gnu_debug::_Safe_iterator<_Ite, _Seq, _Cat>& __first,
> const ::__gnu_debug::_Safe_iterator<_Ite, _Seq, _Cat>& __last,
> @@ -393,6 +401,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>
> template<typename _Ite, typename _Seq, typename _Cat, typename _Size,
> typename _Tp>
> + _GLIBCXX20_CONSTEXPR
> ::__gnu_debug::_Safe_iterator<_Ite, _Seq, _Cat>
> __fill_n_a(const ::__gnu_debug::_Safe_iterator<_Ite, _Seq, _Cat>& __first,
> _Size __n, const _Tp& __value,
> @@ -415,6 +424,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> }
>
> template<typename _II1, typename _Seq1, typename _Cat1, typename _II2>
> + _GLIBCXX20_CONSTEXPR
> bool
> __equal_aux(
> const ::__gnu_debug::_Safe_iterator<_II1, _Seq1, _Cat1>& __first1,
> @@ -432,6 +442,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> }
>
> template<typename _II1, typename _II2, typename _Seq2, typename _Cat2>
> + _GLIBCXX20_CONSTEXPR
> bool
> __equal_aux(_II1 __first1, _II1 __last1,
> const ::__gnu_debug::_Safe_iterator<_II2, _Seq2, _Cat2>& __first2)
> @@ -449,6 +460,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>
> template<typename _II1, typename _Seq1, typename _Cat1,
> typename _II2, typename _Seq2, typename _Cat2>
> + _GLIBCXX20_CONSTEXPR
> bool
> __equal_aux(
> const ::__gnu_debug::_Safe_iterator<_II1, _Seq1, _Cat1>& __first1,
> @@ -473,6 +485,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>
> template<typename _Ite1, typename _Seq1, typename _Cat1,
> typename _II2>
> + _GLIBCXX20_CONSTEXPR
> bool
> __lexicographical_compare_aux(
> const ::__gnu_debug::_Safe_iterator<_Ite1, _Seq1, _Cat1>& __first1,
> @@ -493,6 +506,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>
> template<typename _II1,
> typename _Ite2, typename _Seq2, typename _Cat2>
> + _GLIBCXX20_CONSTEXPR
> bool
> __lexicographical_compare_aux(
> _II1 __first1, _II1 __last1,
> @@ -513,6 +527,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>
> template<typename _Ite1, typename _Seq1, typename _Cat1,
> typename _Ite2, typename _Seq2, typename _Cat2>
> + _GLIBCXX20_CONSTEXPR
> bool
> __lexicographical_compare_aux(
> const ::__gnu_debug::_Safe_iterator<_Ite1, _Seq1, _Cat1>& __first1,
> diff --git a/libstdc++-v3/include/debug/vector b/libstdc++-v3/include/debug/vector
> index ed462caf936..124ae6da1c1 100644
> --- a/libstdc++-v3/include/debug/vector
> +++ b/libstdc++-v3/include/debug/vector
> @@ -55,22 +55,27 @@ namespace __gnu_debug
> {
> typedef typename _BaseSequence::size_type size_type;
>
> + _GLIBCXX20_CONSTEXPR
> const _SafeSequence&
> _M_seq() const { return *static_cast<const _SafeSequence*>(this); }
>
> protected:
> + _GLIBCXX20_CONSTEXPR
> _Safe_vector() _GLIBCXX_NOEXCEPT
> : _M_guaranteed_capacity(0)
> { _M_update_guaranteed_capacity(); }
>
> + _GLIBCXX20_CONSTEXPR
> _Safe_vector(const _Safe_vector&) _GLIBCXX_NOEXCEPT
> : _M_guaranteed_capacity(0)
> { _M_update_guaranteed_capacity(); }
>
> + _GLIBCXX20_CONSTEXPR
> _Safe_vector(size_type __n) _GLIBCXX_NOEXCEPT
> : _M_guaranteed_capacity(__n)
> { }
>
> + _GLIBCXX20_CONSTEXPR
> _Safe_vector&
> operator=(const _Safe_vector&) _GLIBCXX_NOEXCEPT
> {
> @@ -79,10 +84,12 @@ namespace __gnu_debug
> }
>
> #if __cplusplus >= 201103L
> + _GLIBCXX20_CONSTEXPR
> _Safe_vector(_Safe_vector&& __x) noexcept
> : _Safe_vector()
> { __x._M_guaranteed_capacity = 0; }
>
> + _GLIBCXX20_CONSTEXPR
> _Safe_vector&
> operator=(_Safe_vector&& __x) noexcept
> {
> @@ -98,6 +105,7 @@ namespace __gnu_debug
> _M_requires_reallocation(size_type __elements) const _GLIBCXX_NOEXCEPT
> { return __elements > _M_seq().capacity(); }
>
> + _GLIBCXX20_CONSTEXPR
> void
> _M_update_guaranteed_capacity() _GLIBCXX_NOEXCEPT
> {
> @@ -172,15 +180,18 @@ namespace __debug
> vector() = default;
> #endif
>
> + _GLIBCXX20_CONSTEXPR
> explicit
> vector(const _Allocator& __a) _GLIBCXX_NOEXCEPT
> : _Base(__a) { }
>
> #if __cplusplus >= 201103L
> + _GLIBCXX20_CONSTEXPR
> explicit
> vector(size_type __n, const _Allocator& __a = _Allocator())
> : _Base(__n, __a), _Safe_vector(__n) { }
>
> + _GLIBCXX20_CONSTEXPR
> vector(size_type __n, const __type_identity_t<_Tp>& __value,
> const _Allocator& __a = _Allocator())
> : _Base(__n, __value, __a) { }
> @@ -197,10 +208,11 @@ namespace __debug
> #else
> template<class _InputIterator>
> #endif
> + _GLIBCXX20_CONSTEXPR
> vector(_InputIterator __first, _InputIterator __last,
> const _Allocator& __a = _Allocator())
> - : _Base(__gnu_debug::__base(
> - __glibcxx_check_valid_constructor_range(__first, __last)),
> + : _Base(__gnu_debug::__base(std::__is_constant_evaluated() ? __first
> + : __glibcxx_check_valid_constructor_range(__first, __last)),
> __gnu_debug::__base(__last), __a) { }
>
> #if __cplusplus < 201103L
> @@ -212,9 +224,11 @@ namespace __debug
> vector(const vector&) = default;
> vector(vector&&) = default;
>
> + _GLIBCXX20_CONSTEXPR
> vector(const vector& __x, const __type_identity_t<allocator_type>& __a)
> : _Base(__x, __a) { }
>
> + _GLIBCXX20_CONSTEXPR
> vector(vector&& __x, const __type_identity_t<allocator_type>& __a)
> noexcept(
> std::is_nothrow_constructible<_Base,
> @@ -223,6 +237,7 @@ namespace __debug
> _Base(std::move(__x), __a),
> _Safe_vector(std::move(__x)) { }
>
> + _GLIBCXX20_CONSTEXPR
> vector(initializer_list<value_type> __l,
> const allocator_type& __a = allocator_type())
> : _Base(__l, __a) { }
> @@ -231,6 +246,7 @@ namespace __debug
> #endif
>
> /// Construction from a normal-mode vector
> + _GLIBCXX20_CONSTEXPR
> vector(_Base_ref __x)
> : _Base(__x._M_ref) { }
>
> @@ -241,12 +257,16 @@ namespace __debug
> vector&
> operator=(vector&&) = default;
>
> + _GLIBCXX20_CONSTEXPR
> vector&
> operator=(initializer_list<value_type> __l)
> {
> _Base::operator=(__l);
> - this->_M_invalidate_all();
> - this->_M_update_guaranteed_capacity();
> + if (!std::__is_constant_evaluated())
> + {
> + this->_M_invalidate_all();
> + this->_M_update_guaranteed_capacity();
> + }
> return *this;
> }
> #endif
> @@ -257,9 +277,14 @@ namespace __debug
> #else
> template<typename _InputIterator>
> #endif
> + _GLIBCXX20_CONSTEXPR
> 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);
>
> @@ -273,21 +298,29 @@ namespace __debug
> this->_M_update_guaranteed_capacity();
> }
>
> + _GLIBCXX20_CONSTEXPR
> void
> assign(size_type __n, const _Tp& __u)
> {
> _Base::assign(__n, __u);
> - this->_M_invalidate_all();
> - this->_M_update_guaranteed_capacity();
> + if (!std::__is_constant_evaluated())
> + {
> + this->_M_invalidate_all();
> + this->_M_update_guaranteed_capacity();
> + }
> }
>
> #if __cplusplus >= 201103L
> + _GLIBCXX20_CONSTEXPR
> void
> assign(initializer_list<value_type> __l)
> {
> _Base::assign(__l);
> - this->_M_invalidate_all();
> - this->_M_update_guaranteed_capacity();
> + if (!std::__is_constant_evaluated())
> + {
> + this->_M_invalidate_all();
> + this->_M_update_guaranteed_capacity();
> + }
> }
> #endif
>
> @@ -295,62 +328,74 @@ namespace __debug
>
> // iterators:
> _GLIBCXX_NODISCARD
> + _GLIBCXX20_CONSTEXPR
> iterator
> begin() _GLIBCXX_NOEXCEPT
> { return iterator(_Base::begin(), this); }
>
> _GLIBCXX_NODISCARD
> + _GLIBCXX20_CONSTEXPR
> const_iterator
> begin() const _GLIBCXX_NOEXCEPT
> { return const_iterator(_Base::begin(), this); }
>
> _GLIBCXX_NODISCARD
> + _GLIBCXX20_CONSTEXPR
> iterator
> end() _GLIBCXX_NOEXCEPT
> { return iterator(_Base::end(), this); }
>
> _GLIBCXX_NODISCARD
> + _GLIBCXX20_CONSTEXPR
> const_iterator
> end() const _GLIBCXX_NOEXCEPT
> { return const_iterator(_Base::end(), this); }
>
> _GLIBCXX_NODISCARD
> + _GLIBCXX20_CONSTEXPR
> reverse_iterator
> rbegin() _GLIBCXX_NOEXCEPT
> { return reverse_iterator(end()); }
>
> _GLIBCXX_NODISCARD
> + _GLIBCXX20_CONSTEXPR
> const_reverse_iterator
> rbegin() const _GLIBCXX_NOEXCEPT
> { return const_reverse_iterator(end()); }
>
> _GLIBCXX_NODISCARD
> + _GLIBCXX20_CONSTEXPR
> reverse_iterator
> rend() _GLIBCXX_NOEXCEPT
> { return reverse_iterator(begin()); }
>
> _GLIBCXX_NODISCARD
> + _GLIBCXX20_CONSTEXPR
> const_reverse_iterator
> rend() const _GLIBCXX_NOEXCEPT
> { return const_reverse_iterator(begin()); }
>
> #if __cplusplus >= 201103L
> [[__nodiscard__]]
> + _GLIBCXX20_CONSTEXPR
> const_iterator
> cbegin() const noexcept
> { return const_iterator(_Base::begin(), this); }
>
> [[__nodiscard__]]
> + _GLIBCXX20_CONSTEXPR
> const_iterator
> cend() const noexcept
> { return const_iterator(_Base::end(), this); }
>
> [[__nodiscard__]]
> + _GLIBCXX20_CONSTEXPR
> const_reverse_iterator
> crbegin() const noexcept
> { return const_reverse_iterator(end()); }
>
> [[__nodiscard__]]
> + _GLIBCXX20_CONSTEXPR
> const_reverse_iterator
> crend() const noexcept
> { return const_reverse_iterator(begin()); }
> @@ -361,9 +406,13 @@ namespace __debug
> using _Base::max_size;
>
> #if __cplusplus >= 201103L
> + _GLIBCXX20_CONSTEXPR
> 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);
> @@ -373,9 +422,13 @@ namespace __debug
> this->_M_update_guaranteed_capacity();
> }
>
> + _GLIBCXX20_CONSTEXPR
> 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);
> @@ -399,9 +452,13 @@ namespace __debug
> #endif
>
> #if __cplusplus >= 201103L
> + _GLIBCXX20_CONSTEXPR
> 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();
> @@ -411,9 +468,13 @@ namespace __debug
> #endif
>
> _GLIBCXX_NODISCARD
> + _GLIBCXX20_CONSTEXPR
> size_type
> capacity() const _GLIBCXX_NOEXCEPT
> {
> + if (std::__is_constant_evaluated())
> + return _Base::capacity();
> +
> #ifdef _GLIBCXX_DEBUG_PEDANTIC
> return this->_M_guaranteed_capacity;
> #else
> @@ -423,9 +484,13 @@ namespace __debug
>
> using _Base::empty;
>
> + _GLIBCXX20_CONSTEXPR
> 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)
> @@ -436,6 +501,7 @@ namespace __debug
>
> // element access:
> _GLIBCXX_NODISCARD
> + _GLIBCXX20_CONSTEXPR
> reference
> operator[](size_type __n) _GLIBCXX_NOEXCEPT
> {
> @@ -444,6 +510,7 @@ namespace __debug
> }
>
> _GLIBCXX_NODISCARD
> + _GLIBCXX20_CONSTEXPR
> const_reference
> operator[](size_type __n) const _GLIBCXX_NOEXCEPT
> {
> @@ -454,6 +521,7 @@ namespace __debug
> using _Base::at;
>
> _GLIBCXX_NODISCARD
> + _GLIBCXX20_CONSTEXPR
> reference
> front() _GLIBCXX_NOEXCEPT
> {
> @@ -462,6 +530,7 @@ namespace __debug
> }
>
> _GLIBCXX_NODISCARD
> + _GLIBCXX20_CONSTEXPR
> const_reference
> front() const _GLIBCXX_NOEXCEPT
> {
> @@ -470,6 +539,7 @@ namespace __debug
> }
>
> _GLIBCXX_NODISCARD
> + _GLIBCXX20_CONSTEXPR
> reference
> back() _GLIBCXX_NOEXCEPT
> {
> @@ -478,6 +548,7 @@ namespace __debug
> }
>
> _GLIBCXX_NODISCARD
> + _GLIBCXX20_CONSTEXPR
> const_reference
> back() const _GLIBCXX_NOEXCEPT
> {
> @@ -490,9 +561,13 @@ namespace __debug
> using _Base::data;
>
> // 23.2.4.3 modifiers:
> + _GLIBCXX20_CONSTEXPR
> 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)
> @@ -502,12 +577,14 @@ namespace __debug
>
> #if __cplusplus >= 201103L
> template<typename _Up = _Tp>
> + _GLIBCXX20_CONSTEXPR
> typename __gnu_cxx::__enable_if<!std::__are_same<_Up, bool>::__value,
> void>::__type
> push_back(_Tp&& __x)
> { emplace_back(std::move(__x)); }
>
> template<typename... _Args>
> + _GLIBCXX20_CONSTEXPR
> #if __cplusplus > 201402L
> reference
> #else
> @@ -515,6 +592,9 @@ 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)
> @@ -526,19 +606,29 @@ namespace __debug
> }
> #endif
>
> + _GLIBCXX20_CONSTEXPR
> void
> pop_back() _GLIBCXX_NOEXCEPT
> {
> - __glibcxx_check_nonempty();
> - this->_M_invalidate_if(_Equal(--_Base::end()));
> + if (!std::__is_constant_evaluated())
> + {
> + __glibcxx_check_nonempty();
> + this->_M_invalidate_if(_Equal(--_Base::end()));
> + }
> _Base::pop_back();
> }
>
> #if __cplusplus >= 201103L
> template<typename... _Args>
> + _GLIBCXX20_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);
> bool __realloc = this->_M_requires_reallocation(this->size() + 1);
> difference_type __offset = __position.base() - _Base::cbegin();
> @@ -553,6 +643,7 @@ namespace __debug
> }
> #endif
>
> + _GLIBCXX20_CONSTEXPR
> iterator
> #if __cplusplus >= 201103L
> insert(const_iterator __position, const _Tp& __x)
> @@ -560,6 +651,9 @@ 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();
> @@ -574,20 +668,26 @@ namespace __debug
>
> #if __cplusplus >= 201103L
> template<typename _Up = _Tp>
> + _GLIBCXX20_CONSTEXPR
> typename __gnu_cxx::__enable_if<!std::__are_same<_Up, bool>::__value,
> iterator>::__type
> insert(const_iterator __position, _Tp&& __x)
> { return emplace(__position, std::move(__x)); }
>
> + _GLIBCXX20_CONSTEXPR
> iterator
> insert(const_iterator __position, initializer_list<value_type> __l)
> { return this->insert(__position, __l.begin(), __l.end()); }
> #endif
>
> #if __cplusplus >= 201103L
> + _GLIBCXX20_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);
> bool __realloc = this->_M_requires_reallocation(this->size() + __n);
> difference_type __offset = __position.base() - _Base::cbegin();
> @@ -618,10 +718,16 @@ namespace __debug
> #if __cplusplus >= 201103L
> template<class _InputIterator,
> typename = std::_RequireInputIter<_InputIterator>>
> + _GLIBCXX20_CONSTEXPR
> iterator
> 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);
>
> @@ -673,6 +779,7 @@ namespace __debug
> }
> #endif
>
> + _GLIBCXX20_CONSTEXPR
> iterator
> #if __cplusplus >= 201103L
> erase(const_iterator __position)
> @@ -680,6 +787,9 @@ 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());
> @@ -687,6 +797,7 @@ namespace __debug
> return iterator(__res, this);
> }
>
> + _GLIBCXX20_CONSTEXPR
> iterator
> #if __cplusplus >= 201103L
> erase(const_iterator __first, const_iterator __last)
> @@ -694,6 +805,9 @@ 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);
> @@ -714,25 +828,31 @@ namespace __debug
> #endif
> }
>
> + _GLIBCXX20_CONSTEXPR
> void
> swap(vector& __x)
> _GLIBCXX_NOEXCEPT_IF( noexcept(declval<_Base&>().swap(__x)) )
> {
> - _Safe::_M_swap(__x);
> + if (!std::__is_constant_evaluated())
> + _Safe::_M_swap(__x);
> _Base::swap(__x);
> std::swap(this->_M_guaranteed_capacity, __x._M_guaranteed_capacity);
> }
>
> + _GLIBCXX20_CONSTEXPR
> void
> clear() _GLIBCXX_NOEXCEPT
> {
> _Base::clear();
> - this->_M_invalidate_all();
> + if (!std::__is_constant_evaluated())
> + this->_M_invalidate_all();
> }
>
> + _GLIBCXX20_CONSTEXPR
> _Base&
> _M_base() _GLIBCXX_NOEXCEPT { return *this; }
>
> + _GLIBCXX20_CONSTEXPR
> const _Base&
> _M_base() const _GLIBCXX_NOEXCEPT { return *this; }
>
> @@ -746,6 +866,7 @@ namespace __debug
> };
>
> template<typename _Tp, typename _Alloc>
> + _GLIBCXX20_CONSTEXPR
> inline bool
> operator==(const vector<_Tp, _Alloc>& __lhs,
> const vector<_Tp, _Alloc>& __rhs)
> @@ -789,6 +910,7 @@ namespace __debug
> #endif // three-way comparison
>
> template<typename _Tp, typename _Alloc>
> + _GLIBCXX20_CONSTEXPR
> inline void
> swap(vector<_Tp, _Alloc>& __lhs, vector<_Tp, _Alloc>& __rhs)
> _GLIBCXX_NOEXCEPT_IF(noexcept(__lhs.swap(__rhs)))
> diff --git a/libstdc++-v3/testsuite/23_containers/vector/bool/capacity/constexpr.cc b/libstdc++-v3/testsuite/23_containers/vector/bool/capacity/constexpr.cc
> index d44e9d97b46..534128c487e 100644
> --- a/libstdc++-v3/testsuite/23_containers/vector/bool/capacity/constexpr.cc
> +++ b/libstdc++-v3/testsuite/23_containers/vector/bool/capacity/constexpr.cc
> @@ -1,5 +1,4 @@
> // { dg-do compile { target c++20 } }
> -// { dg-xfail-if "not supported" { debug_mode } }
>
> #include <vector>
> #include <testsuite_hooks.h>
> diff --git a/libstdc++-v3/testsuite/23_containers/vector/bool/cmp_c++20.cc b/libstdc++-v3/testsuite/23_containers/vector/bool/cmp_c++20.cc
> index 66197e0aa29..e852c388903 100644
> --- a/libstdc++-v3/testsuite/23_containers/vector/bool/cmp_c++20.cc
> +++ b/libstdc++-v3/testsuite/23_containers/vector/bool/cmp_c++20.cc
> @@ -16,7 +16,6 @@
> // <http://www.gnu.org/licenses/>.
>
> // { dg-do compile { target c++20 } }
> -// { dg-xfail-if "not supported" { debug_mode } }
>
> #include <vector>
> #include <testsuite_hooks.h>
> diff --git a/libstdc++-v3/testsuite/23_containers/vector/bool/cons/constexpr.cc b/libstdc++-v3/testsuite/23_containers/vector/bool/cons/constexpr.cc
> index 0e0c1e1c5ec..88d99fe682f 100644
> --- a/libstdc++-v3/testsuite/23_containers/vector/bool/cons/constexpr.cc
> +++ b/libstdc++-v3/testsuite/23_containers/vector/bool/cons/constexpr.cc
> @@ -1,5 +1,4 @@
> // { dg-do compile { target c++20 } }
> -// { dg-xfail-if "not supported" { debug_mode } }
>
> #include <vector>
> #include <testsuite_hooks.h>
> diff --git a/libstdc++-v3/testsuite/23_containers/vector/bool/element_access/1.cc b/libstdc++-v3/testsuite/23_containers/vector/bool/element_access/1.cc
> index 2a430845058..e7d710829e1 100644
> --- a/libstdc++-v3/testsuite/23_containers/vector/bool/element_access/1.cc
> +++ b/libstdc++-v3/testsuite/23_containers/vector/bool/element_access/1.cc
> @@ -1,5 +1,4 @@
> // { dg-do compile { target c++23 } }
> -// { dg-xfail-if "not supported" { debug_mode } }
>
> #include <vector>
> #include <testsuite_hooks.h>
> diff --git a/libstdc++-v3/testsuite/23_containers/vector/bool/element_access/constexpr.cc b/libstdc++-v3/testsuite/23_containers/vector/bool/element_access/constexpr.cc
> index 5b8ca94e78f..d6b657e0161 100644
> --- a/libstdc++-v3/testsuite/23_containers/vector/bool/element_access/constexpr.cc
> +++ b/libstdc++-v3/testsuite/23_containers/vector/bool/element_access/constexpr.cc
> @@ -1,5 +1,4 @@
> // { dg-do compile { target c++20 } }
> -// { dg-xfail-if "not supported" { debug_mode } }
>
> #include <vector>
> #include <testsuite_hooks.h>
> diff --git a/libstdc++-v3/testsuite/23_containers/vector/bool/modifiers/assign/constexpr.cc b/libstdc++-v3/testsuite/23_containers/vector/bool/modifiers/assign/constexpr.cc
> index 3ad7dda88a9..31a6793f7ff 100644
> --- a/libstdc++-v3/testsuite/23_containers/vector/bool/modifiers/assign/constexpr.cc
> +++ b/libstdc++-v3/testsuite/23_containers/vector/bool/modifiers/assign/constexpr.cc
> @@ -1,5 +1,4 @@
> // { dg-do compile { target c++20 } }
> -// { dg-xfail-if "not supported" { debug_mode } }
>
> #include <vector>
> #include <testsuite_hooks.h>
> diff --git a/libstdc++-v3/testsuite/23_containers/vector/bool/modifiers/constexpr.cc b/libstdc++-v3/testsuite/23_containers/vector/bool/modifiers/constexpr.cc
> index 22a4df5e370..0e37f9aa786 100644
> --- a/libstdc++-v3/testsuite/23_containers/vector/bool/modifiers/constexpr.cc
> +++ b/libstdc++-v3/testsuite/23_containers/vector/bool/modifiers/constexpr.cc
> @@ -1,5 +1,4 @@
> // { dg-do compile { target c++20 } }
> -// { dg-xfail-if "not supported" { debug_mode } }
>
> #include <vector>
> #include <testsuite_hooks.h>
> diff --git a/libstdc++-v3/testsuite/23_containers/vector/bool/modifiers/swap/constexpr.cc b/libstdc++-v3/testsuite/23_containers/vector/bool/modifiers/swap/constexpr.cc
> index 624ff96a9e9..d2a0218a109 100644
> --- a/libstdc++-v3/testsuite/23_containers/vector/bool/modifiers/swap/constexpr.cc
> +++ b/libstdc++-v3/testsuite/23_containers/vector/bool/modifiers/swap/constexpr.cc
> @@ -1,5 +1,4 @@
> // { dg-do compile { target c++20 } }
> -// { dg-xfail-if "not supported" { debug_mode } }
>
> #include <vector>
> #include <utility>
> @@ -49,6 +48,7 @@ test_member_swap()
>
> static_assert(test_member_swap());
>
> +#ifndef _GLIBCXX_DEBUG
> constexpr bool
> test_reference_swap()
> {
> @@ -63,3 +63,4 @@ test_reference_swap()
> }
>
> static_assert(test_reference_swap());
> +#endif
> diff --git a/libstdc++-v3/testsuite/23_containers/vector/capacity/constexpr.cc b/libstdc++-v3/testsuite/23_containers/vector/capacity/constexpr.cc
> index 018a4792891..c331dbd5e57 100644
> --- a/libstdc++-v3/testsuite/23_containers/vector/capacity/constexpr.cc
> +++ b/libstdc++-v3/testsuite/23_containers/vector/capacity/constexpr.cc
> @@ -1,5 +1,4 @@
> // { dg-do compile { target c++20 } }
> -// { dg-xfail-if "not supported" { debug_mode } }
>
> #include <vector>
> #include <testsuite_hooks.h>
> diff --git a/libstdc++-v3/testsuite/23_containers/vector/cmp_c++20.cc b/libstdc++-v3/testsuite/23_containers/vector/cmp_c++20.cc
> index 72c5c6cd7f9..63cb92c0edf 100644
> --- a/libstdc++-v3/testsuite/23_containers/vector/cmp_c++20.cc
> +++ b/libstdc++-v3/testsuite/23_containers/vector/cmp_c++20.cc
> @@ -16,7 +16,6 @@
> // <http://www.gnu.org/licenses/>.
>
> // { dg-do compile { target c++20 } }
> -// { dg-xfail-if "not supported" { debug_mode } }
>
> #include <vector>
> #include <testsuite_hooks.h>
> diff --git a/libstdc++-v3/testsuite/23_containers/vector/cons/constexpr.cc b/libstdc++-v3/testsuite/23_containers/vector/cons/constexpr.cc
> index 7bf86511240..fa78676b300 100644
> --- a/libstdc++-v3/testsuite/23_containers/vector/cons/constexpr.cc
> +++ b/libstdc++-v3/testsuite/23_containers/vector/cons/constexpr.cc
> @@ -1,6 +1,5 @@
> // { dg-do compile { target c++20 } }
> // { dg-add-options no_pch }
> -// { dg-xfail-if "not supported" { debug_mode } }
>
> #include <vector>
>
> diff --git a/libstdc++-v3/testsuite/23_containers/vector/data_access/constexpr.cc b/libstdc++-v3/testsuite/23_containers/vector/data_access/constexpr.cc
> index f5b601a44f4..142050e8f03 100644
> --- a/libstdc++-v3/testsuite/23_containers/vector/data_access/constexpr.cc
> +++ b/libstdc++-v3/testsuite/23_containers/vector/data_access/constexpr.cc
> @@ -1,5 +1,4 @@
> // { dg-do compile { target c++20 } }
> -// { dg-xfail-if "not supported" { debug_mode } }
>
> #include <vector>
> #include <testsuite_hooks.h>
> diff --git a/libstdc++-v3/testsuite/23_containers/vector/element_access/constexpr.cc b/libstdc++-v3/testsuite/23_containers/vector/element_access/constexpr.cc
> index 60c66dcc647..ee93d2fd95e 100644
> --- a/libstdc++-v3/testsuite/23_containers/vector/element_access/constexpr.cc
> +++ b/libstdc++-v3/testsuite/23_containers/vector/element_access/constexpr.cc
> @@ -1,5 +1,4 @@
> // { dg-do compile { target c++20 } }
> -// { dg-xfail-if "not supported" { debug_mode } }
>
> #include <vector>
> #include <testsuite_hooks.h>
> diff --git a/libstdc++-v3/testsuite/23_containers/vector/modifiers/assign/constexpr.cc b/libstdc++-v3/testsuite/23_containers/vector/modifiers/assign/constexpr.cc
> index cca20f4291c..41fc8d9696e 100644
> --- a/libstdc++-v3/testsuite/23_containers/vector/modifiers/assign/constexpr.cc
> +++ b/libstdc++-v3/testsuite/23_containers/vector/modifiers/assign/constexpr.cc
> @@ -1,5 +1,4 @@
> // { dg-do compile { target c++20 } }
> -// { dg-xfail-if "not supported" { debug_mode } }
>
> #include <vector>
> #include <testsuite_hooks.h>
> diff --git a/libstdc++-v3/testsuite/23_containers/vector/modifiers/constexpr.cc b/libstdc++-v3/testsuite/23_containers/vector/modifiers/constexpr.cc
> index 766e3a7690f..4aa1f1f67b7 100644
> --- a/libstdc++-v3/testsuite/23_containers/vector/modifiers/constexpr.cc
> +++ b/libstdc++-v3/testsuite/23_containers/vector/modifiers/constexpr.cc
> @@ -1,5 +1,4 @@
> // { dg-do compile { target c++20 } }
> -// { dg-xfail-if "not supported" { debug_mode } }
>
> #include <vector>
> #include <testsuite_hooks.h>
> diff --git a/libstdc++-v3/testsuite/23_containers/vector/modifiers/swap/constexpr.cc b/libstdc++-v3/testsuite/23_containers/vector/modifiers/swap/constexpr.cc
> index 45b3986beca..77d2a518d69 100644
> --- a/libstdc++-v3/testsuite/23_containers/vector/modifiers/swap/constexpr.cc
> +++ b/libstdc++-v3/testsuite/23_containers/vector/modifiers/swap/constexpr.cc
> @@ -1,5 +1,4 @@
> // { dg-do compile { target c++20 } }
> -// { dg-xfail-if "not supported" { debug_mode } }
>
> #include <vector>
> #include <utility>
> --
> 2.43.0
>
On Wed, 6 Dec 2023, Jonathan Wakely wrote:
> Any comments on this approach?
>
> -- >8 --
>
> This makes constexpr std::vector (mostly) work in Debug Mode. All safe
> iterator instrumentation and checking is disabled during constant
> evaluation, because it requires mutex locks and calls to non-inline
> functions defined in libstdc++.so. It should be OK to disable the safety
> checks, because most UB should be detected during constant evaluation
> anyway.
>
> We could try to enable the full checking in constexpr, but it would mean
> wrapping all the non-inline functions like _M_attach with an inline
> _M_constexpr_attach that does the iterator housekeeping inline without
> mutex locks when calling for constant evaluation, and calls the
> non-inline function at runtime. That could be done in future if we find
> that we've lost safety or useful checking by disabling the safe
> iterators.
>
> There are a few test failures in C++20 mode, which I'm unable to
> explain. The _Safe_iterator::operator++() member gives errors for using
> non-constexpr functions during constant evaluation, even though those
> functions are guarded by std::is_constant_evaluated() checks. The same
> code works fine for C++23 and up.
AFAICT these C++20 test failures are really due to the variable
definition of non-literal type
381 __gnu_cxx::__scoped_lock __l(this->_M_get_mutex());
which were prohibited in a constexpr function (even if that code was
never executed) until C++23's P2242R3.
We can use an immediately invoked lambda to work around this:
381 [this] {
382 __gnu_cxx::__scoped_lock __l(this->_M_get_mutex());
383 ++base();
384 }();
385 return *this;
>
> libstdc++-v3/ChangeLog:
>
> PR libstdc++/109536
> * include/bits/c++config (__glibcxx_constexpr_assert): Remove
> macro.
> * include/bits/stl_algobase.h (__niter_base, __copy_move_a)
> (__copy_move_backward_a, __fill_a, __fill_n_a, __equal_aux)
> (__lexicographical_compare_aux): Add constexpr to overloads for
> debug mode iterators.
> * include/debug/helper_functions.h (__unsafe): Add constexpr.
> * include/debug/macros.h (_GLIBCXX_DEBUG_VERIFY_COND_AT): Remove
> macro, folding it into ...
> (_GLIBCXX_DEBUG_VERIFY_AT_F): ... here. Do not use
> __glibcxx_constexpr_assert.
> * include/debug/safe_base.h (_Safe_iterator_base): Add constexpr
> to some member functions. Omit attaching, detaching and checking
> operations during constant evaluation.
> * include/debug/safe_container.h (_Safe_container): Likewise.
> * include/debug/safe_iterator.h (_Safe_iterator): Likewise.
> * include/debug/safe_iterator.tcc (__niter_base, __copy_move_a)
> (__copy_move_backward_a, __fill_a, __fill_n_a, __equal_aux)
> (__lexicographical_compare_aux): Add constexpr.
> * include/debug/vector (_Safe_vector, vector): Add constexpr.
> Omit safe iterator operations during constant evaluation.
> * testsuite/23_containers/vector/bool/capacity/constexpr.cc:
> Remove dg-xfail-if for debug mode.
> * testsuite/23_containers/vector/bool/cmp_c++20.cc: Likewise.
> * testsuite/23_containers/vector/bool/cons/constexpr.cc:
> Likewise.
> * testsuite/23_containers/vector/bool/element_access/1.cc:
> Likewise.
> * testsuite/23_containers/vector/bool/element_access/constexpr.cc:
> Likewise.
> * testsuite/23_containers/vector/bool/modifiers/assign/constexpr.cc:
> Likewise.
> * testsuite/23_containers/vector/bool/modifiers/constexpr.cc:
> Likewise.
> * testsuite/23_containers/vector/bool/modifiers/swap/constexpr.cc:
> Likewise.
> * testsuite/23_containers/vector/capacity/constexpr.cc:
> Likewise.
> * testsuite/23_containers/vector/cmp_c++20.cc: Likewise.
> * testsuite/23_containers/vector/cons/constexpr.cc: Likewise.
> * testsuite/23_containers/vector/data_access/constexpr.cc:
> Likewise.
> * testsuite/23_containers/vector/element_access/constexpr.cc:
> Likewise.
> * testsuite/23_containers/vector/modifiers/assign/constexpr.cc:
> Likewise.
> * testsuite/23_containers/vector/modifiers/constexpr.cc:
> Likewise.
> * testsuite/23_containers/vector/modifiers/swap/constexpr.cc:
> Likewise.
> ---
> libstdc++-v3/include/bits/c++config | 9 -
> libstdc++-v3/include/bits/stl_algobase.h | 15 ++
> libstdc++-v3/include/debug/helper_functions.h | 1 +
> libstdc++-v3/include/debug/macros.h | 9 +-
> libstdc++-v3/include/debug/safe_base.h | 35 +++-
> libstdc++-v3/include/debug/safe_container.h | 15 +-
> libstdc++-v3/include/debug/safe_iterator.h | 186 +++++++++++++++---
> libstdc++-v3/include/debug/safe_iterator.tcc | 15 ++
> libstdc++-v3/include/debug/vector | 146 ++++++++++++--
> .../vector/bool/capacity/constexpr.cc | 1 -
> .../23_containers/vector/bool/cmp_c++20.cc | 1 -
> .../vector/bool/cons/constexpr.cc | 1 -
> .../vector/bool/element_access/1.cc | 1 -
> .../vector/bool/element_access/constexpr.cc | 1 -
> .../vector/bool/modifiers/assign/constexpr.cc | 1 -
> .../vector/bool/modifiers/constexpr.cc | 1 -
> .../vector/bool/modifiers/swap/constexpr.cc | 3 +-
> .../vector/capacity/constexpr.cc | 1 -
> .../23_containers/vector/cmp_c++20.cc | 1 -
> .../23_containers/vector/cons/constexpr.cc | 1 -
> .../vector/data_access/constexpr.cc | 1 -
> .../vector/element_access/constexpr.cc | 1 -
> .../vector/modifiers/assign/constexpr.cc | 1 -
> .../vector/modifiers/constexpr.cc | 1 -
> .../vector/modifiers/swap/constexpr.cc | 1 -
> 25 files changed, 369 insertions(+), 80 deletions(-)
>
> diff --git a/libstdc++-v3/include/bits/c++config b/libstdc++-v3/include/bits/c++config
> index 284d24d933f..13d416845c3 100644
> --- a/libstdc++-v3/include/bits/c++config
> +++ b/libstdc++-v3/include/bits/c++config
> @@ -565,15 +565,6 @@ namespace std
> # define _GLIBCXX_EXTERN_TEMPLATE -1
> #endif
>
> -
> -#if _GLIBCXX_HAVE_IS_CONSTANT_EVALUATED
> -# define __glibcxx_constexpr_assert(cond) \
> - if (std::__is_constant_evaluated() && !bool(cond)) \
> - __builtin_unreachable() /* precondition violation detected! */
> -#else
> -# define __glibcxx_constexpr_assert(unevaluated)
> -#endif
> -
> #undef _GLIBCXX_VERBOSE_ASSERT
>
> // Assert.
> diff --git a/libstdc++-v3/include/bits/stl_algobase.h b/libstdc++-v3/include/bits/stl_algobase.h
> index 01ca4496dfd..77d0ee7bcf5 100644
> --- a/libstdc++-v3/include/bits/stl_algobase.h
> +++ b/libstdc++-v3/include/bits/stl_algobase.h
> @@ -318,6 +318,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> { return __it; }
>
> template<typename _Ite, typename _Seq>
> + _GLIBCXX20_CONSTEXPR
> _Ite
> __niter_base(const ::__gnu_debug::_Safe_iterator<_Ite, _Seq,
> std::random_access_iterator_tag>&);
> @@ -545,6 +546,7 @@ _GLIBCXX_END_NAMESPACE_CONTAINER
>
> template<bool _IsMove,
> typename _Ite, typename _Seq, typename _Cat, typename _OI>
> + _GLIBCXX20_CONSTEXPR
> _OI
> __copy_move_a(const ::__gnu_debug::_Safe_iterator<_Ite, _Seq, _Cat>&,
> const ::__gnu_debug::_Safe_iterator<_Ite, _Seq, _Cat>&,
> @@ -552,6 +554,7 @@ _GLIBCXX_END_NAMESPACE_CONTAINER
>
> template<bool _IsMove,
> typename _II, typename _Ite, typename _Seq, typename _Cat>
> + _GLIBCXX20_CONSTEXPR
> __gnu_debug::_Safe_iterator<_Ite, _Seq, _Cat>
> __copy_move_a(_II, _II,
> const ::__gnu_debug::_Safe_iterator<_Ite, _Seq, _Cat>&);
> @@ -559,6 +562,7 @@ _GLIBCXX_END_NAMESPACE_CONTAINER
> template<bool _IsMove,
> typename _IIte, typename _ISeq, typename _ICat,
> typename _OIte, typename _OSeq, typename _OCat>
> + _GLIBCXX20_CONSTEXPR
> ::__gnu_debug::_Safe_iterator<_OIte, _OSeq, _OCat>
> __copy_move_a(const ::__gnu_debug::_Safe_iterator<_IIte, _ISeq, _ICat>&,
> const ::__gnu_debug::_Safe_iterator<_IIte, _ISeq, _ICat>&,
> @@ -812,6 +816,7 @@ _GLIBCXX_END_NAMESPACE_CONTAINER
>
> template<bool _IsMove,
> typename _Ite, typename _Seq, typename _Cat, typename _OI>
> + _GLIBCXX20_CONSTEXPR
> _OI
> __copy_move_backward_a(
> const ::__gnu_debug::_Safe_iterator<_Ite, _Seq, _Cat>&,
> @@ -820,6 +825,7 @@ _GLIBCXX_END_NAMESPACE_CONTAINER
>
> template<bool _IsMove,
> typename _II, typename _Ite, typename _Seq, typename _Cat>
> + _GLIBCXX20_CONSTEXPR
> __gnu_debug::_Safe_iterator<_Ite, _Seq, _Cat>
> __copy_move_backward_a(_II, _II,
> const ::__gnu_debug::_Safe_iterator<_Ite, _Seq, _Cat>&);
> @@ -827,6 +833,7 @@ _GLIBCXX_END_NAMESPACE_CONTAINER
> template<bool _IsMove,
> typename _IIte, typename _ISeq, typename _ICat,
> typename _OIte, typename _OSeq, typename _OCat>
> + _GLIBCXX20_CONSTEXPR
> ::__gnu_debug::_Safe_iterator<_OIte, _OSeq, _OCat>
> __copy_move_backward_a(
> const ::__gnu_debug::_Safe_iterator<_IIte, _ISeq, _ICat>&,
> @@ -977,6 +984,7 @@ _GLIBCXX_END_NAMESPACE_CONTAINER
> { std::__fill_a1(__first, __last, __value); }
>
> template<typename _Ite, typename _Seq, typename _Cat, typename _Tp>
> + _GLIBCXX20_CONSTEXPR
> void
> __fill_a(const ::__gnu_debug::_Safe_iterator<_Ite, _Seq, _Cat>&,
> const ::__gnu_debug::_Safe_iterator<_Ite, _Seq, _Cat>&,
> @@ -1082,6 +1090,7 @@ _GLIBCXX_END_NAMESPACE_CONTAINER
>
> template<typename _Ite, typename _Seq, typename _Cat, typename _Size,
> typename _Tp>
> + _GLIBCXX20_CONSTEXPR
> ::__gnu_debug::_Safe_iterator<_Ite, _Seq, _Cat>
> __fill_n_a(const ::__gnu_debug::_Safe_iterator<_Ite, _Seq, _Cat>& __first,
> _Size __n, const _Tp& __value,
> @@ -1230,18 +1239,21 @@ _GLIBCXX_END_NAMESPACE_CONTAINER
> }
>
> template<typename _II1, typename _Seq1, typename _Cat1, typename _II2>
> + _GLIBCXX20_CONSTEXPR
> bool
> __equal_aux(const ::__gnu_debug::_Safe_iterator<_II1, _Seq1, _Cat1>&,
> const ::__gnu_debug::_Safe_iterator<_II1, _Seq1, _Cat1>&,
> _II2);
>
> template<typename _II1, typename _II2, typename _Seq2, typename _Cat2>
> + _GLIBCXX20_CONSTEXPR
> bool
> __equal_aux(_II1, _II1,
> const ::__gnu_debug::_Safe_iterator<_II2, _Seq2, _Cat2>&);
>
> template<typename _II1, typename _Seq1, typename _Cat1,
> typename _II2, typename _Seq2, typename _Cat2>
> + _GLIBCXX20_CONSTEXPR
> bool
> __equal_aux(const ::__gnu_debug::_Safe_iterator<_II1, _Seq1, _Cat1>&,
> const ::__gnu_debug::_Safe_iterator<_II1, _Seq1, _Cat1>&,
> @@ -1430,6 +1442,7 @@ _GLIBCXX_END_NAMESPACE_CONTAINER
>
> template<typename _Iter1, typename _Seq1, typename _Cat1,
> typename _II2>
> + _GLIBCXX20_CONSTEXPR
> bool
> __lexicographical_compare_aux(
> const ::__gnu_debug::_Safe_iterator<_Iter1, _Seq1, _Cat1>&,
> @@ -1438,6 +1451,7 @@ _GLIBCXX_END_NAMESPACE_CONTAINER
>
> template<typename _II1,
> typename _Iter2, typename _Seq2, typename _Cat2>
> + _GLIBCXX20_CONSTEXPR
> bool
> __lexicographical_compare_aux(
> _II1, _II1,
> @@ -1446,6 +1460,7 @@ _GLIBCXX_END_NAMESPACE_CONTAINER
>
> template<typename _Iter1, typename _Seq1, typename _Cat1,
> typename _Iter2, typename _Seq2, typename _Cat2>
> + _GLIBCXX20_CONSTEXPR
> bool
> __lexicographical_compare_aux(
> const ::__gnu_debug::_Safe_iterator<_Iter1, _Seq1, _Cat1>&,
> diff --git a/libstdc++-v3/include/debug/helper_functions.h b/libstdc++-v3/include/debug/helper_functions.h
> index 052b36b484c..4b76cb00f9a 100644
> --- a/libstdc++-v3/include/debug/helper_functions.h
> +++ b/libstdc++-v3/include/debug/helper_functions.h
> @@ -324,6 +324,7 @@ namespace __gnu_debug
>
> /* Remove debug mode safe iterator layer, if any. */
> template<typename _Iterator>
> + _GLIBCXX_CONSTEXPR
> inline _Iterator
> __unsafe(_Iterator __it)
> { return __it; }
> diff --git a/libstdc++-v3/include/debug/macros.h b/libstdc++-v3/include/debug/macros.h
> index 0fef0a006fc..4a3d0f2ea84 100644
> --- a/libstdc++-v3/include/debug/macros.h
> +++ b/libstdc++-v3/include/debug/macros.h
> @@ -38,15 +38,12 @@
> * the user error and where the error is reported.
> *
> */
> -#define _GLIBCXX_DEBUG_VERIFY_COND_AT(_Cond,_ErrMsg,_File,_Line,_Func) \
> - if (__builtin_expect(!bool(_Cond), false)) \
> - __gnu_debug::_Error_formatter::_S_at(_File, _Line, _Func) \
> - ._ErrMsg._M_error()
>
> #define _GLIBCXX_DEBUG_VERIFY_AT_F(_Cond,_ErrMsg,_File,_Line,_Func) \
> do { \
> - __glibcxx_constexpr_assert(_Cond); \
> - _GLIBCXX_DEBUG_VERIFY_COND_AT(_Cond,_ErrMsg,_File,_Line,_Func); \
> + if (__builtin_expect(!bool(_Cond), false)) \
> + __gnu_debug::_Error_formatter::_S_at(_File, _Line, _Func) \
> + ._ErrMsg._M_error(); \
> } while (false)
>
> #define _GLIBCXX_DEBUG_VERIFY_AT(_Cond,_ErrMsg,_File,_Line) \
> diff --git a/libstdc++-v3/include/debug/safe_base.h b/libstdc++-v3/include/debug/safe_base.h
> index 1dfa9f68b65..d9c17b52b48 100644
> --- a/libstdc++-v3/include/debug/safe_base.h
> +++ b/libstdc++-v3/include/debug/safe_base.h
> @@ -75,6 +75,7 @@ namespace __gnu_debug
>
> protected:
> /** Initializes the iterator and makes it singular. */
> + _GLIBCXX20_CONSTEXPR
> _Safe_iterator_base()
> : _M_sequence(0), _M_version(0), _M_prior(0), _M_next(0)
> { }
> @@ -86,18 +87,31 @@ namespace __gnu_debug
> * 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)
> - { this->_M_attach(const_cast<_Safe_sequence_base*>(__seq), __constant); }
> + {
> + if (!std::__is_constant_evaluated())
> + this->_M_attach(const_cast<_Safe_sequence_base*>(__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. */
> + _GLIBCXX20_CONSTEXPR
> _Safe_iterator_base(const _Safe_iterator_base& __x, bool __constant)
> : _M_sequence(0), _M_version(0), _M_prior(0), _M_next(0)
> - { this->_M_attach(__x._M_sequence, __constant); }
> + {
> + if (!std::__is_constant_evaluated())
> + this->_M_attach(__x._M_sequence, __constant);
> + }
>
> - ~_Safe_iterator_base() { this->_M_detach(); }
> + _GLIBCXX20_CONSTEXPR
> + ~_Safe_iterator_base()
> + {
> + if (!std::__is_constant_evaluated())
> + this->_M_detach();
> + }
>
> /** For use in _Safe_iterator. */
> __gnu_cxx::__mutex&
> @@ -201,24 +215,34 @@ namespace __gnu_debug
>
> protected:
> // Initialize with a version number of 1 and no iterators
> + _GLIBCXX20_CONSTEXPR
> _Safe_sequence_base() _GLIBCXX_NOEXCEPT
> : _M_iterators(0), _M_const_iterators(0), _M_version(1)
> { }
>
> #if __cplusplus >= 201103L
> + _GLIBCXX20_CONSTEXPR
> _Safe_sequence_base(const _Safe_sequence_base&) noexcept
> : _Safe_sequence_base() { }
>
> // Move constructor swap iterators.
> + _GLIBCXX20_CONSTEXPR
> _Safe_sequence_base(_Safe_sequence_base&& __seq) noexcept
> : _Safe_sequence_base()
> - { _M_swap(__seq); }
> + {
> + if (!std::__is_constant_evaluated())
> + _M_swap(__seq);
> + }
> #endif
>
> /** Notify all iterators that reference this sequence that the
> sequence is being destroyed. */
> + _GLIBCXX20_CONSTEXPR
> ~_Safe_sequence_base()
> - { this->_M_detach_all(); }
> + {
> + if (!std::__is_constant_evaluated())
> + this->_M_detach_all();
> + }
>
> /** Detach all iterators, leaving them singular. */
> void
> @@ -244,6 +268,7 @@ namespace __gnu_debug
> * operation is complete all iterators that originally referenced
> * one container now reference the other container.
> */
> + _GLIBCXX20_CONSTEXPR
> void
> _M_swap(_Safe_sequence_base& __x) _GLIBCXX_USE_NOEXCEPT;
With -Wsystem-headers on some ranges tests I get:
/gcc-build/x86_64-pc-linux-gnu/libstdc++-v3/include/debug/safe_base.h:273:5: warning: inline function ‘constexpr void __gnu_debug::_Safe_sequence_base::_M_swap(__gnu_debug::_Safe_sequence_base&)’ used but never defined
273 | _M_swap(_Safe_sequence_base& __x) _GLIBCXX_USE_NOEXCEPT;
| ^~~~~~~
>
> diff --git a/libstdc++-v3/include/debug/safe_container.h b/libstdc++-v3/include/debug/safe_container.h
> index 0d8f64740b0..636156af9f5 100644
> --- a/libstdc++-v3/include/debug/safe_container.h
> +++ b/libstdc++-v3/include/debug/safe_container.h
> @@ -43,6 +43,7 @@ namespace __gnu_debug
> {
> typedef _SafeBase<_SafeContainer> _Base;
>
> + _GLIBCXX20_CONSTEXPR
> _SafeContainer&
> _M_cont() _GLIBCXX_NOEXCEPT
> { return *static_cast<_SafeContainer*>(this); }
> @@ -54,20 +55,23 @@ namespace __gnu_debug
> _Safe_container(_Safe_container&&) = default;
>
> private:
> + _GLIBCXX20_CONSTEXPR
> _Safe_container(_Safe_container&& __x, const _Alloc&, std::true_type)
> : _Safe_container(std::move(__x))
> { }
>
> + _GLIBCXX20_CONSTEXPR
> _Safe_container(_Safe_container&& __x, const _Alloc& __a, std::false_type)
> : _Safe_container()
> {
> if (__x._M_cont().get_allocator() == __a)
> _Base::_M_swap(__x);
> - else
> + else if (!std::__is_constant_evaluated())
> __x._M_invalidate_all();
> }
>
> protected:
> + _GLIBCXX20_CONSTEXPR
> _Safe_container(_Safe_container&& __x, const _Alloc& __a)
> : _Safe_container(std::move(__x), __a,
> typename std::allocator_traits<_Alloc>::is_always_equal{})
> @@ -75,17 +79,23 @@ namespace __gnu_debug
> #endif
>
> // Copy assignment invalidate all iterators.
> + _GLIBCXX20_CONSTEXPR
> _Safe_container&
> operator=(const _Safe_container&) _GLIBCXX_NOEXCEPT
> {
> - this->_M_invalidate_all();
> + if (!std::__is_constant_evaluated())
> + this->_M_invalidate_all();
> return *this;
> }
>
> #if __cplusplus >= 201103L
> + _GLIBCXX20_CONSTEXPR
> _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
> @@ -113,6 +123,7 @@ namespace __gnu_debug
> return *this;
> }
>
> + _GLIBCXX20_CONSTEXPR
> void
> _M_swap(_Safe_container& __x) noexcept
> {
> diff --git a/libstdc++-v3/include/debug/safe_iterator.h b/libstdc++-v3/include/debug/safe_iterator.h
> index 693192b3ea9..26f008982f8 100644
> --- a/libstdc++-v3/include/debug/safe_iterator.h
> +++ b/libstdc++-v3/include/debug/safe_iterator.h
> @@ -40,6 +40,7 @@
> #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()), \
> @@ -49,7 +50,8 @@
> _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, \
> @@ -131,9 +133,13 @@ namespace __gnu_debug
>
> struct _Unchecked { };
>
> + _GLIBCXX20_CONSTEXPR
> _Safe_iterator(const _Safe_iterator& __x, _Unchecked) _GLIBCXX_NOEXCEPT
> : _Iter_base(__x.base()), _Safe_base()
> - { _M_attach(__x._M_sequence); }
> + {
> + if (!std::__is_constant_evaluated())
> + _M_attach(__x._M_sequence);
> + }
>
> public:
> typedef _Iterator iterator_type;
> @@ -148,6 +154,7 @@ namespace __gnu_debug
> #endif
>
> /// @post the iterator is singular and unattached
> + _GLIBCXX20_CONSTEXPR
> _Safe_iterator() _GLIBCXX_NOEXCEPT : _Iter_base() { }
>
> /**
> @@ -157,6 +164,7 @@ namespace __gnu_debug
> * @pre @p seq is not NULL
> * @post this is not singular
> */
> + _GLIBCXX20_CONSTEXPR
> _Safe_iterator(_Iterator __i, const _Safe_sequence_base* __seq)
> _GLIBCXX_NOEXCEPT
> : _Iter_base(__i), _Safe_base(__seq, _S_constant())
> @@ -165,9 +173,13 @@ namespace __gnu_debug
> /**
> * @brief Copy construction.
> */
> + _GLIBCXX20_CONSTEXPR
> _Safe_iterator(const _Safe_iterator& __x) _GLIBCXX_NOEXCEPT
> : _Iter_base(__x.base()), _Safe_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()
> @@ -183,9 +195,16 @@ namespace __gnu_debug
> * @brief Move construction.
> * @post __x is singular and unattached
> */
> + _GLIBCXX20_CONSTEXPR
> _Safe_iterator(_Safe_iterator&& __x) noexcept
> : _Iter_base()
> {
> + 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)
> @@ -203,6 +222,7 @@ namespace __gnu_debug
> * constant iterator.
> */
> template<typename _MutableIterator>
> + _GLIBCXX20_CONSTEXPR
> _Safe_iterator(
> const _Safe_iterator<_MutableIterator, _Sequence,
> typename __gnu_cxx::__enable_if<_IsConstant::__value &&
> @@ -211,6 +231,9 @@ namespace __gnu_debug
> _GLIBCXX_NOEXCEPT
> : _Iter_base(__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()
> @@ -224,9 +247,16 @@ namespace __gnu_debug
> /**
> * @brief Copy assignment.
> */
> + _GLIBCXX20_CONSTEXPR
> _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()
> @@ -256,9 +286,16 @@ namespace __gnu_debug
> * @brief Move assignment.
> * @post __x is singular and unattached
> */
> + _GLIBCXX20_CONSTEXPR
> _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)
> @@ -292,12 +329,16 @@ namespace __gnu_debug
> * @pre iterator is dereferenceable
> */
> _GLIBCXX_NODISCARD
> + _GLIBCXX20_CONSTEXPR
> reference
> operator*() const _GLIBCXX_NOEXCEPT
> {
> - _GLIBCXX_DEBUG_VERIFY(this->_M_dereferenceable(),
> - _M_message(__msg_bad_deref)
> - ._M_iterator(*this, "this"));
> + if (!std::__is_constant_evaluated())
> + {
> + _GLIBCXX_DEBUG_VERIFY(this->_M_dereferenceable(),
> + _M_message(__msg_bad_deref)
> + ._M_iterator(*this, "this"));
> + }
> return *base();
> }
>
> @@ -306,12 +347,16 @@ namespace __gnu_debug
> * @pre iterator is dereferenceable
> */
> _GLIBCXX_NODISCARD
> + _GLIBCXX20_CONSTEXPR
> pointer
> operator->() const _GLIBCXX_NOEXCEPT
> {
> - _GLIBCXX_DEBUG_VERIFY(this->_M_dereferenceable(),
> - _M_message(__msg_bad_deref)
> - ._M_iterator(*this, "this"));
> + if (!std::__is_constant_evaluated())
> + {
> + _GLIBCXX_DEBUG_VERIFY(this->_M_dereferenceable(),
> + _M_message(__msg_bad_deref)
> + ._M_iterator(*this, "this"));
> + }
> return base().operator->();
> }
>
> @@ -320,9 +365,16 @@ namespace __gnu_debug
> * @brief Iterator preincrement
> * @pre iterator is incrementable
> */
> + _GLIBCXX20_CONSTEXPR
> _Safe_iterator&
> operator++() _GLIBCXX_NOEXCEPT
> {
> + if (std::__is_constant_evaluated())
> + {
> + ++base();
> + return *this;
> + }
> +
> _GLIBCXX_DEBUG_VERIFY(this->_M_incrementable(),
> _M_message(__msg_bad_inc)
> ._M_iterator(*this, "this"));
> @@ -335,12 +387,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;
> @@ -356,9 +412,11 @@ namespace __gnu_debug
> /**
> * @brief Return the underlying iterator
> */
> + _GLIBCXX20_CONSTEXPR
> _Iterator&
> base() _GLIBCXX_NOEXCEPT { return *this; }
>
> + _GLIBCXX20_CONSTEXPR
> const _Iterator&
> base() const _GLIBCXX_NOEXCEPT { return *this; }
>
> @@ -366,6 +424,7 @@ namespace __gnu_debug
> * @brief Conversion to underlying non-debug iterator to allow
> * better interaction with non-debug containers.
> */
> + _GLIBCXX20_CONSTEXPR
> operator _Iterator() const _GLIBCXX_NOEXCEPT { return *this; }
>
> /** Attach iterator to the given sequence. */
> @@ -440,6 +499,7 @@ namespace __gnu_debug
> _M_get_distance_to_end() const;
>
> /// Is this iterator equal to the sequence's begin() iterator?
> + _GLIBCXX20_CONSTEXPR
> bool
> _M_is_begin() const
> { return base() == _M_get_sequence()->_M_base().begin(); }
> @@ -466,6 +526,7 @@ namespace __gnu_debug
> typedef _Safe_iterator<_Iterator, _Sequence, iterator_category> _Self;
>
> _GLIBCXX_NODISCARD
> + _GLIBCXX20_CONSTEXPR
> friend bool
> operator==(const _Self& __lhs, const _Self& __rhs) _GLIBCXX_NOEXCEPT
> {
> @@ -475,6 +536,7 @@ namespace __gnu_debug
>
> template<typename _IteR>
> _GLIBCXX_NODISCARD
> + _GLIBCXX20_CONSTEXPR
> friend bool
> operator==(const _Self& __lhs,
> const _Safe_iterator<_IteR, _Sequence, iterator_category>& __rhs)
> @@ -518,6 +580,7 @@ namespace __gnu_debug
>
> typedef typename _Safe_base::_Unchecked _Unchecked;
>
> + _GLIBCXX20_CONSTEXPR
> _Safe_iterator(const _Safe_iterator& __x,
> _Unchecked __unchecked) _GLIBCXX_NOEXCEPT
> : _Safe_base(__x, __unchecked)
> @@ -525,6 +588,7 @@ namespace __gnu_debug
>
> public:
> /// @post the iterator is singular and unattached
> + _GLIBCXX20_CONSTEXPR
> _Safe_iterator() _GLIBCXX_NOEXCEPT { }
>
> /**
> @@ -534,6 +598,7 @@ namespace __gnu_debug
> * @pre @p seq is not NULL
> * @post this is not singular
> */
> + _GLIBCXX20_CONSTEXPR
> _Safe_iterator(_Iterator __i, const _Safe_sequence_base* __seq)
> _GLIBCXX_NOEXCEPT
> : _Safe_base(__i, __seq)
> @@ -542,12 +607,14 @@ namespace __gnu_debug
> /**
> * @brief Copy construction.
> */
> + _GLIBCXX20_CONSTEXPR
> _Safe_iterator(const _Safe_iterator& __x) _GLIBCXX_NOEXCEPT
> : _Safe_base(__x)
> { }
>
> #if __cplusplus >= 201103L
> /** @brief Move construction. */
> + _GLIBCXX20_CONSTEXPR
> _Safe_iterator(_Safe_iterator&&) = default;
> #endif
>
> @@ -556,6 +623,7 @@ namespace __gnu_debug
> * constant iterator.
> */
> template<typename _MutableIterator>
> + _GLIBCXX20_CONSTEXPR
> _Safe_iterator(
> const _Safe_iterator<_MutableIterator, _Sequence,
> typename __gnu_cxx::__enable_if<_Safe_base::_IsConstant::__value &&
> @@ -588,6 +656,7 @@ namespace __gnu_debug
> * @brief Iterator preincrement
> * @pre iterator is incrementable
> */
> + _GLIBCXX20_CONSTEXPR
> _Safe_iterator&
> operator++() _GLIBCXX_NOEXCEPT
> {
> @@ -615,9 +684,16 @@ namespace __gnu_debug
> * @brief Iterator predecrement
> * @pre iterator is decrementable
> */
> + _GLIBCXX20_CONSTEXPR
> _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"));
> @@ -663,6 +739,8 @@ namespace __gnu_debug
> std::random_access_iterator_tag> _OtherSelf;
>
> typedef typename _Safe_base::_Unchecked _Unchecked;
> +
> + _GLIBCXX20_CONSTEXPR
> _Safe_iterator(const _Safe_iterator& __x,
> _Unchecked __unchecked) _GLIBCXX_NOEXCEPT
> : _Safe_base(__x, __unchecked)
> @@ -673,6 +751,7 @@ namespace __gnu_debug
> typedef typename _Safe_base::reference reference;
>
> /// @post the iterator is singular and unattached
> + _GLIBCXX20_CONSTEXPR
> _Safe_iterator() _GLIBCXX_NOEXCEPT { }
>
> /**
> @@ -682,6 +761,7 @@ namespace __gnu_debug
> * @pre @p seq is not NULL
> * @post this is not singular
> */
> + _GLIBCXX20_CONSTEXPR
> _Safe_iterator(_Iterator __i, const _Safe_sequence_base* __seq)
> _GLIBCXX_NOEXCEPT
> : _Safe_base(__i, __seq)
> @@ -690,6 +770,7 @@ namespace __gnu_debug
> /**
> * @brief Copy construction.
> */
> + _GLIBCXX20_CONSTEXPR
> _Safe_iterator(const _Safe_iterator& __x) _GLIBCXX_NOEXCEPT
> : _Safe_base(__x)
> { }
> @@ -704,6 +785,7 @@ namespace __gnu_debug
> * constant iterator.
> */
> template<typename _MutableIterator>
> + _GLIBCXX20_CONSTEXPR
> _Safe_iterator(
> const _Safe_iterator<_MutableIterator, _Sequence,
> typename __gnu_cxx::__enable_if<_Safe_base::_IsConstant::__value &&
> @@ -742,6 +824,7 @@ namespace __gnu_debug
> * @brief Iterator preincrement
> * @pre iterator is incrementable
> */
> + _GLIBCXX20_CONSTEXPR
> _Safe_iterator&
> operator++() _GLIBCXX_NOEXCEPT
> {
> @@ -753,12 +836,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;
> @@ -769,6 +856,7 @@ namespace __gnu_debug
> * @brief Iterator predecrement
> * @pre iterator is decrementable
> */
> + _GLIBCXX20_CONSTEXPR
> _Safe_iterator&
> operator--() _GLIBCXX_NOEXCEPT
> {
> @@ -780,12 +868,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;
> @@ -793,19 +885,30 @@ namespace __gnu_debug
>
> // ------ Random access iterator requirements ------
> _GLIBCXX_NODISCARD
> + _GLIBCXX20_CONSTEXPR
> reference
> operator[](difference_type __n) const _GLIBCXX_NOEXCEPT
> {
> - _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));
> + 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));
> + }
> return this->base()[__n];
> }
>
> + _GLIBCXX20_CONSTEXPR
> _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));
> @@ -814,9 +917,16 @@ namespace __gnu_debug
> return *this;
> }
>
> + _GLIBCXX20_CONSTEXPR
> _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));
> @@ -827,6 +937,7 @@ namespace __gnu_debug
>
> #if __cpp_lib_three_way_comparison
> [[nodiscard]]
> + _GLIBCXX20_CONSTEXPR
> friend auto
> operator<=>(const _Self& __lhs, const _Self& __rhs) noexcept
> {
> @@ -835,6 +946,7 @@ namespace __gnu_debug
> }
>
> [[nodiscard]]
> + _GLIBCXX20_CONSTEXPR
> friend auto
> operator<=>(const _Self& __lhs, const _OtherSelf& __rhs) noexcept
> {
> @@ -912,6 +1024,7 @@ namespace __gnu_debug
> // operators but also operator- must accept mixed iterator/const_iterator
> // parameters.
> _GLIBCXX_NODISCARD
> + _GLIBCXX20_CONSTEXPR
> friend difference_type
> operator-(const _Self& __lhs, const _OtherSelf& __rhs) _GLIBCXX_NOEXCEPT
> {
> @@ -920,6 +1033,7 @@ namespace __gnu_debug
> }
>
> _GLIBCXX_NODISCARD
> + _GLIBCXX20_CONSTEXPR
> friend difference_type
> operator-(const _Self& __lhs, const _Self& __rhs) _GLIBCXX_NOEXCEPT
> {
> @@ -928,32 +1042,44 @@ namespace __gnu_debug
> }
>
> _GLIBCXX_NODISCARD
> + _GLIBCXX20_CONSTEXPR
> friend _Self
> operator+(const _Self& __x, difference_type __n) _GLIBCXX_NOEXCEPT
> {
> - _GLIBCXX_DEBUG_VERIFY(__x._M_can_advance(__n),
> - _M_message(__msg_advance_oob)
> - ._M_iterator(__x)._M_integer(__n));
> + if (!std::__is_constant_evaluated())
> + {
> + _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);
> }
>
> _GLIBCXX_NODISCARD
> + _GLIBCXX20_CONSTEXPR
> friend _Self
> operator+(difference_type __n, const _Self& __x) _GLIBCXX_NOEXCEPT
> {
> - _GLIBCXX_DEBUG_VERIFY(__x._M_can_advance(__n),
> - _M_message(__msg_advance_oob)
> - ._M_iterator(__x)._M_integer(__n));
> + if (!std::__is_constant_evaluated())
> + {
> + _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);
> }
>
> _GLIBCXX_NODISCARD
> + _GLIBCXX20_CONSTEXPR
> friend _Self
> operator-(const _Self& __x, difference_type __n) _GLIBCXX_NOEXCEPT
> {
> - _GLIBCXX_DEBUG_VERIFY(__x._M_can_advance(-__n),
> - _M_message(__msg_retreat_oob)
> - ._M_iterator(__x)._M_integer(__n));
> + if (!std::__is_constant_evaluated())
> + {
> + _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);
> }
> };
> diff --git a/libstdc++-v3/include/debug/safe_iterator.tcc b/libstdc++-v3/include/debug/safe_iterator.tcc
> index 170229ad2f1..0bb3dd017b9 100644
> --- a/libstdc++-v3/include/debug/safe_iterator.tcc
> +++ b/libstdc++-v3/include/debug/safe_iterator.tcc
> @@ -236,6 +236,7 @@ namespace std _GLIBCXX_VISIBILITY(default)
> _GLIBCXX_BEGIN_NAMESPACE_VERSION
>
> template<typename _Ite, typename _Seq>
> + _GLIBCXX20_CONSTEXPR
> _Ite
> __niter_base(const ::__gnu_debug::_Safe_iterator<_Ite, _Seq,
> std::random_access_iterator_tag>& __it)
> @@ -243,6 +244,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>
> template<bool _IsMove,
> typename _Ite, typename _Seq, typename _Cat, typename _OI>
> + _GLIBCXX20_CONSTEXPR
> _OI
> __copy_move_a(
> const ::__gnu_debug::_Safe_iterator<_Ite, _Seq, _Cat>& __first,
> @@ -262,6 +264,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>
> template<bool _IsMove,
> typename _II, typename _Ite, typename _Seq, typename _Cat>
> + _GLIBCXX20_CONSTEXPR
> __gnu_debug::_Safe_iterator<_Ite, _Seq, _Cat>
> __copy_move_a(_II __first, _II __last,
> const ::__gnu_debug::_Safe_iterator<_Ite, _Seq, _Cat>& __result)
> @@ -282,6 +285,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> template<bool _IsMove,
> typename _IIte, typename _ISeq, typename _ICat,
> typename _OIte, typename _OSeq, typename _OCat>
> + _GLIBCXX20_CONSTEXPR
> ::__gnu_debug::_Safe_iterator<_OIte, _OSeq, _OCat>
> __copy_move_a(
> const ::__gnu_debug::_Safe_iterator<_IIte, _ISeq, _ICat>& __first,
> @@ -310,6 +314,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>
> template<bool _IsMove,
> typename _Ite, typename _Seq, typename _Cat, typename _OI>
> + _GLIBCXX20_CONSTEXPR
> _OI
> __copy_move_backward_a(
> const ::__gnu_debug::_Safe_iterator<_Ite, _Seq, _Cat>& __first,
> @@ -329,6 +334,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>
> template<bool _IsMove,
> typename _II, typename _Ite, typename _Seq, typename _Cat>
> + _GLIBCXX20_CONSTEXPR
> __gnu_debug::_Safe_iterator<_Ite, _Seq, _Cat>
> __copy_move_backward_a(_II __first, _II __last,
> const ::__gnu_debug::_Safe_iterator<_Ite, _Seq, _Cat>& __result)
> @@ -350,6 +356,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> template<bool _IsMove,
> typename _IIte, typename _ISeq, typename _ICat,
> typename _OIte, typename _OSeq, typename _OCat>
> + _GLIBCXX20_CONSTEXPR
> ::__gnu_debug::_Safe_iterator<_OIte, _OSeq, _OCat>
> __copy_move_backward_a(
> const ::__gnu_debug::_Safe_iterator<_IIte, _ISeq, _ICat>& __first,
> @@ -377,6 +384,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> }
>
> template<typename _Ite, typename _Seq, typename _Cat, typename _Tp>
> + _GLIBCXX20_CONSTEXPR
> void
> __fill_a(const ::__gnu_debug::_Safe_iterator<_Ite, _Seq, _Cat>& __first,
> const ::__gnu_debug::_Safe_iterator<_Ite, _Seq, _Cat>& __last,
> @@ -393,6 +401,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>
> template<typename _Ite, typename _Seq, typename _Cat, typename _Size,
> typename _Tp>
> + _GLIBCXX20_CONSTEXPR
> ::__gnu_debug::_Safe_iterator<_Ite, _Seq, _Cat>
> __fill_n_a(const ::__gnu_debug::_Safe_iterator<_Ite, _Seq, _Cat>& __first,
> _Size __n, const _Tp& __value,
> @@ -415,6 +424,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> }
>
> template<typename _II1, typename _Seq1, typename _Cat1, typename _II2>
> + _GLIBCXX20_CONSTEXPR
> bool
> __equal_aux(
> const ::__gnu_debug::_Safe_iterator<_II1, _Seq1, _Cat1>& __first1,
> @@ -432,6 +442,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> }
>
> template<typename _II1, typename _II2, typename _Seq2, typename _Cat2>
> + _GLIBCXX20_CONSTEXPR
> bool
> __equal_aux(_II1 __first1, _II1 __last1,
> const ::__gnu_debug::_Safe_iterator<_II2, _Seq2, _Cat2>& __first2)
> @@ -449,6 +460,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>
> template<typename _II1, typename _Seq1, typename _Cat1,
> typename _II2, typename _Seq2, typename _Cat2>
> + _GLIBCXX20_CONSTEXPR
> bool
> __equal_aux(
> const ::__gnu_debug::_Safe_iterator<_II1, _Seq1, _Cat1>& __first1,
> @@ -473,6 +485,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>
> template<typename _Ite1, typename _Seq1, typename _Cat1,
> typename _II2>
> + _GLIBCXX20_CONSTEXPR
> bool
> __lexicographical_compare_aux(
> const ::__gnu_debug::_Safe_iterator<_Ite1, _Seq1, _Cat1>& __first1,
> @@ -493,6 +506,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>
> template<typename _II1,
> typename _Ite2, typename _Seq2, typename _Cat2>
> + _GLIBCXX20_CONSTEXPR
> bool
> __lexicographical_compare_aux(
> _II1 __first1, _II1 __last1,
> @@ -513,6 +527,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>
> template<typename _Ite1, typename _Seq1, typename _Cat1,
> typename _Ite2, typename _Seq2, typename _Cat2>
> + _GLIBCXX20_CONSTEXPR
> bool
> __lexicographical_compare_aux(
> const ::__gnu_debug::_Safe_iterator<_Ite1, _Seq1, _Cat1>& __first1,
> diff --git a/libstdc++-v3/include/debug/vector b/libstdc++-v3/include/debug/vector
> index ed462caf936..124ae6da1c1 100644
> --- a/libstdc++-v3/include/debug/vector
> +++ b/libstdc++-v3/include/debug/vector
> @@ -55,22 +55,27 @@ namespace __gnu_debug
> {
> typedef typename _BaseSequence::size_type size_type;
>
> + _GLIBCXX20_CONSTEXPR
> const _SafeSequence&
> _M_seq() const { return *static_cast<const _SafeSequence*>(this); }
>
> protected:
> + _GLIBCXX20_CONSTEXPR
> _Safe_vector() _GLIBCXX_NOEXCEPT
> : _M_guaranteed_capacity(0)
> { _M_update_guaranteed_capacity(); }
>
> + _GLIBCXX20_CONSTEXPR
> _Safe_vector(const _Safe_vector&) _GLIBCXX_NOEXCEPT
> : _M_guaranteed_capacity(0)
> { _M_update_guaranteed_capacity(); }
>
> + _GLIBCXX20_CONSTEXPR
> _Safe_vector(size_type __n) _GLIBCXX_NOEXCEPT
> : _M_guaranteed_capacity(__n)
> { }
>
> + _GLIBCXX20_CONSTEXPR
> _Safe_vector&
> operator=(const _Safe_vector&) _GLIBCXX_NOEXCEPT
> {
> @@ -79,10 +84,12 @@ namespace __gnu_debug
> }
>
> #if __cplusplus >= 201103L
> + _GLIBCXX20_CONSTEXPR
> _Safe_vector(_Safe_vector&& __x) noexcept
> : _Safe_vector()
> { __x._M_guaranteed_capacity = 0; }
>
> + _GLIBCXX20_CONSTEXPR
> _Safe_vector&
> operator=(_Safe_vector&& __x) noexcept
> {
> @@ -98,6 +105,7 @@ namespace __gnu_debug
> _M_requires_reallocation(size_type __elements) const _GLIBCXX_NOEXCEPT
> { return __elements > _M_seq().capacity(); }
>
> + _GLIBCXX20_CONSTEXPR
> void
> _M_update_guaranteed_capacity() _GLIBCXX_NOEXCEPT
> {
> @@ -172,15 +180,18 @@ namespace __debug
> vector() = default;
> #endif
>
> + _GLIBCXX20_CONSTEXPR
> explicit
> vector(const _Allocator& __a) _GLIBCXX_NOEXCEPT
> : _Base(__a) { }
>
> #if __cplusplus >= 201103L
> + _GLIBCXX20_CONSTEXPR
> explicit
> vector(size_type __n, const _Allocator& __a = _Allocator())
> : _Base(__n, __a), _Safe_vector(__n) { }
>
> + _GLIBCXX20_CONSTEXPR
> vector(size_type __n, const __type_identity_t<_Tp>& __value,
> const _Allocator& __a = _Allocator())
> : _Base(__n, __value, __a) { }
> @@ -197,10 +208,11 @@ namespace __debug
> #else
> template<class _InputIterator>
> #endif
> + _GLIBCXX20_CONSTEXPR
> vector(_InputIterator __first, _InputIterator __last,
> const _Allocator& __a = _Allocator())
> - : _Base(__gnu_debug::__base(
> - __glibcxx_check_valid_constructor_range(__first, __last)),
> + : _Base(__gnu_debug::__base(std::__is_constant_evaluated() ? __first
> + : __glibcxx_check_valid_constructor_range(__first, __last)),
> __gnu_debug::__base(__last), __a) { }
>
> #if __cplusplus < 201103L
> @@ -212,9 +224,11 @@ namespace __debug
> vector(const vector&) = default;
> vector(vector&&) = default;
>
> + _GLIBCXX20_CONSTEXPR
> vector(const vector& __x, const __type_identity_t<allocator_type>& __a)
> : _Base(__x, __a) { }
>
> + _GLIBCXX20_CONSTEXPR
> vector(vector&& __x, const __type_identity_t<allocator_type>& __a)
> noexcept(
> std::is_nothrow_constructible<_Base,
> @@ -223,6 +237,7 @@ namespace __debug
> _Base(std::move(__x), __a),
> _Safe_vector(std::move(__x)) { }
>
> + _GLIBCXX20_CONSTEXPR
> vector(initializer_list<value_type> __l,
> const allocator_type& __a = allocator_type())
> : _Base(__l, __a) { }
> @@ -231,6 +246,7 @@ namespace __debug
> #endif
>
> /// Construction from a normal-mode vector
> + _GLIBCXX20_CONSTEXPR
> vector(_Base_ref __x)
> : _Base(__x._M_ref) { }
>
> @@ -241,12 +257,16 @@ namespace __debug
> vector&
> operator=(vector&&) = default;
>
> + _GLIBCXX20_CONSTEXPR
> vector&
> operator=(initializer_list<value_type> __l)
> {
> _Base::operator=(__l);
> - this->_M_invalidate_all();
> - this->_M_update_guaranteed_capacity();
> + if (!std::__is_constant_evaluated())
> + {
> + this->_M_invalidate_all();
> + this->_M_update_guaranteed_capacity();
> + }
> return *this;
> }
> #endif
> @@ -257,9 +277,14 @@ namespace __debug
> #else
> template<typename _InputIterator>
> #endif
> + _GLIBCXX20_CONSTEXPR
> 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);
>
> @@ -273,21 +298,29 @@ namespace __debug
> this->_M_update_guaranteed_capacity();
> }
>
> + _GLIBCXX20_CONSTEXPR
> void
> assign(size_type __n, const _Tp& __u)
> {
> _Base::assign(__n, __u);
> - this->_M_invalidate_all();
> - this->_M_update_guaranteed_capacity();
> + if (!std::__is_constant_evaluated())
> + {
> + this->_M_invalidate_all();
> + this->_M_update_guaranteed_capacity();
> + }
> }
>
> #if __cplusplus >= 201103L
> + _GLIBCXX20_CONSTEXPR
> void
> assign(initializer_list<value_type> __l)
> {
> _Base::assign(__l);
> - this->_M_invalidate_all();
> - this->_M_update_guaranteed_capacity();
> + if (!std::__is_constant_evaluated())
> + {
> + this->_M_invalidate_all();
> + this->_M_update_guaranteed_capacity();
> + }
> }
> #endif
>
> @@ -295,62 +328,74 @@ namespace __debug
>
> // iterators:
> _GLIBCXX_NODISCARD
> + _GLIBCXX20_CONSTEXPR
> iterator
> begin() _GLIBCXX_NOEXCEPT
> { return iterator(_Base::begin(), this); }
>
> _GLIBCXX_NODISCARD
> + _GLIBCXX20_CONSTEXPR
> const_iterator
> begin() const _GLIBCXX_NOEXCEPT
> { return const_iterator(_Base::begin(), this); }
>
> _GLIBCXX_NODISCARD
> + _GLIBCXX20_CONSTEXPR
> iterator
> end() _GLIBCXX_NOEXCEPT
> { return iterator(_Base::end(), this); }
>
> _GLIBCXX_NODISCARD
> + _GLIBCXX20_CONSTEXPR
> const_iterator
> end() const _GLIBCXX_NOEXCEPT
> { return const_iterator(_Base::end(), this); }
>
> _GLIBCXX_NODISCARD
> + _GLIBCXX20_CONSTEXPR
> reverse_iterator
> rbegin() _GLIBCXX_NOEXCEPT
> { return reverse_iterator(end()); }
>
> _GLIBCXX_NODISCARD
> + _GLIBCXX20_CONSTEXPR
> const_reverse_iterator
> rbegin() const _GLIBCXX_NOEXCEPT
> { return const_reverse_iterator(end()); }
>
> _GLIBCXX_NODISCARD
> + _GLIBCXX20_CONSTEXPR
> reverse_iterator
> rend() _GLIBCXX_NOEXCEPT
> { return reverse_iterator(begin()); }
>
> _GLIBCXX_NODISCARD
> + _GLIBCXX20_CONSTEXPR
> const_reverse_iterator
> rend() const _GLIBCXX_NOEXCEPT
> { return const_reverse_iterator(begin()); }
>
> #if __cplusplus >= 201103L
> [[__nodiscard__]]
> + _GLIBCXX20_CONSTEXPR
> const_iterator
> cbegin() const noexcept
> { return const_iterator(_Base::begin(), this); }
>
> [[__nodiscard__]]
> + _GLIBCXX20_CONSTEXPR
> const_iterator
> cend() const noexcept
> { return const_iterator(_Base::end(), this); }
>
> [[__nodiscard__]]
> + _GLIBCXX20_CONSTEXPR
> const_reverse_iterator
> crbegin() const noexcept
> { return const_reverse_iterator(end()); }
>
> [[__nodiscard__]]
> + _GLIBCXX20_CONSTEXPR
> const_reverse_iterator
> crend() const noexcept
> { return const_reverse_iterator(begin()); }
> @@ -361,9 +406,13 @@ namespace __debug
> using _Base::max_size;
>
> #if __cplusplus >= 201103L
> + _GLIBCXX20_CONSTEXPR
> 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);
> @@ -373,9 +422,13 @@ namespace __debug
> this->_M_update_guaranteed_capacity();
> }
>
> + _GLIBCXX20_CONSTEXPR
> 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);
> @@ -399,9 +452,13 @@ namespace __debug
> #endif
>
> #if __cplusplus >= 201103L
> + _GLIBCXX20_CONSTEXPR
> 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();
> @@ -411,9 +468,13 @@ namespace __debug
> #endif
>
> _GLIBCXX_NODISCARD
> + _GLIBCXX20_CONSTEXPR
> size_type
> capacity() const _GLIBCXX_NOEXCEPT
> {
> + if (std::__is_constant_evaluated())
> + return _Base::capacity();
> +
> #ifdef _GLIBCXX_DEBUG_PEDANTIC
> return this->_M_guaranteed_capacity;
> #else
> @@ -423,9 +484,13 @@ namespace __debug
>
> using _Base::empty;
>
> + _GLIBCXX20_CONSTEXPR
> 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)
> @@ -436,6 +501,7 @@ namespace __debug
>
> // element access:
> _GLIBCXX_NODISCARD
> + _GLIBCXX20_CONSTEXPR
> reference
> operator[](size_type __n) _GLIBCXX_NOEXCEPT
> {
> @@ -444,6 +510,7 @@ namespace __debug
> }
>
> _GLIBCXX_NODISCARD
> + _GLIBCXX20_CONSTEXPR
> const_reference
> operator[](size_type __n) const _GLIBCXX_NOEXCEPT
> {
> @@ -454,6 +521,7 @@ namespace __debug
> using _Base::at;
>
> _GLIBCXX_NODISCARD
> + _GLIBCXX20_CONSTEXPR
> reference
> front() _GLIBCXX_NOEXCEPT
> {
> @@ -462,6 +530,7 @@ namespace __debug
> }
>
> _GLIBCXX_NODISCARD
> + _GLIBCXX20_CONSTEXPR
> const_reference
> front() const _GLIBCXX_NOEXCEPT
> {
> @@ -470,6 +539,7 @@ namespace __debug
> }
>
> _GLIBCXX_NODISCARD
> + _GLIBCXX20_CONSTEXPR
> reference
> back() _GLIBCXX_NOEXCEPT
> {
> @@ -478,6 +548,7 @@ namespace __debug
> }
>
> _GLIBCXX_NODISCARD
> + _GLIBCXX20_CONSTEXPR
> const_reference
> back() const _GLIBCXX_NOEXCEPT
> {
> @@ -490,9 +561,13 @@ namespace __debug
> using _Base::data;
>
> // 23.2.4.3 modifiers:
> + _GLIBCXX20_CONSTEXPR
> 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)
> @@ -502,12 +577,14 @@ namespace __debug
>
> #if __cplusplus >= 201103L
> template<typename _Up = _Tp>
> + _GLIBCXX20_CONSTEXPR
> typename __gnu_cxx::__enable_if<!std::__are_same<_Up, bool>::__value,
> void>::__type
> push_back(_Tp&& __x)
> { emplace_back(std::move(__x)); }
>
> template<typename... _Args>
> + _GLIBCXX20_CONSTEXPR
> #if __cplusplus > 201402L
> reference
> #else
> @@ -515,6 +592,9 @@ 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)
> @@ -526,19 +606,29 @@ namespace __debug
> }
> #endif
>
> + _GLIBCXX20_CONSTEXPR
> void
> pop_back() _GLIBCXX_NOEXCEPT
> {
> - __glibcxx_check_nonempty();
> - this->_M_invalidate_if(_Equal(--_Base::end()));
> + if (!std::__is_constant_evaluated())
> + {
> + __glibcxx_check_nonempty();
> + this->_M_invalidate_if(_Equal(--_Base::end()));
> + }
> _Base::pop_back();
> }
>
> #if __cplusplus >= 201103L
> template<typename... _Args>
> + _GLIBCXX20_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);
> bool __realloc = this->_M_requires_reallocation(this->size() + 1);
> difference_type __offset = __position.base() - _Base::cbegin();
> @@ -553,6 +643,7 @@ namespace __debug
> }
> #endif
>
> + _GLIBCXX20_CONSTEXPR
> iterator
> #if __cplusplus >= 201103L
> insert(const_iterator __position, const _Tp& __x)
> @@ -560,6 +651,9 @@ 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();
> @@ -574,20 +668,26 @@ namespace __debug
>
> #if __cplusplus >= 201103L
> template<typename _Up = _Tp>
> + _GLIBCXX20_CONSTEXPR
> typename __gnu_cxx::__enable_if<!std::__are_same<_Up, bool>::__value,
> iterator>::__type
> insert(const_iterator __position, _Tp&& __x)
> { return emplace(__position, std::move(__x)); }
>
> + _GLIBCXX20_CONSTEXPR
> iterator
> insert(const_iterator __position, initializer_list<value_type> __l)
> { return this->insert(__position, __l.begin(), __l.end()); }
> #endif
>
> #if __cplusplus >= 201103L
> + _GLIBCXX20_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);
> bool __realloc = this->_M_requires_reallocation(this->size() + __n);
> difference_type __offset = __position.base() - _Base::cbegin();
> @@ -618,10 +718,16 @@ namespace __debug
> #if __cplusplus >= 201103L
> template<class _InputIterator,
> typename = std::_RequireInputIter<_InputIterator>>
> + _GLIBCXX20_CONSTEXPR
> iterator
> 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);
>
> @@ -673,6 +779,7 @@ namespace __debug
> }
> #endif
>
> + _GLIBCXX20_CONSTEXPR
> iterator
> #if __cplusplus >= 201103L
> erase(const_iterator __position)
> @@ -680,6 +787,9 @@ 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());
> @@ -687,6 +797,7 @@ namespace __debug
> return iterator(__res, this);
> }
>
> + _GLIBCXX20_CONSTEXPR
> iterator
> #if __cplusplus >= 201103L
> erase(const_iterator __first, const_iterator __last)
> @@ -694,6 +805,9 @@ 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);
> @@ -714,25 +828,31 @@ namespace __debug
> #endif
> }
>
> + _GLIBCXX20_CONSTEXPR
> void
> swap(vector& __x)
> _GLIBCXX_NOEXCEPT_IF( noexcept(declval<_Base&>().swap(__x)) )
> {
> - _Safe::_M_swap(__x);
> + if (!std::__is_constant_evaluated())
> + _Safe::_M_swap(__x);
> _Base::swap(__x);
> std::swap(this->_M_guaranteed_capacity, __x._M_guaranteed_capacity);
> }
>
> + _GLIBCXX20_CONSTEXPR
> void
> clear() _GLIBCXX_NOEXCEPT
> {
> _Base::clear();
> - this->_M_invalidate_all();
> + if (!std::__is_constant_evaluated())
> + this->_M_invalidate_all();
> }
>
> + _GLIBCXX20_CONSTEXPR
> _Base&
> _M_base() _GLIBCXX_NOEXCEPT { return *this; }
>
> + _GLIBCXX20_CONSTEXPR
> const _Base&
> _M_base() const _GLIBCXX_NOEXCEPT { return *this; }
>
> @@ -746,6 +866,7 @@ namespace __debug
> };
>
> template<typename _Tp, typename _Alloc>
> + _GLIBCXX20_CONSTEXPR
> inline bool
> operator==(const vector<_Tp, _Alloc>& __lhs,
> const vector<_Tp, _Alloc>& __rhs)
> @@ -789,6 +910,7 @@ namespace __debug
> #endif // three-way comparison
>
> template<typename _Tp, typename _Alloc>
> + _GLIBCXX20_CONSTEXPR
> inline void
> swap(vector<_Tp, _Alloc>& __lhs, vector<_Tp, _Alloc>& __rhs)
> _GLIBCXX_NOEXCEPT_IF(noexcept(__lhs.swap(__rhs)))
> diff --git a/libstdc++-v3/testsuite/23_containers/vector/bool/capacity/constexpr.cc b/libstdc++-v3/testsuite/23_containers/vector/bool/capacity/constexpr.cc
> index d44e9d97b46..534128c487e 100644
> --- a/libstdc++-v3/testsuite/23_containers/vector/bool/capacity/constexpr.cc
> +++ b/libstdc++-v3/testsuite/23_containers/vector/bool/capacity/constexpr.cc
> @@ -1,5 +1,4 @@
> // { dg-do compile { target c++20 } }
> -// { dg-xfail-if "not supported" { debug_mode } }
>
> #include <vector>
> #include <testsuite_hooks.h>
> diff --git a/libstdc++-v3/testsuite/23_containers/vector/bool/cmp_c++20.cc b/libstdc++-v3/testsuite/23_containers/vector/bool/cmp_c++20.cc
> index 66197e0aa29..e852c388903 100644
> --- a/libstdc++-v3/testsuite/23_containers/vector/bool/cmp_c++20.cc
> +++ b/libstdc++-v3/testsuite/23_containers/vector/bool/cmp_c++20.cc
> @@ -16,7 +16,6 @@
> // <http://www.gnu.org/licenses/>.
>
> // { dg-do compile { target c++20 } }
> -// { dg-xfail-if "not supported" { debug_mode } }
>
> #include <vector>
> #include <testsuite_hooks.h>
> diff --git a/libstdc++-v3/testsuite/23_containers/vector/bool/cons/constexpr.cc b/libstdc++-v3/testsuite/23_containers/vector/bool/cons/constexpr.cc
> index 0e0c1e1c5ec..88d99fe682f 100644
> --- a/libstdc++-v3/testsuite/23_containers/vector/bool/cons/constexpr.cc
> +++ b/libstdc++-v3/testsuite/23_containers/vector/bool/cons/constexpr.cc
> @@ -1,5 +1,4 @@
> // { dg-do compile { target c++20 } }
> -// { dg-xfail-if "not supported" { debug_mode } }
>
> #include <vector>
> #include <testsuite_hooks.h>
> diff --git a/libstdc++-v3/testsuite/23_containers/vector/bool/element_access/1.cc b/libstdc++-v3/testsuite/23_containers/vector/bool/element_access/1.cc
> index 2a430845058..e7d710829e1 100644
> --- a/libstdc++-v3/testsuite/23_containers/vector/bool/element_access/1.cc
> +++ b/libstdc++-v3/testsuite/23_containers/vector/bool/element_access/1.cc
> @@ -1,5 +1,4 @@
> // { dg-do compile { target c++23 } }
> -// { dg-xfail-if "not supported" { debug_mode } }
>
> #include <vector>
> #include <testsuite_hooks.h>
> diff --git a/libstdc++-v3/testsuite/23_containers/vector/bool/element_access/constexpr.cc b/libstdc++-v3/testsuite/23_containers/vector/bool/element_access/constexpr.cc
> index 5b8ca94e78f..d6b657e0161 100644
> --- a/libstdc++-v3/testsuite/23_containers/vector/bool/element_access/constexpr.cc
> +++ b/libstdc++-v3/testsuite/23_containers/vector/bool/element_access/constexpr.cc
> @@ -1,5 +1,4 @@
> // { dg-do compile { target c++20 } }
> -// { dg-xfail-if "not supported" { debug_mode } }
>
> #include <vector>
> #include <testsuite_hooks.h>
> diff --git a/libstdc++-v3/testsuite/23_containers/vector/bool/modifiers/assign/constexpr.cc b/libstdc++-v3/testsuite/23_containers/vector/bool/modifiers/assign/constexpr.cc
> index 3ad7dda88a9..31a6793f7ff 100644
> --- a/libstdc++-v3/testsuite/23_containers/vector/bool/modifiers/assign/constexpr.cc
> +++ b/libstdc++-v3/testsuite/23_containers/vector/bool/modifiers/assign/constexpr.cc
> @@ -1,5 +1,4 @@
> // { dg-do compile { target c++20 } }
> -// { dg-xfail-if "not supported" { debug_mode } }
>
> #include <vector>
> #include <testsuite_hooks.h>
> diff --git a/libstdc++-v3/testsuite/23_containers/vector/bool/modifiers/constexpr.cc b/libstdc++-v3/testsuite/23_containers/vector/bool/modifiers/constexpr.cc
> index 22a4df5e370..0e37f9aa786 100644
> --- a/libstdc++-v3/testsuite/23_containers/vector/bool/modifiers/constexpr.cc
> +++ b/libstdc++-v3/testsuite/23_containers/vector/bool/modifiers/constexpr.cc
> @@ -1,5 +1,4 @@
> // { dg-do compile { target c++20 } }
> -// { dg-xfail-if "not supported" { debug_mode } }
>
> #include <vector>
> #include <testsuite_hooks.h>
> diff --git a/libstdc++-v3/testsuite/23_containers/vector/bool/modifiers/swap/constexpr.cc b/libstdc++-v3/testsuite/23_containers/vector/bool/modifiers/swap/constexpr.cc
> index 624ff96a9e9..d2a0218a109 100644
> --- a/libstdc++-v3/testsuite/23_containers/vector/bool/modifiers/swap/constexpr.cc
> +++ b/libstdc++-v3/testsuite/23_containers/vector/bool/modifiers/swap/constexpr.cc
> @@ -1,5 +1,4 @@
> // { dg-do compile { target c++20 } }
> -// { dg-xfail-if "not supported" { debug_mode } }
>
> #include <vector>
> #include <utility>
> @@ -49,6 +48,7 @@ test_member_swap()
>
> static_assert(test_member_swap());
>
> +#ifndef _GLIBCXX_DEBUG
> constexpr bool
> test_reference_swap()
> {
> @@ -63,3 +63,4 @@ test_reference_swap()
> }
>
> static_assert(test_reference_swap());
> +#endif
> diff --git a/libstdc++-v3/testsuite/23_containers/vector/capacity/constexpr.cc b/libstdc++-v3/testsuite/23_containers/vector/capacity/constexpr.cc
> index 018a4792891..c331dbd5e57 100644
> --- a/libstdc++-v3/testsuite/23_containers/vector/capacity/constexpr.cc
> +++ b/libstdc++-v3/testsuite/23_containers/vector/capacity/constexpr.cc
> @@ -1,5 +1,4 @@
> // { dg-do compile { target c++20 } }
> -// { dg-xfail-if "not supported" { debug_mode } }
>
> #include <vector>
> #include <testsuite_hooks.h>
> diff --git a/libstdc++-v3/testsuite/23_containers/vector/cmp_c++20.cc b/libstdc++-v3/testsuite/23_containers/vector/cmp_c++20.cc
> index 72c5c6cd7f9..63cb92c0edf 100644
> --- a/libstdc++-v3/testsuite/23_containers/vector/cmp_c++20.cc
> +++ b/libstdc++-v3/testsuite/23_containers/vector/cmp_c++20.cc
> @@ -16,7 +16,6 @@
> // <http://www.gnu.org/licenses/>.
>
> // { dg-do compile { target c++20 } }
> -// { dg-xfail-if "not supported" { debug_mode } }
>
> #include <vector>
> #include <testsuite_hooks.h>
> diff --git a/libstdc++-v3/testsuite/23_containers/vector/cons/constexpr.cc b/libstdc++-v3/testsuite/23_containers/vector/cons/constexpr.cc
> index 7bf86511240..fa78676b300 100644
> --- a/libstdc++-v3/testsuite/23_containers/vector/cons/constexpr.cc
> +++ b/libstdc++-v3/testsuite/23_containers/vector/cons/constexpr.cc
> @@ -1,6 +1,5 @@
> // { dg-do compile { target c++20 } }
> // { dg-add-options no_pch }
> -// { dg-xfail-if "not supported" { debug_mode } }
>
> #include <vector>
>
> diff --git a/libstdc++-v3/testsuite/23_containers/vector/data_access/constexpr.cc b/libstdc++-v3/testsuite/23_containers/vector/data_access/constexpr.cc
> index f5b601a44f4..142050e8f03 100644
> --- a/libstdc++-v3/testsuite/23_containers/vector/data_access/constexpr.cc
> +++ b/libstdc++-v3/testsuite/23_containers/vector/data_access/constexpr.cc
> @@ -1,5 +1,4 @@
> // { dg-do compile { target c++20 } }
> -// { dg-xfail-if "not supported" { debug_mode } }
>
> #include <vector>
> #include <testsuite_hooks.h>
> diff --git a/libstdc++-v3/testsuite/23_containers/vector/element_access/constexpr.cc b/libstdc++-v3/testsuite/23_containers/vector/element_access/constexpr.cc
> index 60c66dcc647..ee93d2fd95e 100644
> --- a/libstdc++-v3/testsuite/23_containers/vector/element_access/constexpr.cc
> +++ b/libstdc++-v3/testsuite/23_containers/vector/element_access/constexpr.cc
> @@ -1,5 +1,4 @@
> // { dg-do compile { target c++20 } }
> -// { dg-xfail-if "not supported" { debug_mode } }
>
> #include <vector>
> #include <testsuite_hooks.h>
> diff --git a/libstdc++-v3/testsuite/23_containers/vector/modifiers/assign/constexpr.cc b/libstdc++-v3/testsuite/23_containers/vector/modifiers/assign/constexpr.cc
> index cca20f4291c..41fc8d9696e 100644
> --- a/libstdc++-v3/testsuite/23_containers/vector/modifiers/assign/constexpr.cc
> +++ b/libstdc++-v3/testsuite/23_containers/vector/modifiers/assign/constexpr.cc
> @@ -1,5 +1,4 @@
> // { dg-do compile { target c++20 } }
> -// { dg-xfail-if "not supported" { debug_mode } }
>
> #include <vector>
> #include <testsuite_hooks.h>
> diff --git a/libstdc++-v3/testsuite/23_containers/vector/modifiers/constexpr.cc b/libstdc++-v3/testsuite/23_containers/vector/modifiers/constexpr.cc
> index 766e3a7690f..4aa1f1f67b7 100644
> --- a/libstdc++-v3/testsuite/23_containers/vector/modifiers/constexpr.cc
> +++ b/libstdc++-v3/testsuite/23_containers/vector/modifiers/constexpr.cc
> @@ -1,5 +1,4 @@
> // { dg-do compile { target c++20 } }
> -// { dg-xfail-if "not supported" { debug_mode } }
>
> #include <vector>
> #include <testsuite_hooks.h>
> diff --git a/libstdc++-v3/testsuite/23_containers/vector/modifiers/swap/constexpr.cc b/libstdc++-v3/testsuite/23_containers/vector/modifiers/swap/constexpr.cc
> index 45b3986beca..77d2a518d69 100644
> --- a/libstdc++-v3/testsuite/23_containers/vector/modifiers/swap/constexpr.cc
> +++ b/libstdc++-v3/testsuite/23_containers/vector/modifiers/swap/constexpr.cc
> @@ -1,5 +1,4 @@
> // { dg-do compile { target c++20 } }
> -// { dg-xfail-if "not supported" { debug_mode } }
>
> #include <vector>
> #include <utility>
> --
> 2.43.0
>
>
On Sat, 16 Dec 2023 at 00:27, Patrick Palka wrote:
>
> On Wed, 6 Dec 2023, Jonathan Wakely wrote:
>
> > Any comments on this approach?
> >
> > -- >8 --
> >
> > This makes constexpr std::vector (mostly) work in Debug Mode. All safe
> > iterator instrumentation and checking is disabled during constant
> > evaluation, because it requires mutex locks and calls to non-inline
> > functions defined in libstdc++.so. It should be OK to disable the safety
> > checks, because most UB should be detected during constant evaluation
> > anyway.
> >
> > We could try to enable the full checking in constexpr, but it would mean
> > wrapping all the non-inline functions like _M_attach with an inline
> > _M_constexpr_attach that does the iterator housekeeping inline without
> > mutex locks when calling for constant evaluation, and calls the
> > non-inline function at runtime. That could be done in future if we find
> > that we've lost safety or useful checking by disabling the safe
> > iterators.
> >
> > There are a few test failures in C++20 mode, which I'm unable to
> > explain. The _Safe_iterator::operator++() member gives errors for using
> > non-constexpr functions during constant evaluation, even though those
> > functions are guarded by std::is_constant_evaluated() checks. The same
> > code works fine for C++23 and up.
>
> AFAICT these C++20 test failures are really due to the variable
> definition of non-literal type
>
> 381 __gnu_cxx::__scoped_lock __l(this->_M_get_mutex());
>
> which were prohibited in a constexpr function (even if that code was
> never executed) until C++23's P2242R3.
Ah, I figured it was a core change but I couldn't recall which one. Thanks.
> We can use an immediately invoked lambda to work around this:
>
> 381 [this] {
> 382 __gnu_cxx::__scoped_lock __l(this->_M_get_mutex());
> 383 ++base();
> 384 }();
> 385 return *this;
We'd need some #if as this code has to work for C++98. But that's doable.
> >
> > libstdc++-v3/ChangeLog:
> >
> > PR libstdc++/109536
> > * include/bits/c++config (__glibcxx_constexpr_assert): Remove
> > macro.
> > * include/bits/stl_algobase.h (__niter_base, __copy_move_a)
> > (__copy_move_backward_a, __fill_a, __fill_n_a, __equal_aux)
> > (__lexicographical_compare_aux): Add constexpr to overloads for
> > debug mode iterators.
> > * include/debug/helper_functions.h (__unsafe): Add constexpr.
> > * include/debug/macros.h (_GLIBCXX_DEBUG_VERIFY_COND_AT): Remove
> > macro, folding it into ...
> > (_GLIBCXX_DEBUG_VERIFY_AT_F): ... here. Do not use
> > __glibcxx_constexpr_assert.
> > * include/debug/safe_base.h (_Safe_iterator_base): Add constexpr
> > to some member functions. Omit attaching, detaching and checking
> > operations during constant evaluation.
> > * include/debug/safe_container.h (_Safe_container): Likewise.
> > * include/debug/safe_iterator.h (_Safe_iterator): Likewise.
> > * include/debug/safe_iterator.tcc (__niter_base, __copy_move_a)
> > (__copy_move_backward_a, __fill_a, __fill_n_a, __equal_aux)
> > (__lexicographical_compare_aux): Add constexpr.
> > * include/debug/vector (_Safe_vector, vector): Add constexpr.
> > Omit safe iterator operations during constant evaluation.
> > * testsuite/23_containers/vector/bool/capacity/constexpr.cc:
> > Remove dg-xfail-if for debug mode.
> > * testsuite/23_containers/vector/bool/cmp_c++20.cc: Likewise.
> > * testsuite/23_containers/vector/bool/cons/constexpr.cc:
> > Likewise.
> > * testsuite/23_containers/vector/bool/element_access/1.cc:
> > Likewise.
> > * testsuite/23_containers/vector/bool/element_access/constexpr.cc:
> > Likewise.
> > * testsuite/23_containers/vector/bool/modifiers/assign/constexpr.cc:
> > Likewise.
> > * testsuite/23_containers/vector/bool/modifiers/constexpr.cc:
> > Likewise.
> > * testsuite/23_containers/vector/bool/modifiers/swap/constexpr.cc:
> > Likewise.
> > * testsuite/23_containers/vector/capacity/constexpr.cc:
> > Likewise.
> > * testsuite/23_containers/vector/cmp_c++20.cc: Likewise.
> > * testsuite/23_containers/vector/cons/constexpr.cc: Likewise.
> > * testsuite/23_containers/vector/data_access/constexpr.cc:
> > Likewise.
> > * testsuite/23_containers/vector/element_access/constexpr.cc:
> > Likewise.
> > * testsuite/23_containers/vector/modifiers/assign/constexpr.cc:
> > Likewise.
> > * testsuite/23_containers/vector/modifiers/constexpr.cc:
> > Likewise.
> > * testsuite/23_containers/vector/modifiers/swap/constexpr.cc:
> > Likewise.
> > ---
> > libstdc++-v3/include/bits/c++config | 9 -
> > libstdc++-v3/include/bits/stl_algobase.h | 15 ++
> > libstdc++-v3/include/debug/helper_functions.h | 1 +
> > libstdc++-v3/include/debug/macros.h | 9 +-
> > libstdc++-v3/include/debug/safe_base.h | 35 +++-
> > libstdc++-v3/include/debug/safe_container.h | 15 +-
> > libstdc++-v3/include/debug/safe_iterator.h | 186 +++++++++++++++---
> > libstdc++-v3/include/debug/safe_iterator.tcc | 15 ++
> > libstdc++-v3/include/debug/vector | 146 ++++++++++++--
> > .../vector/bool/capacity/constexpr.cc | 1 -
> > .../23_containers/vector/bool/cmp_c++20.cc | 1 -
> > .../vector/bool/cons/constexpr.cc | 1 -
> > .../vector/bool/element_access/1.cc | 1 -
> > .../vector/bool/element_access/constexpr.cc | 1 -
> > .../vector/bool/modifiers/assign/constexpr.cc | 1 -
> > .../vector/bool/modifiers/constexpr.cc | 1 -
> > .../vector/bool/modifiers/swap/constexpr.cc | 3 +-
> > .../vector/capacity/constexpr.cc | 1 -
> > .../23_containers/vector/cmp_c++20.cc | 1 -
> > .../23_containers/vector/cons/constexpr.cc | 1 -
> > .../vector/data_access/constexpr.cc | 1 -
> > .../vector/element_access/constexpr.cc | 1 -
> > .../vector/modifiers/assign/constexpr.cc | 1 -
> > .../vector/modifiers/constexpr.cc | 1 -
> > .../vector/modifiers/swap/constexpr.cc | 1 -
> > 25 files changed, 369 insertions(+), 80 deletions(-)
> >
> > diff --git a/libstdc++-v3/include/bits/c++config b/libstdc++-v3/include/bits/c++config
> > index 284d24d933f..13d416845c3 100644
> > --- a/libstdc++-v3/include/bits/c++config
> > +++ b/libstdc++-v3/include/bits/c++config
> > @@ -565,15 +565,6 @@ namespace std
> > # define _GLIBCXX_EXTERN_TEMPLATE -1
> > #endif
> >
> > -
> > -#if _GLIBCXX_HAVE_IS_CONSTANT_EVALUATED
> > -# define __glibcxx_constexpr_assert(cond) \
> > - if (std::__is_constant_evaluated() && !bool(cond)) \
> > - __builtin_unreachable() /* precondition violation detected! */
> > -#else
> > -# define __glibcxx_constexpr_assert(unevaluated)
> > -#endif
> > -
> > #undef _GLIBCXX_VERBOSE_ASSERT
> >
> > // Assert.
> > diff --git a/libstdc++-v3/include/bits/stl_algobase.h b/libstdc++-v3/include/bits/stl_algobase.h
> > index 01ca4496dfd..77d0ee7bcf5 100644
> > --- a/libstdc++-v3/include/bits/stl_algobase.h
> > +++ b/libstdc++-v3/include/bits/stl_algobase.h
> > @@ -318,6 +318,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> > { return __it; }
> >
> > template<typename _Ite, typename _Seq>
> > + _GLIBCXX20_CONSTEXPR
> > _Ite
> > __niter_base(const ::__gnu_debug::_Safe_iterator<_Ite, _Seq,
> > std::random_access_iterator_tag>&);
> > @@ -545,6 +546,7 @@ _GLIBCXX_END_NAMESPACE_CONTAINER
> >
> > template<bool _IsMove,
> > typename _Ite, typename _Seq, typename _Cat, typename _OI>
> > + _GLIBCXX20_CONSTEXPR
> > _OI
> > __copy_move_a(const ::__gnu_debug::_Safe_iterator<_Ite, _Seq, _Cat>&,
> > const ::__gnu_debug::_Safe_iterator<_Ite, _Seq, _Cat>&,
> > @@ -552,6 +554,7 @@ _GLIBCXX_END_NAMESPACE_CONTAINER
> >
> > template<bool _IsMove,
> > typename _II, typename _Ite, typename _Seq, typename _Cat>
> > + _GLIBCXX20_CONSTEXPR
> > __gnu_debug::_Safe_iterator<_Ite, _Seq, _Cat>
> > __copy_move_a(_II, _II,
> > const ::__gnu_debug::_Safe_iterator<_Ite, _Seq, _Cat>&);
> > @@ -559,6 +562,7 @@ _GLIBCXX_END_NAMESPACE_CONTAINER
> > template<bool _IsMove,
> > typename _IIte, typename _ISeq, typename _ICat,
> > typename _OIte, typename _OSeq, typename _OCat>
> > + _GLIBCXX20_CONSTEXPR
> > ::__gnu_debug::_Safe_iterator<_OIte, _OSeq, _OCat>
> > __copy_move_a(const ::__gnu_debug::_Safe_iterator<_IIte, _ISeq, _ICat>&,
> > const ::__gnu_debug::_Safe_iterator<_IIte, _ISeq, _ICat>&,
> > @@ -812,6 +816,7 @@ _GLIBCXX_END_NAMESPACE_CONTAINER
> >
> > template<bool _IsMove,
> > typename _Ite, typename _Seq, typename _Cat, typename _OI>
> > + _GLIBCXX20_CONSTEXPR
> > _OI
> > __copy_move_backward_a(
> > const ::__gnu_debug::_Safe_iterator<_Ite, _Seq, _Cat>&,
> > @@ -820,6 +825,7 @@ _GLIBCXX_END_NAMESPACE_CONTAINER
> >
> > template<bool _IsMove,
> > typename _II, typename _Ite, typename _Seq, typename _Cat>
> > + _GLIBCXX20_CONSTEXPR
> > __gnu_debug::_Safe_iterator<_Ite, _Seq, _Cat>
> > __copy_move_backward_a(_II, _II,
> > const ::__gnu_debug::_Safe_iterator<_Ite, _Seq, _Cat>&);
> > @@ -827,6 +833,7 @@ _GLIBCXX_END_NAMESPACE_CONTAINER
> > template<bool _IsMove,
> > typename _IIte, typename _ISeq, typename _ICat,
> > typename _OIte, typename _OSeq, typename _OCat>
> > + _GLIBCXX20_CONSTEXPR
> > ::__gnu_debug::_Safe_iterator<_OIte, _OSeq, _OCat>
> > __copy_move_backward_a(
> > const ::__gnu_debug::_Safe_iterator<_IIte, _ISeq, _ICat>&,
> > @@ -977,6 +984,7 @@ _GLIBCXX_END_NAMESPACE_CONTAINER
> > { std::__fill_a1(__first, __last, __value); }
> >
> > template<typename _Ite, typename _Seq, typename _Cat, typename _Tp>
> > + _GLIBCXX20_CONSTEXPR
> > void
> > __fill_a(const ::__gnu_debug::_Safe_iterator<_Ite, _Seq, _Cat>&,
> > const ::__gnu_debug::_Safe_iterator<_Ite, _Seq, _Cat>&,
> > @@ -1082,6 +1090,7 @@ _GLIBCXX_END_NAMESPACE_CONTAINER
> >
> > template<typename _Ite, typename _Seq, typename _Cat, typename _Size,
> > typename _Tp>
> > + _GLIBCXX20_CONSTEXPR
> > ::__gnu_debug::_Safe_iterator<_Ite, _Seq, _Cat>
> > __fill_n_a(const ::__gnu_debug::_Safe_iterator<_Ite, _Seq, _Cat>& __first,
> > _Size __n, const _Tp& __value,
> > @@ -1230,18 +1239,21 @@ _GLIBCXX_END_NAMESPACE_CONTAINER
> > }
> >
> > template<typename _II1, typename _Seq1, typename _Cat1, typename _II2>
> > + _GLIBCXX20_CONSTEXPR
> > bool
> > __equal_aux(const ::__gnu_debug::_Safe_iterator<_II1, _Seq1, _Cat1>&,
> > const ::__gnu_debug::_Safe_iterator<_II1, _Seq1, _Cat1>&,
> > _II2);
> >
> > template<typename _II1, typename _II2, typename _Seq2, typename _Cat2>
> > + _GLIBCXX20_CONSTEXPR
> > bool
> > __equal_aux(_II1, _II1,
> > const ::__gnu_debug::_Safe_iterator<_II2, _Seq2, _Cat2>&);
> >
> > template<typename _II1, typename _Seq1, typename _Cat1,
> > typename _II2, typename _Seq2, typename _Cat2>
> > + _GLIBCXX20_CONSTEXPR
> > bool
> > __equal_aux(const ::__gnu_debug::_Safe_iterator<_II1, _Seq1, _Cat1>&,
> > const ::__gnu_debug::_Safe_iterator<_II1, _Seq1, _Cat1>&,
> > @@ -1430,6 +1442,7 @@ _GLIBCXX_END_NAMESPACE_CONTAINER
> >
> > template<typename _Iter1, typename _Seq1, typename _Cat1,
> > typename _II2>
> > + _GLIBCXX20_CONSTEXPR
> > bool
> > __lexicographical_compare_aux(
> > const ::__gnu_debug::_Safe_iterator<_Iter1, _Seq1, _Cat1>&,
> > @@ -1438,6 +1451,7 @@ _GLIBCXX_END_NAMESPACE_CONTAINER
> >
> > template<typename _II1,
> > typename _Iter2, typename _Seq2, typename _Cat2>
> > + _GLIBCXX20_CONSTEXPR
> > bool
> > __lexicographical_compare_aux(
> > _II1, _II1,
> > @@ -1446,6 +1460,7 @@ _GLIBCXX_END_NAMESPACE_CONTAINER
> >
> > template<typename _Iter1, typename _Seq1, typename _Cat1,
> > typename _Iter2, typename _Seq2, typename _Cat2>
> > + _GLIBCXX20_CONSTEXPR
> > bool
> > __lexicographical_compare_aux(
> > const ::__gnu_debug::_Safe_iterator<_Iter1, _Seq1, _Cat1>&,
> > diff --git a/libstdc++-v3/include/debug/helper_functions.h b/libstdc++-v3/include/debug/helper_functions.h
> > index 052b36b484c..4b76cb00f9a 100644
> > --- a/libstdc++-v3/include/debug/helper_functions.h
> > +++ b/libstdc++-v3/include/debug/helper_functions.h
> > @@ -324,6 +324,7 @@ namespace __gnu_debug
> >
> > /* Remove debug mode safe iterator layer, if any. */
> > template<typename _Iterator>
> > + _GLIBCXX_CONSTEXPR
> > inline _Iterator
> > __unsafe(_Iterator __it)
> > { return __it; }
> > diff --git a/libstdc++-v3/include/debug/macros.h b/libstdc++-v3/include/debug/macros.h
> > index 0fef0a006fc..4a3d0f2ea84 100644
> > --- a/libstdc++-v3/include/debug/macros.h
> > +++ b/libstdc++-v3/include/debug/macros.h
> > @@ -38,15 +38,12 @@
> > * the user error and where the error is reported.
> > *
> > */
> > -#define _GLIBCXX_DEBUG_VERIFY_COND_AT(_Cond,_ErrMsg,_File,_Line,_Func) \
> > - if (__builtin_expect(!bool(_Cond), false)) \
> > - __gnu_debug::_Error_formatter::_S_at(_File, _Line, _Func) \
> > - ._ErrMsg._M_error()
> >
> > #define _GLIBCXX_DEBUG_VERIFY_AT_F(_Cond,_ErrMsg,_File,_Line,_Func) \
> > do { \
> > - __glibcxx_constexpr_assert(_Cond); \
> > - _GLIBCXX_DEBUG_VERIFY_COND_AT(_Cond,_ErrMsg,_File,_Line,_Func); \
> > + if (__builtin_expect(!bool(_Cond), false)) \
> > + __gnu_debug::_Error_formatter::_S_at(_File, _Line, _Func) \
> > + ._ErrMsg._M_error(); \
> > } while (false)
> >
> > #define _GLIBCXX_DEBUG_VERIFY_AT(_Cond,_ErrMsg,_File,_Line) \
> > diff --git a/libstdc++-v3/include/debug/safe_base.h b/libstdc++-v3/include/debug/safe_base.h
> > index 1dfa9f68b65..d9c17b52b48 100644
> > --- a/libstdc++-v3/include/debug/safe_base.h
> > +++ b/libstdc++-v3/include/debug/safe_base.h
> > @@ -75,6 +75,7 @@ namespace __gnu_debug
> >
> > protected:
> > /** Initializes the iterator and makes it singular. */
> > + _GLIBCXX20_CONSTEXPR
> > _Safe_iterator_base()
> > : _M_sequence(0), _M_version(0), _M_prior(0), _M_next(0)
> > { }
> > @@ -86,18 +87,31 @@ namespace __gnu_debug
> > * 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)
> > - { this->_M_attach(const_cast<_Safe_sequence_base*>(__seq), __constant); }
> > + {
> > + if (!std::__is_constant_evaluated())
> > + this->_M_attach(const_cast<_Safe_sequence_base*>(__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. */
> > + _GLIBCXX20_CONSTEXPR
> > _Safe_iterator_base(const _Safe_iterator_base& __x, bool __constant)
> > : _M_sequence(0), _M_version(0), _M_prior(0), _M_next(0)
> > - { this->_M_attach(__x._M_sequence, __constant); }
> > + {
> > + if (!std::__is_constant_evaluated())
> > + this->_M_attach(__x._M_sequence, __constant);
> > + }
> >
> > - ~_Safe_iterator_base() { this->_M_detach(); }
> > + _GLIBCXX20_CONSTEXPR
> > + ~_Safe_iterator_base()
> > + {
> > + if (!std::__is_constant_evaluated())
> > + this->_M_detach();
> > + }
> >
> > /** For use in _Safe_iterator. */
> > __gnu_cxx::__mutex&
> > @@ -201,24 +215,34 @@ namespace __gnu_debug
> >
> > protected:
> > // Initialize with a version number of 1 and no iterators
> > + _GLIBCXX20_CONSTEXPR
> > _Safe_sequence_base() _GLIBCXX_NOEXCEPT
> > : _M_iterators(0), _M_const_iterators(0), _M_version(1)
> > { }
> >
> > #if __cplusplus >= 201103L
> > + _GLIBCXX20_CONSTEXPR
> > _Safe_sequence_base(const _Safe_sequence_base&) noexcept
> > : _Safe_sequence_base() { }
> >
> > // Move constructor swap iterators.
> > + _GLIBCXX20_CONSTEXPR
> > _Safe_sequence_base(_Safe_sequence_base&& __seq) noexcept
> > : _Safe_sequence_base()
> > - { _M_swap(__seq); }
> > + {
> > + if (!std::__is_constant_evaluated())
> > + _M_swap(__seq);
> > + }
> > #endif
> >
> > /** Notify all iterators that reference this sequence that the
> > sequence is being destroyed. */
> > + _GLIBCXX20_CONSTEXPR
> > ~_Safe_sequence_base()
> > - { this->_M_detach_all(); }
> > + {
> > + if (!std::__is_constant_evaluated())
> > + this->_M_detach_all();
> > + }
> >
> > /** Detach all iterators, leaving them singular. */
> > void
> > @@ -244,6 +268,7 @@ namespace __gnu_debug
> > * operation is complete all iterators that originally referenced
> > * one container now reference the other container.
> > */
> > + _GLIBCXX20_CONSTEXPR
> > void
> > _M_swap(_Safe_sequence_base& __x) _GLIBCXX_USE_NOEXCEPT;
>
> With -Wsystem-headers on some ranges tests I get:
>
> /gcc-build/x86_64-pc-linux-gnu/libstdc++-v3/include/debug/safe_base.h:273:5: warning: inline function ‘constexpr void __gnu_debug::_Safe_sequence_base::_M_swap(__gnu_debug::_Safe_sequence_base&)’ used but never defined
> 273 | _M_swap(_Safe_sequence_base& __x) _GLIBCXX_USE_NOEXCEPT;
> | ^~~~~~~
Oh I think we can remove the CONSTEXPR macro. I added it too
aggressively and forgot to remove it again in some places.
On Sat, 16 Dec 2023 at 09:14, Jonathan Wakely wrote:
>
> On Sat, 16 Dec 2023 at 00:27, Patrick Palka wrote:
> >
> > On Wed, 6 Dec 2023, Jonathan Wakely wrote:
> >
> > > Any comments on this approach?
> > >
> > > -- >8 --
> > >
> > > This makes constexpr std::vector (mostly) work in Debug Mode. All safe
> > > iterator instrumentation and checking is disabled during constant
> > > evaluation, because it requires mutex locks and calls to non-inline
> > > functions defined in libstdc++.so. It should be OK to disable the safety
> > > checks, because most UB should be detected during constant evaluation
> > > anyway.
> > >
> > > We could try to enable the full checking in constexpr, but it would mean
> > > wrapping all the non-inline functions like _M_attach with an inline
> > > _M_constexpr_attach that does the iterator housekeeping inline without
> > > mutex locks when calling for constant evaluation, and calls the
> > > non-inline function at runtime. That could be done in future if we find
> > > that we've lost safety or useful checking by disabling the safe
> > > iterators.
> > >
> > > There are a few test failures in C++20 mode, which I'm unable to
> > > explain. The _Safe_iterator::operator++() member gives errors for using
> > > non-constexpr functions during constant evaluation, even though those
> > > functions are guarded by std::is_constant_evaluated() checks. The same
> > > code works fine for C++23 and up.
> >
> > AFAICT these C++20 test failures are really due to the variable
> > definition of non-literal type
> >
> > 381 __gnu_cxx::__scoped_lock __l(this->_M_get_mutex());
> >
> > which were prohibited in a constexpr function (even if that code was
> > never executed) until C++23's P2242R3.
>
> Ah, I figured it was a core change but I couldn't recall which one. Thanks.
>
> > We can use an immediately invoked lambda to work around this:
> >
> > 381 [this] {
> > 382 __gnu_cxx::__scoped_lock __l(this->_M_get_mutex());
> > 383 ++base();
> > 384 }();
> > 385 return *this;
>
> We'd need some #if as this code has to work for C++98. But that's doable.
The attached patch seems simpler, I'm testing it now.
commit 5d70c6c2965647077749a869e9cdbf7e91dba4c7
Author: Jonathan Wakely <jwakely@redhat.com>
Date: Sat Dec 16 09:31:40 2023
libstdc++: Fix errors for constexpr __gnu_debug::vector in C++23 [PR109536]
In the commit log for r14-6553-g7d00a59229ee17 I noted some tests FAIL
in C++20 mode. Patrick identified that they were due to the variable
definitions of non-literal type __scoped_lock, which were prohibited in
a constexpr function (even if that code was never executed) until
C++23's P2242R3.
We can move the problematic code into new non-constexpr functions that
are not called during constant evaluation.
There's also a warning about a constexpr _M_swap function which is never
defined. That's simply because I added the _GLIBCXX20_CONSTEXPR macro on
a member that doesn't need it.
libstdc++-v3/ChangeLog:
PR libstdc++/109536
* include/debug/safe_base.h (_Safe_sequence_base::_M_swap):
Remove _GLIBCXX20_CONSTEXPR from non-inline member function.
* include/debug/safe_iterator.h (_Safe_iterator::_M_move_assign)
diff --git a/libstdc++-v3/include/debug/safe_base.h b/libstdc++-v3/include/debug/safe_base.h
index d9c17b52b48..1519ad809a4 100644
--- a/libstdc++-v3/include/debug/safe_base.h
+++ b/libstdc++-v3/include/debug/safe_base.h
@@ -268,7 +268,6 @@ namespace __gnu_debug
* operation is complete all iterators that originally referenced
* one container now reference the other container.
*/
- _GLIBCXX20_CONSTEXPR
void
_M_swap(_Safe_sequence_base& __x) _GLIBCXX_USE_NOEXCEPT;
diff --git a/libstdc++-v3/include/debug/safe_iterator.h b/libstdc++-v3/include/debug/safe_iterator.h
index 26f008982f8..bde34e1f99c 100644
--- a/libstdc++-v3/include/debug/safe_iterator.h
+++ b/libstdc++-v3/include/debug/safe_iterator.h
@@ -295,7 +295,13 @@ namespace __gnu_debug
base() = __x.base();
return *this;
}
+ _M_move_assign(std::move(__x));
+ return *this;
+ }
+ void
+ _M_move_assign(_Safe_iterator&& __x) noexcept
+ {
_GLIBCXX_DEBUG_VERIFY(!__x._M_singular()
|| __x._M_value_initialized(),
_M_message(__msg_copy_singular)
@@ -303,7 +309,7 @@ namespace __gnu_debug
._M_iterator(__x, "other"));
if (std::__addressof(__x) == this)
- return *this;
+ return;
if (this->_M_sequence && this->_M_sequence == __x._M_sequence)
{
@@ -320,7 +326,6 @@ namespace __gnu_debug
__x._M_detach();
__x.base() = _Iterator();
- return *this;
}
#endif
@@ -370,17 +375,20 @@ namespace __gnu_debug
operator++() _GLIBCXX_NOEXCEPT
{
if (std::__is_constant_evaluated())
- {
- ++base();
- return *this;
- }
+ ++base();
+ else
+ _M_increment();
+ return *this;
+ }
+ void
+ _M_increment() _GLIBCXX_NOEXCEPT
+ {
_GLIBCXX_DEBUG_VERIFY(this->_M_incrementable(),
_M_message(__msg_bad_inc)
._M_iterator(*this, "this"));
__gnu_cxx::__scoped_lock __l(this->_M_get_mutex());
++base();
- return *this;
}
/**
@@ -689,17 +697,20 @@ namespace __gnu_debug
operator--() _GLIBCXX_NOEXCEPT
{
if (std::__is_constant_evaluated())
- {
- --this->base();
- return *this;
- }
+ --this->base();
+ else
+ _M_decrement();
+ return *this;
+ }
+ void
+ _M_decrement() _GLIBCXX_NOEXCEPT
+ {
_GLIBCXX_DEBUG_VERIFY(this->_M_decrementable(),
_M_message(__msg_bad_dec)
._M_iterator(*this, "this"));
__gnu_cxx::__scoped_lock __l(this->_M_get_mutex());
--this->base();
- return *this;
}
/**
On Sat, 16 Dec 2023, Jonathan Wakely wrote:
> On Sat, 16 Dec 2023 at 09:14, Jonathan Wakely wrote:
> >
> > On Sat, 16 Dec 2023 at 00:27, Patrick Palka wrote:
> > >
> > > On Wed, 6 Dec 2023, Jonathan Wakely wrote:
> > >
> > > > Any comments on this approach?
> > > >
> > > > -- >8 --
> > > >
> > > > This makes constexpr std::vector (mostly) work in Debug Mode. All safe
> > > > iterator instrumentation and checking is disabled during constant
> > > > evaluation, because it requires mutex locks and calls to non-inline
> > > > functions defined in libstdc++.so. It should be OK to disable the safety
> > > > checks, because most UB should be detected during constant evaluation
> > > > anyway.
> > > >
> > > > We could try to enable the full checking in constexpr, but it would mean
> > > > wrapping all the non-inline functions like _M_attach with an inline
> > > > _M_constexpr_attach that does the iterator housekeeping inline without
> > > > mutex locks when calling for constant evaluation, and calls the
> > > > non-inline function at runtime. That could be done in future if we find
> > > > that we've lost safety or useful checking by disabling the safe
> > > > iterators.
> > > >
> > > > There are a few test failures in C++20 mode, which I'm unable to
> > > > explain. The _Safe_iterator::operator++() member gives errors for using
> > > > non-constexpr functions during constant evaluation, even though those
> > > > functions are guarded by std::is_constant_evaluated() checks. The same
> > > > code works fine for C++23 and up.
> > >
> > > AFAICT these C++20 test failures are really due to the variable
> > > definition of non-literal type
> > >
> > > 381 __gnu_cxx::__scoped_lock __l(this->_M_get_mutex());
> > >
> > > which were prohibited in a constexpr function (even if that code was
> > > never executed) until C++23's P2242R3.
> >
> > Ah, I figured it was a core change but I couldn't recall which one. Thanks.
Yeah the diagnostic blaming the non-constexpr call to _M_incrementable
was outright wrong and misleading, I filed PR113041 about that.
> >
> > > We can use an immediately invoked lambda to work around this:
> > >
> > > 381 [this] {
> > > 382 __gnu_cxx::__scoped_lock __l(this->_M_get_mutex());
> > > 383 ++base();
> > > 384 }();
> > > 385 return *this;
> >
> > We'd need some #if as this code has to work for C++98. But that's doable.
>
> The attached patch seems simpler, I'm testing it now.
Would the operator+=, operator-= and the copy assign operator= also need
adjustment?
We could somewhat cleanly encapsulate the lambda workaround with a pair
of macros surrounding the problematic variable, something like:
diff --git a/libstdc++-v3/include/debug/safe_iterator.h b/libstdc++-v3/include/debug/safe_iterator.h
index 26f008982f8..df3b4d33f04 100644
--- a/libstdc++-v3/include/debug/safe_iterator.h
+++ b/libstdc++-v3/include/debug/safe_iterator.h
@@ -360,6 +360,14 @@ namespace __gnu_debug
return base().operator->();
}
+#if __cplusplus >= 202002L && __cpp_constexpr < 202110L
+# define _GLIBCXX20_CONSTEXPR_NON_LITERAL_SCOPE_BEGIN [&] { do
+# define _GLIBCXX20_CONSTEXPR_NON_LITERAL_SCOPE_END while(false); }()
+#else
+# define _GLIBCXX20_CONSTEXPR_NON_LITERAL_SCOPE_BEGIN do
+# define _GLIBCXX20_CONSTEXPR_NON_LITERAL_SCOPE_END while(false)
+#endif
+
// ------ Input iterator requirements ------
/**
* @brief Iterator preincrement
@@ -378,8 +386,10 @@ namespace __gnu_debug
_GLIBCXX_DEBUG_VERIFY(this->_M_incrementable(),
_M_message(__msg_bad_inc)
._M_iterator(*this, "this"));
- __gnu_cxx::__scoped_lock __l(this->_M_get_mutex());
- ++base();
+ _GLIBCXX20_CONSTEXPR_NON_LITERAL_SCOPE_BEGIN {
+ __gnu_cxx::__scoped_lock __l(this->_M_get_mutex());
+ ++base();
+ } _GLIBCXX20_CONSTEXPR_NON_LITERAL_SCOPE_END;
return *this;
}
On Sat, 16 Dec 2023 at 16:26, Patrick Palka <ppalka@redhat.com> wrote:
>
> On Sat, 16 Dec 2023, Jonathan Wakely wrote:
>
> > On Sat, 16 Dec 2023 at 09:14, Jonathan Wakely wrote:
> > >
> > > On Sat, 16 Dec 2023 at 00:27, Patrick Palka wrote:
> > > >
> > > > On Wed, 6 Dec 2023, Jonathan Wakely wrote:
> > > >
> > > > > Any comments on this approach?
> > > > >
> > > > > -- >8 --
> > > > >
> > > > > This makes constexpr std::vector (mostly) work in Debug Mode. All safe
> > > > > iterator instrumentation and checking is disabled during constant
> > > > > evaluation, because it requires mutex locks and calls to non-inline
> > > > > functions defined in libstdc++.so. It should be OK to disable the safety
> > > > > checks, because most UB should be detected during constant evaluation
> > > > > anyway.
> > > > >
> > > > > We could try to enable the full checking in constexpr, but it would mean
> > > > > wrapping all the non-inline functions like _M_attach with an inline
> > > > > _M_constexpr_attach that does the iterator housekeeping inline without
> > > > > mutex locks when calling for constant evaluation, and calls the
> > > > > non-inline function at runtime. That could be done in future if we find
> > > > > that we've lost safety or useful checking by disabling the safe
> > > > > iterators.
> > > > >
> > > > > There are a few test failures in C++20 mode, which I'm unable to
> > > > > explain. The _Safe_iterator::operator++() member gives errors for using
> > > > > non-constexpr functions during constant evaluation, even though those
> > > > > functions are guarded by std::is_constant_evaluated() checks. The same
> > > > > code works fine for C++23 and up.
> > > >
> > > > AFAICT these C++20 test failures are really due to the variable
> > > > definition of non-literal type
> > > >
> > > > 381 __gnu_cxx::__scoped_lock __l(this->_M_get_mutex());
> > > >
> > > > which were prohibited in a constexpr function (even if that code was
> > > > never executed) until C++23's P2242R3.
> > >
> > > Ah, I figured it was a core change but I couldn't recall which one. Thanks.
>
> Yeah the diagnostic blaming the non-constexpr call to _M_incrementable
> was outright wrong and misleading, I filed PR113041 about that.
>
> > >
> > > > We can use an immediately invoked lambda to work around this:
> > > >
> > > > 381 [this] {
> > > > 382 __gnu_cxx::__scoped_lock __l(this->_M_get_mutex());
> > > > 383 ++base();
> > > > 384 }();
> > > > 385 return *this;
> > >
> > > We'd need some #if as this code has to work for C++98. But that's doable.
> >
> > The attached patch seems simpler, I'm testing it now.
>
> Would the operator+=, operator-= and the copy assign operator= also need
> adjustment?
Maybe ... which suggest we have missing tests for constexpr vector
(which is probably the case).
>
> We could somewhat cleanly encapsulate the lambda workaround with a pair
> of macros surrounding the problematic variable, something like:
>
> diff --git a/libstdc++-v3/include/debug/safe_iterator.h b/libstdc++-v3/include/debug/safe_iterator.h
> index 26f008982f8..df3b4d33f04 100644
> --- a/libstdc++-v3/include/debug/safe_iterator.h
> +++ b/libstdc++-v3/include/debug/safe_iterator.h
> @@ -360,6 +360,14 @@ namespace __gnu_debug
> return base().operator->();
> }
>
> +#if __cplusplus >= 202002L && __cpp_constexpr < 202110L
> +# define _GLIBCXX20_CONSTEXPR_NON_LITERAL_SCOPE_BEGIN [&] { do
> +# define _GLIBCXX20_CONSTEXPR_NON_LITERAL_SCOPE_END while(false); }()
> +#else
> +# define _GLIBCXX20_CONSTEXPR_NON_LITERAL_SCOPE_BEGIN do
> +# define _GLIBCXX20_CONSTEXPR_NON_LITERAL_SCOPE_END while(false)
I think for the limited uses in this file, we don't even need the
do-while, as the code we're enclosing is not a single statement
anyway.
> +#endif
> +
> // ------ Input iterator requirements ------
> /**
> * @brief Iterator preincrement
> @@ -378,8 +386,10 @@ namespace __gnu_debug
> _GLIBCXX_DEBUG_VERIFY(this->_M_incrementable(),
> _M_message(__msg_bad_inc)
> ._M_iterator(*this, "this"));
> - __gnu_cxx::__scoped_lock __l(this->_M_get_mutex());
> - ++base();
> + _GLIBCXX20_CONSTEXPR_NON_LITERAL_SCOPE_BEGIN {
> + __gnu_cxx::__scoped_lock __l(this->_M_get_mutex());
> + ++base();
> + } _GLIBCXX20_CONSTEXPR_NON_LITERAL_SCOPE_END;
> return *this;
> }
>
Yeah, I'll check if other operators need it, and if it's more than
just the two places in my patch I'll go with that.
If I don't get around to it (as I'm meant to have stopped work for the
year yesterday) then feel free to do that.
@@ -565,15 +565,6 @@ namespace std
# define _GLIBCXX_EXTERN_TEMPLATE -1
#endif
-
-#if _GLIBCXX_HAVE_IS_CONSTANT_EVALUATED
-# define __glibcxx_constexpr_assert(cond) \
- if (std::__is_constant_evaluated() && !bool(cond)) \
- __builtin_unreachable() /* precondition violation detected! */
-#else
-# define __glibcxx_constexpr_assert(unevaluated)
-#endif
-
#undef _GLIBCXX_VERBOSE_ASSERT
// Assert.
@@ -318,6 +318,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
{ return __it; }
template<typename _Ite, typename _Seq>
+ _GLIBCXX20_CONSTEXPR
_Ite
__niter_base(const ::__gnu_debug::_Safe_iterator<_Ite, _Seq,
std::random_access_iterator_tag>&);
@@ -545,6 +546,7 @@ _GLIBCXX_END_NAMESPACE_CONTAINER
template<bool _IsMove,
typename _Ite, typename _Seq, typename _Cat, typename _OI>
+ _GLIBCXX20_CONSTEXPR
_OI
__copy_move_a(const ::__gnu_debug::_Safe_iterator<_Ite, _Seq, _Cat>&,
const ::__gnu_debug::_Safe_iterator<_Ite, _Seq, _Cat>&,
@@ -552,6 +554,7 @@ _GLIBCXX_END_NAMESPACE_CONTAINER
template<bool _IsMove,
typename _II, typename _Ite, typename _Seq, typename _Cat>
+ _GLIBCXX20_CONSTEXPR
__gnu_debug::_Safe_iterator<_Ite, _Seq, _Cat>
__copy_move_a(_II, _II,
const ::__gnu_debug::_Safe_iterator<_Ite, _Seq, _Cat>&);
@@ -559,6 +562,7 @@ _GLIBCXX_END_NAMESPACE_CONTAINER
template<bool _IsMove,
typename _IIte, typename _ISeq, typename _ICat,
typename _OIte, typename _OSeq, typename _OCat>
+ _GLIBCXX20_CONSTEXPR
::__gnu_debug::_Safe_iterator<_OIte, _OSeq, _OCat>
__copy_move_a(const ::__gnu_debug::_Safe_iterator<_IIte, _ISeq, _ICat>&,
const ::__gnu_debug::_Safe_iterator<_IIte, _ISeq, _ICat>&,
@@ -812,6 +816,7 @@ _GLIBCXX_END_NAMESPACE_CONTAINER
template<bool _IsMove,
typename _Ite, typename _Seq, typename _Cat, typename _OI>
+ _GLIBCXX20_CONSTEXPR
_OI
__copy_move_backward_a(
const ::__gnu_debug::_Safe_iterator<_Ite, _Seq, _Cat>&,
@@ -820,6 +825,7 @@ _GLIBCXX_END_NAMESPACE_CONTAINER
template<bool _IsMove,
typename _II, typename _Ite, typename _Seq, typename _Cat>
+ _GLIBCXX20_CONSTEXPR
__gnu_debug::_Safe_iterator<_Ite, _Seq, _Cat>
__copy_move_backward_a(_II, _II,
const ::__gnu_debug::_Safe_iterator<_Ite, _Seq, _Cat>&);
@@ -827,6 +833,7 @@ _GLIBCXX_END_NAMESPACE_CONTAINER
template<bool _IsMove,
typename _IIte, typename _ISeq, typename _ICat,
typename _OIte, typename _OSeq, typename _OCat>
+ _GLIBCXX20_CONSTEXPR
::__gnu_debug::_Safe_iterator<_OIte, _OSeq, _OCat>
__copy_move_backward_a(
const ::__gnu_debug::_Safe_iterator<_IIte, _ISeq, _ICat>&,
@@ -977,6 +984,7 @@ _GLIBCXX_END_NAMESPACE_CONTAINER
{ std::__fill_a1(__first, __last, __value); }
template<typename _Ite, typename _Seq, typename _Cat, typename _Tp>
+ _GLIBCXX20_CONSTEXPR
void
__fill_a(const ::__gnu_debug::_Safe_iterator<_Ite, _Seq, _Cat>&,
const ::__gnu_debug::_Safe_iterator<_Ite, _Seq, _Cat>&,
@@ -1082,6 +1090,7 @@ _GLIBCXX_END_NAMESPACE_CONTAINER
template<typename _Ite, typename _Seq, typename _Cat, typename _Size,
typename _Tp>
+ _GLIBCXX20_CONSTEXPR
::__gnu_debug::_Safe_iterator<_Ite, _Seq, _Cat>
__fill_n_a(const ::__gnu_debug::_Safe_iterator<_Ite, _Seq, _Cat>& __first,
_Size __n, const _Tp& __value,
@@ -1230,18 +1239,21 @@ _GLIBCXX_END_NAMESPACE_CONTAINER
}
template<typename _II1, typename _Seq1, typename _Cat1, typename _II2>
+ _GLIBCXX20_CONSTEXPR
bool
__equal_aux(const ::__gnu_debug::_Safe_iterator<_II1, _Seq1, _Cat1>&,
const ::__gnu_debug::_Safe_iterator<_II1, _Seq1, _Cat1>&,
_II2);
template<typename _II1, typename _II2, typename _Seq2, typename _Cat2>
+ _GLIBCXX20_CONSTEXPR
bool
__equal_aux(_II1, _II1,
const ::__gnu_debug::_Safe_iterator<_II2, _Seq2, _Cat2>&);
template<typename _II1, typename _Seq1, typename _Cat1,
typename _II2, typename _Seq2, typename _Cat2>
+ _GLIBCXX20_CONSTEXPR
bool
__equal_aux(const ::__gnu_debug::_Safe_iterator<_II1, _Seq1, _Cat1>&,
const ::__gnu_debug::_Safe_iterator<_II1, _Seq1, _Cat1>&,
@@ -1430,6 +1442,7 @@ _GLIBCXX_END_NAMESPACE_CONTAINER
template<typename _Iter1, typename _Seq1, typename _Cat1,
typename _II2>
+ _GLIBCXX20_CONSTEXPR
bool
__lexicographical_compare_aux(
const ::__gnu_debug::_Safe_iterator<_Iter1, _Seq1, _Cat1>&,
@@ -1438,6 +1451,7 @@ _GLIBCXX_END_NAMESPACE_CONTAINER
template<typename _II1,
typename _Iter2, typename _Seq2, typename _Cat2>
+ _GLIBCXX20_CONSTEXPR
bool
__lexicographical_compare_aux(
_II1, _II1,
@@ -1446,6 +1460,7 @@ _GLIBCXX_END_NAMESPACE_CONTAINER
template<typename _Iter1, typename _Seq1, typename _Cat1,
typename _Iter2, typename _Seq2, typename _Cat2>
+ _GLIBCXX20_CONSTEXPR
bool
__lexicographical_compare_aux(
const ::__gnu_debug::_Safe_iterator<_Iter1, _Seq1, _Cat1>&,
@@ -324,6 +324,7 @@ namespace __gnu_debug
/* Remove debug mode safe iterator layer, if any. */
template<typename _Iterator>
+ _GLIBCXX_CONSTEXPR
inline _Iterator
__unsafe(_Iterator __it)
{ return __it; }
@@ -38,15 +38,12 @@
* the user error and where the error is reported.
*
*/
-#define _GLIBCXX_DEBUG_VERIFY_COND_AT(_Cond,_ErrMsg,_File,_Line,_Func) \
- if (__builtin_expect(!bool(_Cond), false)) \
- __gnu_debug::_Error_formatter::_S_at(_File, _Line, _Func) \
- ._ErrMsg._M_error()
#define _GLIBCXX_DEBUG_VERIFY_AT_F(_Cond,_ErrMsg,_File,_Line,_Func) \
do { \
- __glibcxx_constexpr_assert(_Cond); \
- _GLIBCXX_DEBUG_VERIFY_COND_AT(_Cond,_ErrMsg,_File,_Line,_Func); \
+ if (__builtin_expect(!bool(_Cond), false)) \
+ __gnu_debug::_Error_formatter::_S_at(_File, _Line, _Func) \
+ ._ErrMsg._M_error(); \
} while (false)
#define _GLIBCXX_DEBUG_VERIFY_AT(_Cond,_ErrMsg,_File,_Line) \
@@ -75,6 +75,7 @@ namespace __gnu_debug
protected:
/** Initializes the iterator and makes it singular. */
+ _GLIBCXX20_CONSTEXPR
_Safe_iterator_base()
: _M_sequence(0), _M_version(0), _M_prior(0), _M_next(0)
{ }
@@ -86,18 +87,31 @@ namespace __gnu_debug
* 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)
- { this->_M_attach(const_cast<_Safe_sequence_base*>(__seq), __constant); }
+ {
+ if (!std::__is_constant_evaluated())
+ this->_M_attach(const_cast<_Safe_sequence_base*>(__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. */
+ _GLIBCXX20_CONSTEXPR
_Safe_iterator_base(const _Safe_iterator_base& __x, bool __constant)
: _M_sequence(0), _M_version(0), _M_prior(0), _M_next(0)
- { this->_M_attach(__x._M_sequence, __constant); }
+ {
+ if (!std::__is_constant_evaluated())
+ this->_M_attach(__x._M_sequence, __constant);
+ }
- ~_Safe_iterator_base() { this->_M_detach(); }
+ _GLIBCXX20_CONSTEXPR
+ ~_Safe_iterator_base()
+ {
+ if (!std::__is_constant_evaluated())
+ this->_M_detach();
+ }
/** For use in _Safe_iterator. */
__gnu_cxx::__mutex&
@@ -201,24 +215,34 @@ namespace __gnu_debug
protected:
// Initialize with a version number of 1 and no iterators
+ _GLIBCXX20_CONSTEXPR
_Safe_sequence_base() _GLIBCXX_NOEXCEPT
: _M_iterators(0), _M_const_iterators(0), _M_version(1)
{ }
#if __cplusplus >= 201103L
+ _GLIBCXX20_CONSTEXPR
_Safe_sequence_base(const _Safe_sequence_base&) noexcept
: _Safe_sequence_base() { }
// Move constructor swap iterators.
+ _GLIBCXX20_CONSTEXPR
_Safe_sequence_base(_Safe_sequence_base&& __seq) noexcept
: _Safe_sequence_base()
- { _M_swap(__seq); }
+ {
+ if (!std::__is_constant_evaluated())
+ _M_swap(__seq);
+ }
#endif
/** Notify all iterators that reference this sequence that the
sequence is being destroyed. */
+ _GLIBCXX20_CONSTEXPR
~_Safe_sequence_base()
- { this->_M_detach_all(); }
+ {
+ if (!std::__is_constant_evaluated())
+ this->_M_detach_all();
+ }
/** Detach all iterators, leaving them singular. */
void
@@ -244,6 +268,7 @@ namespace __gnu_debug
* operation is complete all iterators that originally referenced
* one container now reference the other container.
*/
+ _GLIBCXX20_CONSTEXPR
void
_M_swap(_Safe_sequence_base& __x) _GLIBCXX_USE_NOEXCEPT;
@@ -43,6 +43,7 @@ namespace __gnu_debug
{
typedef _SafeBase<_SafeContainer> _Base;
+ _GLIBCXX20_CONSTEXPR
_SafeContainer&
_M_cont() _GLIBCXX_NOEXCEPT
{ return *static_cast<_SafeContainer*>(this); }
@@ -54,20 +55,23 @@ namespace __gnu_debug
_Safe_container(_Safe_container&&) = default;
private:
+ _GLIBCXX20_CONSTEXPR
_Safe_container(_Safe_container&& __x, const _Alloc&, std::true_type)
: _Safe_container(std::move(__x))
{ }
+ _GLIBCXX20_CONSTEXPR
_Safe_container(_Safe_container&& __x, const _Alloc& __a, std::false_type)
: _Safe_container()
{
if (__x._M_cont().get_allocator() == __a)
_Base::_M_swap(__x);
- else
+ else if (!std::__is_constant_evaluated())
__x._M_invalidate_all();
}
protected:
+ _GLIBCXX20_CONSTEXPR
_Safe_container(_Safe_container&& __x, const _Alloc& __a)
: _Safe_container(std::move(__x), __a,
typename std::allocator_traits<_Alloc>::is_always_equal{})
@@ -75,17 +79,23 @@ namespace __gnu_debug
#endif
// Copy assignment invalidate all iterators.
+ _GLIBCXX20_CONSTEXPR
_Safe_container&
operator=(const _Safe_container&) _GLIBCXX_NOEXCEPT
{
- this->_M_invalidate_all();
+ if (!std::__is_constant_evaluated())
+ this->_M_invalidate_all();
return *this;
}
#if __cplusplus >= 201103L
+ _GLIBCXX20_CONSTEXPR
_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
@@ -113,6 +123,7 @@ namespace __gnu_debug
return *this;
}
+ _GLIBCXX20_CONSTEXPR
void
_M_swap(_Safe_container& __x) noexcept
{
@@ -40,6 +40,7 @@
#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()), \
@@ -49,7 +50,8 @@
_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, \
@@ -131,9 +133,13 @@ namespace __gnu_debug
struct _Unchecked { };
+ _GLIBCXX20_CONSTEXPR
_Safe_iterator(const _Safe_iterator& __x, _Unchecked) _GLIBCXX_NOEXCEPT
: _Iter_base(__x.base()), _Safe_base()
- { _M_attach(__x._M_sequence); }
+ {
+ if (!std::__is_constant_evaluated())
+ _M_attach(__x._M_sequence);
+ }
public:
typedef _Iterator iterator_type;
@@ -148,6 +154,7 @@ namespace __gnu_debug
#endif
/// @post the iterator is singular and unattached
+ _GLIBCXX20_CONSTEXPR
_Safe_iterator() _GLIBCXX_NOEXCEPT : _Iter_base() { }
/**
@@ -157,6 +164,7 @@ namespace __gnu_debug
* @pre @p seq is not NULL
* @post this is not singular
*/
+ _GLIBCXX20_CONSTEXPR
_Safe_iterator(_Iterator __i, const _Safe_sequence_base* __seq)
_GLIBCXX_NOEXCEPT
: _Iter_base(__i), _Safe_base(__seq, _S_constant())
@@ -165,9 +173,13 @@ namespace __gnu_debug
/**
* @brief Copy construction.
*/
+ _GLIBCXX20_CONSTEXPR
_Safe_iterator(const _Safe_iterator& __x) _GLIBCXX_NOEXCEPT
: _Iter_base(__x.base()), _Safe_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()
@@ -183,9 +195,16 @@ namespace __gnu_debug
* @brief Move construction.
* @post __x is singular and unattached
*/
+ _GLIBCXX20_CONSTEXPR
_Safe_iterator(_Safe_iterator&& __x) noexcept
: _Iter_base()
{
+ 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)
@@ -203,6 +222,7 @@ namespace __gnu_debug
* constant iterator.
*/
template<typename _MutableIterator>
+ _GLIBCXX20_CONSTEXPR
_Safe_iterator(
const _Safe_iterator<_MutableIterator, _Sequence,
typename __gnu_cxx::__enable_if<_IsConstant::__value &&
@@ -211,6 +231,9 @@ namespace __gnu_debug
_GLIBCXX_NOEXCEPT
: _Iter_base(__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()
@@ -224,9 +247,16 @@ namespace __gnu_debug
/**
* @brief Copy assignment.
*/
+ _GLIBCXX20_CONSTEXPR
_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()
@@ -256,9 +286,16 @@ namespace __gnu_debug
* @brief Move assignment.
* @post __x is singular and unattached
*/
+ _GLIBCXX20_CONSTEXPR
_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)
@@ -292,12 +329,16 @@ namespace __gnu_debug
* @pre iterator is dereferenceable
*/
_GLIBCXX_NODISCARD
+ _GLIBCXX20_CONSTEXPR
reference
operator*() const _GLIBCXX_NOEXCEPT
{
- _GLIBCXX_DEBUG_VERIFY(this->_M_dereferenceable(),
- _M_message(__msg_bad_deref)
- ._M_iterator(*this, "this"));
+ if (!std::__is_constant_evaluated())
+ {
+ _GLIBCXX_DEBUG_VERIFY(this->_M_dereferenceable(),
+ _M_message(__msg_bad_deref)
+ ._M_iterator(*this, "this"));
+ }
return *base();
}
@@ -306,12 +347,16 @@ namespace __gnu_debug
* @pre iterator is dereferenceable
*/
_GLIBCXX_NODISCARD
+ _GLIBCXX20_CONSTEXPR
pointer
operator->() const _GLIBCXX_NOEXCEPT
{
- _GLIBCXX_DEBUG_VERIFY(this->_M_dereferenceable(),
- _M_message(__msg_bad_deref)
- ._M_iterator(*this, "this"));
+ if (!std::__is_constant_evaluated())
+ {
+ _GLIBCXX_DEBUG_VERIFY(this->_M_dereferenceable(),
+ _M_message(__msg_bad_deref)
+ ._M_iterator(*this, "this"));
+ }
return base().operator->();
}
@@ -320,9 +365,16 @@ namespace __gnu_debug
* @brief Iterator preincrement
* @pre iterator is incrementable
*/
+ _GLIBCXX20_CONSTEXPR
_Safe_iterator&
operator++() _GLIBCXX_NOEXCEPT
{
+ if (std::__is_constant_evaluated())
+ {
+ ++base();
+ return *this;
+ }
+
_GLIBCXX_DEBUG_VERIFY(this->_M_incrementable(),
_M_message(__msg_bad_inc)
._M_iterator(*this, "this"));
@@ -335,12 +387,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;
@@ -356,9 +412,11 @@ namespace __gnu_debug
/**
* @brief Return the underlying iterator
*/
+ _GLIBCXX20_CONSTEXPR
_Iterator&
base() _GLIBCXX_NOEXCEPT { return *this; }
+ _GLIBCXX20_CONSTEXPR
const _Iterator&
base() const _GLIBCXX_NOEXCEPT { return *this; }
@@ -366,6 +424,7 @@ namespace __gnu_debug
* @brief Conversion to underlying non-debug iterator to allow
* better interaction with non-debug containers.
*/
+ _GLIBCXX20_CONSTEXPR
operator _Iterator() const _GLIBCXX_NOEXCEPT { return *this; }
/** Attach iterator to the given sequence. */
@@ -440,6 +499,7 @@ namespace __gnu_debug
_M_get_distance_to_end() const;
/// Is this iterator equal to the sequence's begin() iterator?
+ _GLIBCXX20_CONSTEXPR
bool
_M_is_begin() const
{ return base() == _M_get_sequence()->_M_base().begin(); }
@@ -466,6 +526,7 @@ namespace __gnu_debug
typedef _Safe_iterator<_Iterator, _Sequence, iterator_category> _Self;
_GLIBCXX_NODISCARD
+ _GLIBCXX20_CONSTEXPR
friend bool
operator==(const _Self& __lhs, const _Self& __rhs) _GLIBCXX_NOEXCEPT
{
@@ -475,6 +536,7 @@ namespace __gnu_debug
template<typename _IteR>
_GLIBCXX_NODISCARD
+ _GLIBCXX20_CONSTEXPR
friend bool
operator==(const _Self& __lhs,
const _Safe_iterator<_IteR, _Sequence, iterator_category>& __rhs)
@@ -518,6 +580,7 @@ namespace __gnu_debug
typedef typename _Safe_base::_Unchecked _Unchecked;
+ _GLIBCXX20_CONSTEXPR
_Safe_iterator(const _Safe_iterator& __x,
_Unchecked __unchecked) _GLIBCXX_NOEXCEPT
: _Safe_base(__x, __unchecked)
@@ -525,6 +588,7 @@ namespace __gnu_debug
public:
/// @post the iterator is singular and unattached
+ _GLIBCXX20_CONSTEXPR
_Safe_iterator() _GLIBCXX_NOEXCEPT { }
/**
@@ -534,6 +598,7 @@ namespace __gnu_debug
* @pre @p seq is not NULL
* @post this is not singular
*/
+ _GLIBCXX20_CONSTEXPR
_Safe_iterator(_Iterator __i, const _Safe_sequence_base* __seq)
_GLIBCXX_NOEXCEPT
: _Safe_base(__i, __seq)
@@ -542,12 +607,14 @@ namespace __gnu_debug
/**
* @brief Copy construction.
*/
+ _GLIBCXX20_CONSTEXPR
_Safe_iterator(const _Safe_iterator& __x) _GLIBCXX_NOEXCEPT
: _Safe_base(__x)
{ }
#if __cplusplus >= 201103L
/** @brief Move construction. */
+ _GLIBCXX20_CONSTEXPR
_Safe_iterator(_Safe_iterator&&) = default;
#endif
@@ -556,6 +623,7 @@ namespace __gnu_debug
* constant iterator.
*/
template<typename _MutableIterator>
+ _GLIBCXX20_CONSTEXPR
_Safe_iterator(
const _Safe_iterator<_MutableIterator, _Sequence,
typename __gnu_cxx::__enable_if<_Safe_base::_IsConstant::__value &&
@@ -588,6 +656,7 @@ namespace __gnu_debug
* @brief Iterator preincrement
* @pre iterator is incrementable
*/
+ _GLIBCXX20_CONSTEXPR
_Safe_iterator&
operator++() _GLIBCXX_NOEXCEPT
{
@@ -615,9 +684,16 @@ namespace __gnu_debug
* @brief Iterator predecrement
* @pre iterator is decrementable
*/
+ _GLIBCXX20_CONSTEXPR
_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"));
@@ -663,6 +739,8 @@ namespace __gnu_debug
std::random_access_iterator_tag> _OtherSelf;
typedef typename _Safe_base::_Unchecked _Unchecked;
+
+ _GLIBCXX20_CONSTEXPR
_Safe_iterator(const _Safe_iterator& __x,
_Unchecked __unchecked) _GLIBCXX_NOEXCEPT
: _Safe_base(__x, __unchecked)
@@ -673,6 +751,7 @@ namespace __gnu_debug
typedef typename _Safe_base::reference reference;
/// @post the iterator is singular and unattached
+ _GLIBCXX20_CONSTEXPR
_Safe_iterator() _GLIBCXX_NOEXCEPT { }
/**
@@ -682,6 +761,7 @@ namespace __gnu_debug
* @pre @p seq is not NULL
* @post this is not singular
*/
+ _GLIBCXX20_CONSTEXPR
_Safe_iterator(_Iterator __i, const _Safe_sequence_base* __seq)
_GLIBCXX_NOEXCEPT
: _Safe_base(__i, __seq)
@@ -690,6 +770,7 @@ namespace __gnu_debug
/**
* @brief Copy construction.
*/
+ _GLIBCXX20_CONSTEXPR
_Safe_iterator(const _Safe_iterator& __x) _GLIBCXX_NOEXCEPT
: _Safe_base(__x)
{ }
@@ -704,6 +785,7 @@ namespace __gnu_debug
* constant iterator.
*/
template<typename _MutableIterator>
+ _GLIBCXX20_CONSTEXPR
_Safe_iterator(
const _Safe_iterator<_MutableIterator, _Sequence,
typename __gnu_cxx::__enable_if<_Safe_base::_IsConstant::__value &&
@@ -742,6 +824,7 @@ namespace __gnu_debug
* @brief Iterator preincrement
* @pre iterator is incrementable
*/
+ _GLIBCXX20_CONSTEXPR
_Safe_iterator&
operator++() _GLIBCXX_NOEXCEPT
{
@@ -753,12 +836,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;
@@ -769,6 +856,7 @@ namespace __gnu_debug
* @brief Iterator predecrement
* @pre iterator is decrementable
*/
+ _GLIBCXX20_CONSTEXPR
_Safe_iterator&
operator--() _GLIBCXX_NOEXCEPT
{
@@ -780,12 +868,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;
@@ -793,19 +885,30 @@ namespace __gnu_debug
// ------ Random access iterator requirements ------
_GLIBCXX_NODISCARD
+ _GLIBCXX20_CONSTEXPR
reference
operator[](difference_type __n) const _GLIBCXX_NOEXCEPT
{
- _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));
+ 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));
+ }
return this->base()[__n];
}
+ _GLIBCXX20_CONSTEXPR
_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));
@@ -814,9 +917,16 @@ namespace __gnu_debug
return *this;
}
+ _GLIBCXX20_CONSTEXPR
_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));
@@ -827,6 +937,7 @@ namespace __gnu_debug
#if __cpp_lib_three_way_comparison
[[nodiscard]]
+ _GLIBCXX20_CONSTEXPR
friend auto
operator<=>(const _Self& __lhs, const _Self& __rhs) noexcept
{
@@ -835,6 +946,7 @@ namespace __gnu_debug
}
[[nodiscard]]
+ _GLIBCXX20_CONSTEXPR
friend auto
operator<=>(const _Self& __lhs, const _OtherSelf& __rhs) noexcept
{
@@ -912,6 +1024,7 @@ namespace __gnu_debug
// operators but also operator- must accept mixed iterator/const_iterator
// parameters.
_GLIBCXX_NODISCARD
+ _GLIBCXX20_CONSTEXPR
friend difference_type
operator-(const _Self& __lhs, const _OtherSelf& __rhs) _GLIBCXX_NOEXCEPT
{
@@ -920,6 +1033,7 @@ namespace __gnu_debug
}
_GLIBCXX_NODISCARD
+ _GLIBCXX20_CONSTEXPR
friend difference_type
operator-(const _Self& __lhs, const _Self& __rhs) _GLIBCXX_NOEXCEPT
{
@@ -928,32 +1042,44 @@ namespace __gnu_debug
}
_GLIBCXX_NODISCARD
+ _GLIBCXX20_CONSTEXPR
friend _Self
operator+(const _Self& __x, difference_type __n) _GLIBCXX_NOEXCEPT
{
- _GLIBCXX_DEBUG_VERIFY(__x._M_can_advance(__n),
- _M_message(__msg_advance_oob)
- ._M_iterator(__x)._M_integer(__n));
+ if (!std::__is_constant_evaluated())
+ {
+ _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);
}
_GLIBCXX_NODISCARD
+ _GLIBCXX20_CONSTEXPR
friend _Self
operator+(difference_type __n, const _Self& __x) _GLIBCXX_NOEXCEPT
{
- _GLIBCXX_DEBUG_VERIFY(__x._M_can_advance(__n),
- _M_message(__msg_advance_oob)
- ._M_iterator(__x)._M_integer(__n));
+ if (!std::__is_constant_evaluated())
+ {
+ _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);
}
_GLIBCXX_NODISCARD
+ _GLIBCXX20_CONSTEXPR
friend _Self
operator-(const _Self& __x, difference_type __n) _GLIBCXX_NOEXCEPT
{
- _GLIBCXX_DEBUG_VERIFY(__x._M_can_advance(-__n),
- _M_message(__msg_retreat_oob)
- ._M_iterator(__x)._M_integer(__n));
+ if (!std::__is_constant_evaluated())
+ {
+ _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);
}
};
@@ -236,6 +236,7 @@ namespace std _GLIBCXX_VISIBILITY(default)
_GLIBCXX_BEGIN_NAMESPACE_VERSION
template<typename _Ite, typename _Seq>
+ _GLIBCXX20_CONSTEXPR
_Ite
__niter_base(const ::__gnu_debug::_Safe_iterator<_Ite, _Seq,
std::random_access_iterator_tag>& __it)
@@ -243,6 +244,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
template<bool _IsMove,
typename _Ite, typename _Seq, typename _Cat, typename _OI>
+ _GLIBCXX20_CONSTEXPR
_OI
__copy_move_a(
const ::__gnu_debug::_Safe_iterator<_Ite, _Seq, _Cat>& __first,
@@ -262,6 +264,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
template<bool _IsMove,
typename _II, typename _Ite, typename _Seq, typename _Cat>
+ _GLIBCXX20_CONSTEXPR
__gnu_debug::_Safe_iterator<_Ite, _Seq, _Cat>
__copy_move_a(_II __first, _II __last,
const ::__gnu_debug::_Safe_iterator<_Ite, _Seq, _Cat>& __result)
@@ -282,6 +285,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
template<bool _IsMove,
typename _IIte, typename _ISeq, typename _ICat,
typename _OIte, typename _OSeq, typename _OCat>
+ _GLIBCXX20_CONSTEXPR
::__gnu_debug::_Safe_iterator<_OIte, _OSeq, _OCat>
__copy_move_a(
const ::__gnu_debug::_Safe_iterator<_IIte, _ISeq, _ICat>& __first,
@@ -310,6 +314,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
template<bool _IsMove,
typename _Ite, typename _Seq, typename _Cat, typename _OI>
+ _GLIBCXX20_CONSTEXPR
_OI
__copy_move_backward_a(
const ::__gnu_debug::_Safe_iterator<_Ite, _Seq, _Cat>& __first,
@@ -329,6 +334,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
template<bool _IsMove,
typename _II, typename _Ite, typename _Seq, typename _Cat>
+ _GLIBCXX20_CONSTEXPR
__gnu_debug::_Safe_iterator<_Ite, _Seq, _Cat>
__copy_move_backward_a(_II __first, _II __last,
const ::__gnu_debug::_Safe_iterator<_Ite, _Seq, _Cat>& __result)
@@ -350,6 +356,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
template<bool _IsMove,
typename _IIte, typename _ISeq, typename _ICat,
typename _OIte, typename _OSeq, typename _OCat>
+ _GLIBCXX20_CONSTEXPR
::__gnu_debug::_Safe_iterator<_OIte, _OSeq, _OCat>
__copy_move_backward_a(
const ::__gnu_debug::_Safe_iterator<_IIte, _ISeq, _ICat>& __first,
@@ -377,6 +384,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
}
template<typename _Ite, typename _Seq, typename _Cat, typename _Tp>
+ _GLIBCXX20_CONSTEXPR
void
__fill_a(const ::__gnu_debug::_Safe_iterator<_Ite, _Seq, _Cat>& __first,
const ::__gnu_debug::_Safe_iterator<_Ite, _Seq, _Cat>& __last,
@@ -393,6 +401,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
template<typename _Ite, typename _Seq, typename _Cat, typename _Size,
typename _Tp>
+ _GLIBCXX20_CONSTEXPR
::__gnu_debug::_Safe_iterator<_Ite, _Seq, _Cat>
__fill_n_a(const ::__gnu_debug::_Safe_iterator<_Ite, _Seq, _Cat>& __first,
_Size __n, const _Tp& __value,
@@ -415,6 +424,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
}
template<typename _II1, typename _Seq1, typename _Cat1, typename _II2>
+ _GLIBCXX20_CONSTEXPR
bool
__equal_aux(
const ::__gnu_debug::_Safe_iterator<_II1, _Seq1, _Cat1>& __first1,
@@ -432,6 +442,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
}
template<typename _II1, typename _II2, typename _Seq2, typename _Cat2>
+ _GLIBCXX20_CONSTEXPR
bool
__equal_aux(_II1 __first1, _II1 __last1,
const ::__gnu_debug::_Safe_iterator<_II2, _Seq2, _Cat2>& __first2)
@@ -449,6 +460,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
template<typename _II1, typename _Seq1, typename _Cat1,
typename _II2, typename _Seq2, typename _Cat2>
+ _GLIBCXX20_CONSTEXPR
bool
__equal_aux(
const ::__gnu_debug::_Safe_iterator<_II1, _Seq1, _Cat1>& __first1,
@@ -473,6 +485,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
template<typename _Ite1, typename _Seq1, typename _Cat1,
typename _II2>
+ _GLIBCXX20_CONSTEXPR
bool
__lexicographical_compare_aux(
const ::__gnu_debug::_Safe_iterator<_Ite1, _Seq1, _Cat1>& __first1,
@@ -493,6 +506,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
template<typename _II1,
typename _Ite2, typename _Seq2, typename _Cat2>
+ _GLIBCXX20_CONSTEXPR
bool
__lexicographical_compare_aux(
_II1 __first1, _II1 __last1,
@@ -513,6 +527,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
template<typename _Ite1, typename _Seq1, typename _Cat1,
typename _Ite2, typename _Seq2, typename _Cat2>
+ _GLIBCXX20_CONSTEXPR
bool
__lexicographical_compare_aux(
const ::__gnu_debug::_Safe_iterator<_Ite1, _Seq1, _Cat1>& __first1,
@@ -55,22 +55,27 @@ namespace __gnu_debug
{
typedef typename _BaseSequence::size_type size_type;
+ _GLIBCXX20_CONSTEXPR
const _SafeSequence&
_M_seq() const { return *static_cast<const _SafeSequence*>(this); }
protected:
+ _GLIBCXX20_CONSTEXPR
_Safe_vector() _GLIBCXX_NOEXCEPT
: _M_guaranteed_capacity(0)
{ _M_update_guaranteed_capacity(); }
+ _GLIBCXX20_CONSTEXPR
_Safe_vector(const _Safe_vector&) _GLIBCXX_NOEXCEPT
: _M_guaranteed_capacity(0)
{ _M_update_guaranteed_capacity(); }
+ _GLIBCXX20_CONSTEXPR
_Safe_vector(size_type __n) _GLIBCXX_NOEXCEPT
: _M_guaranteed_capacity(__n)
{ }
+ _GLIBCXX20_CONSTEXPR
_Safe_vector&
operator=(const _Safe_vector&) _GLIBCXX_NOEXCEPT
{
@@ -79,10 +84,12 @@ namespace __gnu_debug
}
#if __cplusplus >= 201103L
+ _GLIBCXX20_CONSTEXPR
_Safe_vector(_Safe_vector&& __x) noexcept
: _Safe_vector()
{ __x._M_guaranteed_capacity = 0; }
+ _GLIBCXX20_CONSTEXPR
_Safe_vector&
operator=(_Safe_vector&& __x) noexcept
{
@@ -98,6 +105,7 @@ namespace __gnu_debug
_M_requires_reallocation(size_type __elements) const _GLIBCXX_NOEXCEPT
{ return __elements > _M_seq().capacity(); }
+ _GLIBCXX20_CONSTEXPR
void
_M_update_guaranteed_capacity() _GLIBCXX_NOEXCEPT
{
@@ -172,15 +180,18 @@ namespace __debug
vector() = default;
#endif
+ _GLIBCXX20_CONSTEXPR
explicit
vector(const _Allocator& __a) _GLIBCXX_NOEXCEPT
: _Base(__a) { }
#if __cplusplus >= 201103L
+ _GLIBCXX20_CONSTEXPR
explicit
vector(size_type __n, const _Allocator& __a = _Allocator())
: _Base(__n, __a), _Safe_vector(__n) { }
+ _GLIBCXX20_CONSTEXPR
vector(size_type __n, const __type_identity_t<_Tp>& __value,
const _Allocator& __a = _Allocator())
: _Base(__n, __value, __a) { }
@@ -197,10 +208,11 @@ namespace __debug
#else
template<class _InputIterator>
#endif
+ _GLIBCXX20_CONSTEXPR
vector(_InputIterator __first, _InputIterator __last,
const _Allocator& __a = _Allocator())
- : _Base(__gnu_debug::__base(
- __glibcxx_check_valid_constructor_range(__first, __last)),
+ : _Base(__gnu_debug::__base(std::__is_constant_evaluated() ? __first
+ : __glibcxx_check_valid_constructor_range(__first, __last)),
__gnu_debug::__base(__last), __a) { }
#if __cplusplus < 201103L
@@ -212,9 +224,11 @@ namespace __debug
vector(const vector&) = default;
vector(vector&&) = default;
+ _GLIBCXX20_CONSTEXPR
vector(const vector& __x, const __type_identity_t<allocator_type>& __a)
: _Base(__x, __a) { }
+ _GLIBCXX20_CONSTEXPR
vector(vector&& __x, const __type_identity_t<allocator_type>& __a)
noexcept(
std::is_nothrow_constructible<_Base,
@@ -223,6 +237,7 @@ namespace __debug
_Base(std::move(__x), __a),
_Safe_vector(std::move(__x)) { }
+ _GLIBCXX20_CONSTEXPR
vector(initializer_list<value_type> __l,
const allocator_type& __a = allocator_type())
: _Base(__l, __a) { }
@@ -231,6 +246,7 @@ namespace __debug
#endif
/// Construction from a normal-mode vector
+ _GLIBCXX20_CONSTEXPR
vector(_Base_ref __x)
: _Base(__x._M_ref) { }
@@ -241,12 +257,16 @@ namespace __debug
vector&
operator=(vector&&) = default;
+ _GLIBCXX20_CONSTEXPR
vector&
operator=(initializer_list<value_type> __l)
{
_Base::operator=(__l);
- this->_M_invalidate_all();
- this->_M_update_guaranteed_capacity();
+ if (!std::__is_constant_evaluated())
+ {
+ this->_M_invalidate_all();
+ this->_M_update_guaranteed_capacity();
+ }
return *this;
}
#endif
@@ -257,9 +277,14 @@ namespace __debug
#else
template<typename _InputIterator>
#endif
+ _GLIBCXX20_CONSTEXPR
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);
@@ -273,21 +298,29 @@ namespace __debug
this->_M_update_guaranteed_capacity();
}
+ _GLIBCXX20_CONSTEXPR
void
assign(size_type __n, const _Tp& __u)
{
_Base::assign(__n, __u);
- this->_M_invalidate_all();
- this->_M_update_guaranteed_capacity();
+ if (!std::__is_constant_evaluated())
+ {
+ this->_M_invalidate_all();
+ this->_M_update_guaranteed_capacity();
+ }
}
#if __cplusplus >= 201103L
+ _GLIBCXX20_CONSTEXPR
void
assign(initializer_list<value_type> __l)
{
_Base::assign(__l);
- this->_M_invalidate_all();
- this->_M_update_guaranteed_capacity();
+ if (!std::__is_constant_evaluated())
+ {
+ this->_M_invalidate_all();
+ this->_M_update_guaranteed_capacity();
+ }
}
#endif
@@ -295,62 +328,74 @@ namespace __debug
// iterators:
_GLIBCXX_NODISCARD
+ _GLIBCXX20_CONSTEXPR
iterator
begin() _GLIBCXX_NOEXCEPT
{ return iterator(_Base::begin(), this); }
_GLIBCXX_NODISCARD
+ _GLIBCXX20_CONSTEXPR
const_iterator
begin() const _GLIBCXX_NOEXCEPT
{ return const_iterator(_Base::begin(), this); }
_GLIBCXX_NODISCARD
+ _GLIBCXX20_CONSTEXPR
iterator
end() _GLIBCXX_NOEXCEPT
{ return iterator(_Base::end(), this); }
_GLIBCXX_NODISCARD
+ _GLIBCXX20_CONSTEXPR
const_iterator
end() const _GLIBCXX_NOEXCEPT
{ return const_iterator(_Base::end(), this); }
_GLIBCXX_NODISCARD
+ _GLIBCXX20_CONSTEXPR
reverse_iterator
rbegin() _GLIBCXX_NOEXCEPT
{ return reverse_iterator(end()); }
_GLIBCXX_NODISCARD
+ _GLIBCXX20_CONSTEXPR
const_reverse_iterator
rbegin() const _GLIBCXX_NOEXCEPT
{ return const_reverse_iterator(end()); }
_GLIBCXX_NODISCARD
+ _GLIBCXX20_CONSTEXPR
reverse_iterator
rend() _GLIBCXX_NOEXCEPT
{ return reverse_iterator(begin()); }
_GLIBCXX_NODISCARD
+ _GLIBCXX20_CONSTEXPR
const_reverse_iterator
rend() const _GLIBCXX_NOEXCEPT
{ return const_reverse_iterator(begin()); }
#if __cplusplus >= 201103L
[[__nodiscard__]]
+ _GLIBCXX20_CONSTEXPR
const_iterator
cbegin() const noexcept
{ return const_iterator(_Base::begin(), this); }
[[__nodiscard__]]
+ _GLIBCXX20_CONSTEXPR
const_iterator
cend() const noexcept
{ return const_iterator(_Base::end(), this); }
[[__nodiscard__]]
+ _GLIBCXX20_CONSTEXPR
const_reverse_iterator
crbegin() const noexcept
{ return const_reverse_iterator(end()); }
[[__nodiscard__]]
+ _GLIBCXX20_CONSTEXPR
const_reverse_iterator
crend() const noexcept
{ return const_reverse_iterator(begin()); }
@@ -361,9 +406,13 @@ namespace __debug
using _Base::max_size;
#if __cplusplus >= 201103L
+ _GLIBCXX20_CONSTEXPR
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);
@@ -373,9 +422,13 @@ namespace __debug
this->_M_update_guaranteed_capacity();
}
+ _GLIBCXX20_CONSTEXPR
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);
@@ -399,9 +452,13 @@ namespace __debug
#endif
#if __cplusplus >= 201103L
+ _GLIBCXX20_CONSTEXPR
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();
@@ -411,9 +468,13 @@ namespace __debug
#endif
_GLIBCXX_NODISCARD
+ _GLIBCXX20_CONSTEXPR
size_type
capacity() const _GLIBCXX_NOEXCEPT
{
+ if (std::__is_constant_evaluated())
+ return _Base::capacity();
+
#ifdef _GLIBCXX_DEBUG_PEDANTIC
return this->_M_guaranteed_capacity;
#else
@@ -423,9 +484,13 @@ namespace __debug
using _Base::empty;
+ _GLIBCXX20_CONSTEXPR
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)
@@ -436,6 +501,7 @@ namespace __debug
// element access:
_GLIBCXX_NODISCARD
+ _GLIBCXX20_CONSTEXPR
reference
operator[](size_type __n) _GLIBCXX_NOEXCEPT
{
@@ -444,6 +510,7 @@ namespace __debug
}
_GLIBCXX_NODISCARD
+ _GLIBCXX20_CONSTEXPR
const_reference
operator[](size_type __n) const _GLIBCXX_NOEXCEPT
{
@@ -454,6 +521,7 @@ namespace __debug
using _Base::at;
_GLIBCXX_NODISCARD
+ _GLIBCXX20_CONSTEXPR
reference
front() _GLIBCXX_NOEXCEPT
{
@@ -462,6 +530,7 @@ namespace __debug
}
_GLIBCXX_NODISCARD
+ _GLIBCXX20_CONSTEXPR
const_reference
front() const _GLIBCXX_NOEXCEPT
{
@@ -470,6 +539,7 @@ namespace __debug
}
_GLIBCXX_NODISCARD
+ _GLIBCXX20_CONSTEXPR
reference
back() _GLIBCXX_NOEXCEPT
{
@@ -478,6 +548,7 @@ namespace __debug
}
_GLIBCXX_NODISCARD
+ _GLIBCXX20_CONSTEXPR
const_reference
back() const _GLIBCXX_NOEXCEPT
{
@@ -490,9 +561,13 @@ namespace __debug
using _Base::data;
// 23.2.4.3 modifiers:
+ _GLIBCXX20_CONSTEXPR
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)
@@ -502,12 +577,14 @@ namespace __debug
#if __cplusplus >= 201103L
template<typename _Up = _Tp>
+ _GLIBCXX20_CONSTEXPR
typename __gnu_cxx::__enable_if<!std::__are_same<_Up, bool>::__value,
void>::__type
push_back(_Tp&& __x)
{ emplace_back(std::move(__x)); }
template<typename... _Args>
+ _GLIBCXX20_CONSTEXPR
#if __cplusplus > 201402L
reference
#else
@@ -515,6 +592,9 @@ 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)
@@ -526,19 +606,29 @@ namespace __debug
}
#endif
+ _GLIBCXX20_CONSTEXPR
void
pop_back() _GLIBCXX_NOEXCEPT
{
- __glibcxx_check_nonempty();
- this->_M_invalidate_if(_Equal(--_Base::end()));
+ if (!std::__is_constant_evaluated())
+ {
+ __glibcxx_check_nonempty();
+ this->_M_invalidate_if(_Equal(--_Base::end()));
+ }
_Base::pop_back();
}
#if __cplusplus >= 201103L
template<typename... _Args>
+ _GLIBCXX20_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);
bool __realloc = this->_M_requires_reallocation(this->size() + 1);
difference_type __offset = __position.base() - _Base::cbegin();
@@ -553,6 +643,7 @@ namespace __debug
}
#endif
+ _GLIBCXX20_CONSTEXPR
iterator
#if __cplusplus >= 201103L
insert(const_iterator __position, const _Tp& __x)
@@ -560,6 +651,9 @@ 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();
@@ -574,20 +668,26 @@ namespace __debug
#if __cplusplus >= 201103L
template<typename _Up = _Tp>
+ _GLIBCXX20_CONSTEXPR
typename __gnu_cxx::__enable_if<!std::__are_same<_Up, bool>::__value,
iterator>::__type
insert(const_iterator __position, _Tp&& __x)
{ return emplace(__position, std::move(__x)); }
+ _GLIBCXX20_CONSTEXPR
iterator
insert(const_iterator __position, initializer_list<value_type> __l)
{ return this->insert(__position, __l.begin(), __l.end()); }
#endif
#if __cplusplus >= 201103L
+ _GLIBCXX20_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);
bool __realloc = this->_M_requires_reallocation(this->size() + __n);
difference_type __offset = __position.base() - _Base::cbegin();
@@ -618,10 +718,16 @@ namespace __debug
#if __cplusplus >= 201103L
template<class _InputIterator,
typename = std::_RequireInputIter<_InputIterator>>
+ _GLIBCXX20_CONSTEXPR
iterator
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);
@@ -673,6 +779,7 @@ namespace __debug
}
#endif
+ _GLIBCXX20_CONSTEXPR
iterator
#if __cplusplus >= 201103L
erase(const_iterator __position)
@@ -680,6 +787,9 @@ 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());
@@ -687,6 +797,7 @@ namespace __debug
return iterator(__res, this);
}
+ _GLIBCXX20_CONSTEXPR
iterator
#if __cplusplus >= 201103L
erase(const_iterator __first, const_iterator __last)
@@ -694,6 +805,9 @@ 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);
@@ -714,25 +828,31 @@ namespace __debug
#endif
}
+ _GLIBCXX20_CONSTEXPR
void
swap(vector& __x)
_GLIBCXX_NOEXCEPT_IF( noexcept(declval<_Base&>().swap(__x)) )
{
- _Safe::_M_swap(__x);
+ if (!std::__is_constant_evaluated())
+ _Safe::_M_swap(__x);
_Base::swap(__x);
std::swap(this->_M_guaranteed_capacity, __x._M_guaranteed_capacity);
}
+ _GLIBCXX20_CONSTEXPR
void
clear() _GLIBCXX_NOEXCEPT
{
_Base::clear();
- this->_M_invalidate_all();
+ if (!std::__is_constant_evaluated())
+ this->_M_invalidate_all();
}
+ _GLIBCXX20_CONSTEXPR
_Base&
_M_base() _GLIBCXX_NOEXCEPT { return *this; }
+ _GLIBCXX20_CONSTEXPR
const _Base&
_M_base() const _GLIBCXX_NOEXCEPT { return *this; }
@@ -746,6 +866,7 @@ namespace __debug
};
template<typename _Tp, typename _Alloc>
+ _GLIBCXX20_CONSTEXPR
inline bool
operator==(const vector<_Tp, _Alloc>& __lhs,
const vector<_Tp, _Alloc>& __rhs)
@@ -789,6 +910,7 @@ namespace __debug
#endif // three-way comparison
template<typename _Tp, typename _Alloc>
+ _GLIBCXX20_CONSTEXPR
inline void
swap(vector<_Tp, _Alloc>& __lhs, vector<_Tp, _Alloc>& __rhs)
_GLIBCXX_NOEXCEPT_IF(noexcept(__lhs.swap(__rhs)))
@@ -1,5 +1,4 @@
// { dg-do compile { target c++20 } }
-// { dg-xfail-if "not supported" { debug_mode } }
#include <vector>
#include <testsuite_hooks.h>
@@ -16,7 +16,6 @@
// <http://www.gnu.org/licenses/>.
// { dg-do compile { target c++20 } }
-// { dg-xfail-if "not supported" { debug_mode } }
#include <vector>
#include <testsuite_hooks.h>
@@ -1,5 +1,4 @@
// { dg-do compile { target c++20 } }
-// { dg-xfail-if "not supported" { debug_mode } }
#include <vector>
#include <testsuite_hooks.h>
@@ -1,5 +1,4 @@
// { dg-do compile { target c++23 } }
-// { dg-xfail-if "not supported" { debug_mode } }
#include <vector>
#include <testsuite_hooks.h>
@@ -1,5 +1,4 @@
// { dg-do compile { target c++20 } }
-// { dg-xfail-if "not supported" { debug_mode } }
#include <vector>
#include <testsuite_hooks.h>
@@ -1,5 +1,4 @@
// { dg-do compile { target c++20 } }
-// { dg-xfail-if "not supported" { debug_mode } }
#include <vector>
#include <testsuite_hooks.h>
@@ -1,5 +1,4 @@
// { dg-do compile { target c++20 } }
-// { dg-xfail-if "not supported" { debug_mode } }
#include <vector>
#include <testsuite_hooks.h>
@@ -1,5 +1,4 @@
// { dg-do compile { target c++20 } }
-// { dg-xfail-if "not supported" { debug_mode } }
#include <vector>
#include <utility>
@@ -49,6 +48,7 @@ test_member_swap()
static_assert(test_member_swap());
+#ifndef _GLIBCXX_DEBUG
constexpr bool
test_reference_swap()
{
@@ -63,3 +63,4 @@ test_reference_swap()
}
static_assert(test_reference_swap());
+#endif
@@ -1,5 +1,4 @@
// { dg-do compile { target c++20 } }
-// { dg-xfail-if "not supported" { debug_mode } }
#include <vector>
#include <testsuite_hooks.h>
@@ -16,7 +16,6 @@
// <http://www.gnu.org/licenses/>.
// { dg-do compile { target c++20 } }
-// { dg-xfail-if "not supported" { debug_mode } }
#include <vector>
#include <testsuite_hooks.h>
@@ -1,6 +1,5 @@
// { dg-do compile { target c++20 } }
// { dg-add-options no_pch }
-// { dg-xfail-if "not supported" { debug_mode } }
#include <vector>
@@ -1,5 +1,4 @@
// { dg-do compile { target c++20 } }
-// { dg-xfail-if "not supported" { debug_mode } }
#include <vector>
#include <testsuite_hooks.h>
@@ -1,5 +1,4 @@
// { dg-do compile { target c++20 } }
-// { dg-xfail-if "not supported" { debug_mode } }
#include <vector>
#include <testsuite_hooks.h>
@@ -1,5 +1,4 @@
// { dg-do compile { target c++20 } }
-// { dg-xfail-if "not supported" { debug_mode } }
#include <vector>
#include <testsuite_hooks.h>
@@ -1,5 +1,4 @@
// { dg-do compile { target c++20 } }
-// { dg-xfail-if "not supported" { debug_mode } }
#include <vector>
#include <testsuite_hooks.h>
@@ -1,5 +1,4 @@
// { dg-do compile { target c++20 } }
-// { dg-xfail-if "not supported" { debug_mode } }
#include <vector>
#include <utility>