Replied below, here is the new ChangeLog:
libstdc++: [_GLIBCXX_DEBUG] Implement std::__debug::inplace_vector
Add _GLIBCXX_DEBUG std::inplace_vector implementation.
libstdc++-v3/ChangeLog:
* include/Makefile.am (debug_headers): Add inplace_vector.
* include/Makefile.in: Regenerate.
* include/debug/functions.h (__check_valid_range): Add
C++20 constexpr.
* include/debug/helper_functions.h (__valid_range): Likewise.
* include/debug/inplace_vector: New.
* include/debug/safe_base.h (~_Safe_sequence_base()): Add
C++11 noexcept.
(_Safe_sequence_base::operator=(const
_Safe_sequence_base&)): New.
(_Safe_sequence_base::operator=(_Safe_sequence_base&&)): New.
(_Safe_sequence_base::_M_invalidate_all): Add C++20 constexpr.
* include/debug/safe_container.h
(_Safe_container<>::operator=(const _Safe_container<>&)):
Implement using
_Safe_sequence_base same operator.
* include/debug/safe_iterator.h (__valid_range): Add C++20
constexpr.
* include/debug/safe_sequence.h
(_Not_equal_to(const _Type&)): Add C++20 constexpr.
(_Equal_to(const _Type&)): Add C++20 constexpr.
(_After_nth_from(const difference_type&, const
_Iterator&)): Add C++20 constexpr.
(_Safe_sequence<>::_M_invalidate_if): Add C++20 constexpr.
(_Safe_node_sequence::operator=(const
_Safe_node_sequence&)): New.
(_Safe_node_sequence::operator=(_Safe_node_sequence&&)): New.
(_Safe_node_sequence<>::_M_invalidate_all()): Add C++20
constexpr.
* include/debug/safe_sequence.tcc
(_Safe_sequence<>::_M_invalidate_if): Add C++20 constexpr.
* include/debug/safe_container.h
(_Safe_container::operator=(const _Safe_container&)):
Implement using same
_Safe_sequence_base operator.
* include/std/inplace_vector
[_GLIBCXX_DEBUG](std::inplace_vector<>): Move
implementation into __cxx1998 namespace.
(erase, erase_if): Limit to non-debug inplace_vector<>,
cleanup code.
[_GLIBCXX_DEBUG]: Add include <debug/inplace_vector>.
* testsuite/23_containers/inplace_vector/cons/1.cc: Adapt,
skip several
is_trivially_xxx checks when in _GLIBCXX_DEBUG mode.
* testsuite/23_containers/inplace_vector/copy.cc: Likewise.
* testsuite/23_containers/inplace_vector/move.cc: Likewise.
*
testsuite/23_containers/inplace_vector/debug/assign1_neg.cc: New test case.
*
testsuite/23_containers/inplace_vector/debug/assign2_neg.cc: New test case.
*
testsuite/23_containers/inplace_vector/debug/assign3_neg.cc: New test case.
*
testsuite/23_containers/inplace_vector/debug/assign4_backtrace_neg.cc:
New test case.
*
testsuite/23_containers/inplace_vector/debug/assign4_neg.cc: New test case.
*
testsuite/23_containers/inplace_vector/debug/construct1_neg.cc: New test
case.
*
testsuite/23_containers/inplace_vector/debug/construct2_neg.cc: New test
case.
*
testsuite/23_containers/inplace_vector/debug/construct3_neg.cc: New test
case.
*
testsuite/23_containers/inplace_vector/debug/construct4_neg.cc: New test
case.
*
testsuite/23_containers/inplace_vector/debug/debug_functions.cc: New
test case.
* testsuite/23_containers/inplace_vector/debug/erase.cc:
New test case.
*
testsuite/23_containers/inplace_vector/debug/insert1_neg.cc: New test case.
*
testsuite/23_containers/inplace_vector/debug/insert2_neg.cc: New test case.
*
testsuite/23_containers/inplace_vector/debug/insert3_neg.cc: New test case.
*
testsuite/23_containers/inplace_vector/debug/insert4_neg.cc: New test case.
*
testsuite/23_containers/inplace_vector/debug/insert5_neg.cc: New test case.
*
testsuite/23_containers/inplace_vector/debug/insert7_neg.cc: New test case.
*
testsuite/23_containers/inplace_vector/debug/invalidation/1.cc: New test
case.
*
testsuite/23_containers/inplace_vector/debug/invalidation/2.cc: New test
case.
*
testsuite/23_containers/inplace_vector/debug/invalidation/3.cc: New test
case.
*
testsuite/23_containers/inplace_vector/debug/invalidation/4.cc: New test
case.
*
testsuite/23_containers/inplace_vector/debug/invalidation/append_range.cc:
New test case.
*
testsuite/23_containers/inplace_vector/debug/invalidation/erase.cc: New
test case.
*
testsuite/23_containers/inplace_vector/debug/invalidation/pop_back.cc:
New test case.
*
testsuite/23_containers/inplace_vector/debug/invalidation/push_back.cc:
New test case.
*
testsuite/23_containers/inplace_vector/debug/invalidation/swap.cc: New
test case.
*
testsuite/23_containers/inplace_vector/debug/invalidation/try_append_range.cc:
New test case.
*
testsuite/23_containers/inplace_vector/debug/invalidation/try_emplace_back.cc:
New test case.
*
testsuite/23_containers/inplace_vector/debug/invalidation/try_push_back.cc:
New test case.
*
testsuite/23_containers/inplace_vector/debug/invalidation/unchecked_emplace_back.cc:
New test case.
* testsuite/util/debug/checks.h: Avoid using _GLIBCXX_DEBUG
containers in test
implementations.
PR updated:
https://forge.sourceware.org/gcc/gcc-TEST/pulls/119
François
On 11/13/25 12:08, Jonathan Wakely wrote:
On Thu, 06 Nov 2025 at 21:52 +0100, François Dumont wrote:
I just updated the PR to remove the multithreaded_swap.cc test that I
had copied from the vector tests but had no meaning for the
inplace_vector.
François
[...]
diff --git a/libstdc++-v3/include/Makefile.am
b/libstdc++-v3/include/Makefile.am
index ae7a7ca9073..7d65c6f3ab3 100644
--- a/libstdc++-v3/include/Makefile.am
+++ b/libstdc++-v3/include/Makefile.am
@@ -971,6 +971,7 @@ debug_headers = \
${debug_srcdir}/forward_list \
${debug_srcdir}/functions.h \
${debug_srcdir}/helper_functions.h \
+ ${debug_srcdir}/inplace_vector \
${debug_srcdir}/list \
${debug_srcdir}/map \
${debug_srcdir}/macros.h \
diff --git a/libstdc++-v3/include/Makefile.in
b/libstdc++-v3/include/Makefile.in
index f07e2326816..acf8ae9be44 100644
--- a/libstdc++-v3/include/Makefile.in
+++ b/libstdc++-v3/include/Makefile.in
@@ -1308,6 +1308,7 @@ debug_freestanding = \
@GLIBCXX_HOSTED_TRUE@ ${debug_srcdir}/forward_list \
@GLIBCXX_HOSTED_TRUE@ ${debug_srcdir}/functions.h \
@GLIBCXX_HOSTED_TRUE@ ${debug_srcdir}/helper_functions.h \
+@GLIBCXX_HOSTED_TRUE@ ${debug_srcdir}/inplace_vector \
@GLIBCXX_HOSTED_TRUE@ ${debug_srcdir}/list \
@GLIBCXX_HOSTED_TRUE@ ${debug_srcdir}/map \
@GLIBCXX_HOSTED_TRUE@ ${debug_srcdir}/macros.h \
diff --git a/libstdc++-v3/include/debug/inplace_vector
b/libstdc++-v3/include/debug/inplace_vector
new file mode 100644
index 00000000000..ae28717a98d
--- /dev/null
+++ b/libstdc++-v3/include/debug/inplace_vector
@@ -0,0 +1,737 @@
+// Debugging inplace_vector implementation -*- C++ -*-
+
+// Copyright The GNU Toolchain Authors.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License
and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively. If not,
see
+// <http://www.gnu.org/licenses/>.
+
+/** @file debug/inplace_vector
+ * This file is a GNU debug extension to the Standard C++ Library.
+ */
+
+#ifndef _GLIBCXX_DEBUG_INPLACE_VECTOR
+#define _GLIBCXX_DEBUG_INPLACE_VECTOR 1
+
+#ifdef _GLIBCXX_SYSHDR
+#pragma GCC system_header
+#endif
+
+#include <debug/debug.h>
+
+namespace std _GLIBCXX_VISIBILITY(default) { namespace __debug {
+ template<typename _Tp, size_t _Nm> class inplace_vector;
+} } // namespace std::__debug
I was concerned that this declaration isn't guarded by any
preprocessor check, so the name 'inplace_vector' is declared
inconditionally even in older standards where it's not a reserved
name. But I think it's only a problem if people explicitly include
<debug/inplace_vector>, in which case it's their own fault. They
included a non-standard header so it's OK to declare the name.
And this is how we already do it in <debug/forward_list> and
<debug/array> and <debug/unordered_xxx> too, so it's fine.
+
+#include <inplace_vector>
+
+#ifdef __glibcxx_inplace_vector // C++ >= 26
+
+#include <debug/safe_sequence.h>
+#include <debug/safe_iterator.h>
+
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+namespace __debug
+{
+ /// Class std::inplace_vector with safety/checking/debug
instrumentation.
+ template<typename _Tp, size_t _Nm>
+ class inplace_vector
+ : private __gnu_debug::_Safe_sequence<inplace_vector<_Tp, _Nm>>
+ , private _GLIBCXX_STD_C::inplace_vector<_Tp, _Nm>
+ {
+ using _Base = _GLIBCXX_STD_C::inplace_vector<_Tp, _Nm>;
+ using _Base_iterator = typename _Base::iterator;
+ using _Base_const_iterator = typename _Base::const_iterator;
+ using _Equal = __gnu_debug::_Equal_to<_Base_const_iterator>;
+
+ template<typename _ItT, typename _SeqT, typename _CatT>
+ friend class ::__gnu_debug::_Safe_iterator;
+
+ public:
+
+ // types:
+ using value_type = _Base::value_type;
+ using pointer = _Base::pointer;
+ using const_pointer = _Base::const_pointer;
+ using reference = _Base::reference;
+ using const_reference = _Base::const_reference;
+ using size_type = _Base::size_type;
+ using difference_type = _Base::difference_type;
+ using iterator
+ = __gnu_debug::_Safe_iterator<_Base_iterator, inplace_vector>;
+ using const_iterator
+ = __gnu_debug::_Safe_iterator<_Base_const_iterator,
inplace_vector>;
+ using reverse_iterator = std::reverse_iterator<iterator>;
+ using const_reverse_iterator =
std::reverse_iterator<const_iterator>;
+
+ constexpr
+ inplace_vector() noexcept = default;
+
+ constexpr explicit
+ inplace_vector(size_type __n)
+ : _Base(__n) { }
+
+ constexpr
+ inplace_vector(size_type __n, const _Tp& __value)
+ : _Base(__n, __value) { }
+
+ template<__any_input_iterator _InputIterator>
+ constexpr
+ inplace_vector(_InputIterator __first, _InputIterator __last)
+ : _Base(__gnu_debug::__base(std::is_constant_evaluated() ? __first
+ : __glibcxx_check_valid_constructor_range(__first, __last)),
+ __gnu_debug::__base(__last)) { }
+
+ template<__detail::__container_compatible_range<_Tp> _Rg>
+ constexpr
+ inplace_vector(from_range_t, _Rg&& __rg)
+ : _Base(from_range_t{}, std::forward<_Rg>(__rg)) { }
+
+ constexpr
+ inplace_vector(initializer_list<_Tp> __il)
+ : _Base(__il) { }
+
+ inplace_vector(const inplace_vector&)
+ requires is_trivially_copy_constructible_v<_Tp>
+ = default;
+
+ constexpr
+ inplace_vector(const inplace_vector&)
+ noexcept(is_nothrow_copy_constructible_v<_Tp>)
+ = default;
Both copy constructors are defined as defaulted, so do we need the one
constrained with is_trivially_copy_constructible_v?
Can't we just have the unconstrained one?
And we don't need the noexcept-specifier, that will be deduced from
the base class constructor. And 'constexpr' will be defaulted too.
So just:
inplace_vector(const inplace_vector&) = default;
+ inplace_vector(inplace_vector&&)
+ requires is_trivially_move_constructible_v<_Tp>
+ = default;
+
+ constexpr
+ inplace_vector(inplace_vector&&)
+ noexcept(is_nothrow_move_constructible_v<_Tp>)
+ = default;
Similarly:
inplace_vector(inplace_vector&&) = default;
+
+ ~inplace_vector()
+ requires is_trivially_destructible_v<_Tp>
+ = default;
+
+ constexpr
+ ~inplace_vector() = default;
And again:
~inplace_vector() = default;
+
+ inplace_vector&
+ operator=(const inplace_vector&)
+ requires is_trivially_copy_assignable_v<_Tp>
+ && is_trivially_copy_constructible_v<_Tp>
+ && is_trivially_destructible_v<_Tp>
+ = default;
+
+ constexpr inplace_vector&
+ operator=(const inplace_vector&)
+ noexcept(is_nothrow_copy_assignable_v<_Tp>
+ && is_nothrow_copy_constructible_v<_Tp>)
+ = default;
+
+ inplace_vector&
+ operator=(inplace_vector&&)
+ requires is_trivially_move_assignable_v<_Tp>
+ && is_trivially_move_constructible_v<_Tp>
+ && is_trivially_destructible_v<_Tp>
+ = default;
+
+ constexpr inplace_vector&
+ operator=(inplace_vector&&)
+ noexcept(is_nothrow_move_assignable_v<_Tp>
+ && is_nothrow_move_constructible_v<_Tp>)
+ = default;
And for the assignments too.
Or am I missing something why these are all needed?
No, I just started to write this class by copy/paste the normal
implementation and adapted the methods needing debug assertions. I
didn't consider that all those could be simplified indeed.
+ constexpr inplace_vector&
+ operator=(initializer_list<_Tp> __il)
+ {
+ _Base::operator=(__il);
+ this->_M_invalidate_all();
+ return *this;
+ }
+
+ template<__any_input_iterator _InputIterator>
+ constexpr void
+ assign(_InputIterator __first, _InputIterator __last)
+ {
+ using namespace __gnu_debug;
+ if (std::is_constant_evaluated())
+ return _Base::assign(__unsafe(__first), __unsafe(__last));
Calling __unsafe unqualified will do ADL, it would be better to use
__gnu_debug::__unsafe here.
Right, fixed.
+
+ typename _Distance_traits<_InputIterator>::__type __dist;
+ __glibcxx_check_valid_range2(__first, __last, __dist);
+
+ if (__dist.second >= __dp_sign)
+ _Base::assign(__unsafe(__first), __unsafe(__last));
+ else
+ _Base::assign(__first, __last);
+
+ this->_M_invalidate_all();
Is it too aggressive to invalidate all iterators?
I know the generic Sequence requirements say that assign(i, j)
invalidates all iterators, but I think maybe that's a defect.
The storage is never invalidated for inplace_vector, so we only
invalidate iterators if they point to elements which were destroyed
because the new size is smaller than the old size.
Let's leave it this way for now, and I'll discuss it with the
committee.
I might have had misinterpreted the section about iterator invalidation
here:
https://cppreference.net/cpp/container/inplace_vector.html
As std::swap is invalidating all iterators I considered that as soon as
iterator value had a chance to be changed then iterator should be
invalidated.
But below it is said that assign can potentially invalidate iterators so
I think it should rather follow what has been done for std::vector when
no reallocation is taking place.
+ }
+
+ template<__detail::__container_compatible_range<_Tp> _Rg>
+ constexpr void
+ assign_range(_Rg&& __rg)
+ {
+ _Base::assign_range(std::forward<_Rg>(__rg));
+ this->_M_invalidate_all();
+ }
+
+ constexpr void
+ assign(size_type __n, const _Tp& __u)
+ {
+ _Base::assign(__n, __u);
+ this->_M_invalidate_all();
+ }
+
+ constexpr void
+ assign(initializer_list<_Tp> __il)
+ {
+ _Base::assign(__il);
+ this->_M_invalidate_all();
+ }
+
+ // iterators
+ [[nodiscard]]
+ constexpr iterator
+ begin() noexcept
+ { return { _Base::begin(), this }; }
+
+ [[nodiscard]]
+ constexpr const_iterator
+ begin() const noexcept
+ { return { _Base::begin(), this }; }
+
+ [[nodiscard]]
+ constexpr iterator
+ end() noexcept
+ { return { _Base::end(), this }; }
+
+ [[nodiscard]]
+ constexpr const_iterator
+ end() const noexcept
+ { return { _Base::end(), this }; }
+
+ [[nodiscard]]
+ constexpr reverse_iterator
+ rbegin() noexcept
+ { return reverse_iterator(end()); }
+
+ [[nodiscard]]
+ constexpr const_reverse_iterator
+ rbegin() const noexcept
+ { return const_reverse_iterator(end()); }
+
+ [[nodiscard]]
+ constexpr reverse_iterator
+ rend() noexcept { return reverse_iterator(begin()); }
+
+ [[nodiscard]]
+ constexpr const_reverse_iterator
+ rend() const noexcept { return const_reverse_iterator(begin()); }
+
+ [[nodiscard]]
+ constexpr const_iterator
+ cbegin() const noexcept
+ { return { _Base::cbegin(), this }; }
+
+ [[nodiscard]]
+ constexpr const_iterator
+ cend() const noexcept
+ { return { _Base::cend(), this }; }
+
+ [[nodiscard]]
+ constexpr const_reverse_iterator
+ crbegin() const noexcept { return rbegin(); }
+
+ [[nodiscard]]
+ constexpr const_reverse_iterator
+ crend() const noexcept { return rend(); }
+
+ using _Base::empty;
+ using _Base::size;
+ using _Base::max_size;
+ using _Base::capacity;
+
+ constexpr void
+ resize(size_type __n)
+ {
+ _Base::resize(__n);
+ _M_invalidate_after_nth(__n);
+ }
+
+ constexpr void
+ resize(size_type __n, const _Tp& __c)
+ {
+ _Base::resize(__n, __c);
+ _M_invalidate_after_nth(__n);
+ }
+
+ using _Base::reserve;
+ using _Base::shrink_to_fit;
+
+ // element access
+ [[nodiscard]]
+ constexpr reference
+ operator[](size_type __n)
+ {
+ __glibcxx_check_subscript(__n);
+ return _Base::operator[](__n);
+ }
+
+ [[nodiscard]]
+ constexpr const_reference
+ operator[](size_type __n) const
+ {
+ __glibcxx_check_subscript(__n);
+ return _Base::operator[](__n);
Thanks for explaining why we want the check here (so that we do the
checks for __gnu_debug::inplace_vector even when _GLIBCXX_DEBUG isn't
defined).
It occurs to me that we avoid checking the assertion again in the base
class by doing:
return data()[__n];
We could also make that change in __gnu_debug::vector and deque.
It's not critical though; optimizing performance for the debug
containers is nice, but not essential.
It could be managed with a new set of macros defined only when
_GLIBCXX_ASSERTIONS is not defined and so checking only when directly
using the __gnu_debug containers.
I'll see if there's something to do here.
+ }
+
+ using _Base::at;
+
+ [[nodiscard]]
+ constexpr reference
+ front()
+ {
+ __glibcxx_check_nonempty();
+ return _Base::front();
And this could be return data()[0];
I usually prefer to have _GLIBCXX_DEBUG implementation call normal
implementation but as we avoid a redundant check let's do it this way.
+ }
+
+ [[nodiscard]]
+ constexpr const_reference
+ front() const
+ {
+ __glibcxx_check_nonempty();
+ return _Base::front();
+ }
+
+ [[nodiscard]]
+ constexpr reference
+ back()
+ {
+ __glibcxx_check_nonempty();
+ return _Base::back();
And return data()[size() - 1];
Ok
+ }
+
+ [[nodiscard]]
+ constexpr const_reference
+ back() const
+ {
+ __glibcxx_check_nonempty();
+ return _Base::back();
+ }
+
+ using _Base::data;
+
+ template<typename... _Args>
+ constexpr _Tp&
+ emplace_back(_Args&&... __args)
+ {
+ auto __end = _Base::cend();
+ _Tp& __res =
_Base::emplace_back(std::forward<_Args>(__args)...);
+
+ if (!std::is_constant_evaluated())
+ this->_M_invalidate_if(_Equal(__end));
Is this correct? The end iterator would no longer be a past-the-end
iterator, but does it need to be invalidated?
IMHO yes, if a user captured the end iterator and keeps on using it as
such it's wrong. So better invalidate it when it's not the end iterator
anymore.
cppreference.com is also saying that this method can invalidate the end
iterator only.
For __gnu_debug::vector we only invalidate any iterators if storage is
reallocated (but maybe I got that wrong when I added append_range to
the debug vector).
+
+ return __res;
+ }
+
+ constexpr _Tp&
+ push_back(const _Tp& __x)
+ { return emplace_back(__x); }
+
+ constexpr _Tp&
+ push_back(_Tp&& __x)
+ { return emplace_back(std::move(__x)); }
+
+ template<__detail::__container_compatible_range<_Tp> _Rg>
+ constexpr void
+ append_range(_Rg&& __rg)
+ {
+ const auto __size = size();
+ _Base::append_range(__rg);
+ if (size() != __size)
+ _M_invalidate_after_nth(__size);
Why is this different from emplace_back?
The only iterators after the old size are past-the-end iterators,
which could be invalidated with _M_invalidate_if(_Equal(__end)),
right?
The same question applies here though: do we need to invalidate the
past-the-end iterator at all?
+ }
+
+ constexpr void
+ pop_back()
+ {
+ __glibcxx_check_nonempty();
+ _M_invalidate_after_nth(_Base::size() - 1);
+ _Base::pop_back();
+ }
+
+ template<typename... _Args>
+ constexpr _Tp*
+ try_emplace_back(_Args&&... __args)
+ {
+ auto __end = _Base::cend();
+ _Tp* __res =
_Base::try_emplace_back(std::forward<_Args>(__args)...);
+
+ if (!std::is_constant_evaluated() && __res)
+ this->_M_invalidate_if(_Equal(__end));
+
+ return __res;
+ }
+
+ constexpr _Tp*
+ try_push_back(const _Tp& __x)
+ {
+ auto __end = _Base::cend();
+ _Tp* __res = _Base::try_push_back(__x);
+
+ if (!std::is_constant_evaluated() && __res)
+ this->_M_invalidate_if(_Equal(__end));
+
+ return __res;
+ }
+
+ constexpr _Tp*
+ try_push_back(_Tp&& __x)
+ {
+ auto __end = _Base::cend();
+ _Tp* __res = _Base::try_push_back(std::move(__x));
+
+ if (!std::is_constant_evaluated() && __res)
+ this->_M_invalidate_if(_Equal(__end));
+
+ return __res;
+ }
+
+ template<__detail::__container_compatible_range<_Tp> _Rg>
+ constexpr ranges::borrowed_iterator_t<_Rg>
+ try_append_range(_Rg&& __rg)
+ {
+ const auto __size = size();
+ auto __res = _Base::try_append_range(__rg);
+ if (size() != __size)
+ _M_invalidate_after_nth(__size);
Same question as for append_range.
+ return __res;
+ }
+
+ template<typename... _Args>
+ constexpr _Tp&
+ unchecked_emplace_back(_Args&&... __args)
+ {
+ auto __end = _Base::cend();
+ _Tp& __res =
+ _Base::unchecked_emplace_back(std::forward<_Args>(__args)...);
+
+ if (!std::is_constant_evaluated())
+ this->_M_invalidate_if(_Equal(__end));
+
+ return __res;
+ }
+
+ constexpr _Tp&
+ unchecked_push_back(const _Tp& __x)
+ { return unchecked_emplace_back(__x); }
+
+ constexpr _Tp&
+ unchecked_push_back(_Tp&& __x)
+ { return unchecked_emplace_back(std::move(__x)); }
+
+ template<typename... _Args>
+ 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);
+ difference_type __offset = __position.base() - _Base::cbegin();
+ _Base_iterator __res = _Base::emplace(__position.base(),
+ std::forward<_Args>(__args)...);
+ _M_invalidate_after_nth(__offset);
Why do any of the emplace or insert members invalidate any iterators?
Here I did like std::vector, but indeed I wonder if iterators which have
their value changed behind the scene must be invalidated.
Maybe we could some back to it for both vector and inplace_vector at the
same time later, once clarified.
+ return { __res, this };
+ }
+
+ constexpr iterator
+ insert(const_iterator __position, const _Tp& __x)
+ { return emplace(__position, __x); }
+
+ constexpr iterator
+ insert(const_iterator __position, _Tp&& __x)
+ { return emplace(__position, std::move(__x)); }
+
+ 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);
+ difference_type __offset = __position.base() - _Base::cbegin();
+ _Base_iterator __res = _Base::insert(__position.base(), __n, __x);
+ _M_invalidate_after_nth(__offset);
+ return { __res, this };
+ }
+
+ template<__any_input_iterator _InputIterator>
+ constexpr iterator
+ insert(const_iterator __position, _InputIterator __first,
+ _InputIterator __last)
+ {
+ using namespace __gnu_debug;
+ if (std::is_constant_evaluated())
+ return iterator(_Base::insert(__position.base(),
+ __unsafe(__first),
+ __unsafe(__last)), this);
+
+ typename _Distance_traits<_InputIterator>::__type __dist;
+ __glibcxx_check_insert_range(__position, __first, __last,
__dist);
+
+ difference_type __offset = __position.base() - _Base::cbegin();
+ _Base_iterator __res;
+ if (__dist.second >= __dp_sign)
+ __res = _Base::insert(__position.base(),
+ __unsafe(__first), __unsafe(__last));
+ else
+ __res = _Base::insert(__position.base(), __first, __last);
+
+ _M_invalidate_after_nth(__offset);
+ return { __res, this };
+ }
+
+ template<__detail::__container_compatible_range<_Tp> _Rg>
+ constexpr iterator
+ insert_range(const_iterator __position, _Rg&& __rg)
+ {
+ auto __res = _Base::insert_range(__position.base(), __rg);
+ this->_M_invalidate_all();
+
+ return iterator(__res, this);
+ }
+
+ constexpr iterator
+ insert(const_iterator __position, initializer_list<_Tp> __il)
+ {
+ if (std::is_constant_evaluated())
+ return iterator(_Base::insert(__position.base(), __il), this);
+
+ __glibcxx_check_insert(__position);
+ difference_type __offset = __position.base() - _Base::begin();
+ _Base_iterator __res = _Base::insert(__position.base(), __il);
+ this->_M_invalidate_after_nth(__offset);
+ return iterator(__res, this);
+ }
+
+ constexpr iterator
+ erase(const_iterator __position)
+ {
+ if (std::is_constant_evaluated())
+ return iterator(_Base::erase(__position.base()), this);
+
+ __glibcxx_check_erase(__position);
+ difference_type __offset = __position.base() - _Base::cbegin();
+ _Base_iterator __res = _Base::erase(__position.base());
+ this->_M_invalidate_after_nth(__offset);
+ return iterator(__res, this);
+ }
+
+ constexpr iterator
+ erase(const_iterator __first, const_iterator __last)
+ {
+ if (std::is_constant_evaluated())
+ return iterator(_Base::erase(__first.base(), __last.base()),
this);
+
+ __glibcxx_check_erase_range(__first, __last);
+
+ if (__first.base() != __last.base())
+ {
+ difference_type __offset = __first.base() - _Base::cbegin();
+ _Base_iterator __res = _Base::erase(__first.base(),
+ __last.base());
+ this->_M_invalidate_after_nth(__offset);
+ return { __res, this };
+ }
+ else
+ return { _Base::begin() + (__first.base() - _Base::cbegin()),
this };
+ }
+
+ constexpr void
+ swap(inplace_vector& __x)
+ noexcept(is_nothrow_swappable_v<_Tp> &&
is_nothrow_move_constructible_v<_Tp>)
+ {
+ this->_M_invalidate_all();
+ __x._M_invalidate_all();
+ _Base::swap(__x);
+ }
+
+ constexpr void
+ clear() noexcept
+ {
+ _Base::clear();
+ this->_M_invalidate_all();
+ }
+
+ constexpr friend bool
+ operator==(const inplace_vector& __x, const inplace_vector& __y)
I wondered if this could be defined as defaulted, but I think we'd
need to define _Safe_sequence::operator== for that to work.
+ { return __x._M_base() == __y._M_base(); }
+
+ constexpr friend auto
+ operator<=>(const inplace_vector& __x, const inplace_vector& __y)
+ requires requires (const _Tp __t) {
+ { __t < __t } -> __detail::__boolean_testable;
+ }
+ { return __x._M_base() <=> __y._M_base(); }
+
+ constexpr friend void
+ swap(inplace_vector& __x, inplace_vector& __y)
+ noexcept( noexcept(__x.swap(__y)) )
+ { __x.swap(__y); }
+
+ private:
+ constexpr _Base&
+ _M_base() noexcept { return *this; }
+
+ constexpr const _Base&
+ _M_base() const noexcept { return *this; }
+
+ constexpr void
+ _M_invalidate_after_nth(difference_type __n) noexcept
+ {
+ if (!std::is_constant_evaluated())
+ {
+ using _After_nth
+ = __gnu_debug::_After_nth_from<_Base_const_iterator>;
+ this->_M_invalidate_if(_After_nth(__n, _Base::cbegin()));
+ }
+ }
+
+ template<typename _Tp2, size_t _Nm2, typename _Predicate>
+ friend constexpr size_t std::erase_if(inplace_vector<_Tp2, _Nm2>&,
+ _Predicate __pred);
+ };
+
+ // specialization for zero capacity, that is required to be
trivally copyable
+ // and empty regardless of _Tp.
+ template<typename _Tp>
+ class inplace_vector<_Tp, 0>
+ : public _GLIBCXX_STD_C::inplace_vector<_Tp, 0>
+ {
+ using _Base = _GLIBCXX_STD_C::inplace_vector<_Tp, 0>;
+
+ public:
+ // types:
+ using value_type = _Base::value_type;
+ using pointer = _Base::pointer;
+ using const_pointer = _Base::const_pointer;
+ using reference = _Base::reference;
+ using const_reference = _Base::const_reference;
+ using size_type = _Base::size_type;
+ using difference_type = _Base::difference_type;
+ using iterator = _Base::iterator;
+ using const_iterator = _Base::const_iterator;
+ using reverse_iterator = _Base::reverse_iterator;
+ using const_reverse_iterator = _Base::const_reverse_iterator;
+
+ inplace_vector() = default;
+
+ constexpr explicit
+ inplace_vector(size_type __n) : _Base(__n) { }
+
+ constexpr
+ inplace_vector(size_type __n, const _Tp& __value)
+ : _Base(__n, __value) { }
+
+ template<__any_input_iterator _InputIterator>
+ constexpr
+ inplace_vector(_InputIterator __first, _InputIterator __last)
+ : _Base(__gnu_debug::__base(std::is_constant_evaluated() ? __first
+ : __glibcxx_check_valid_constructor_range(__first, __last)),
+ __gnu_debug::__base(__last)) { }
+
+ template <__detail::__container_compatible_range<_Tp> _Rg>
+ constexpr
+ inplace_vector(from_range_t, _Rg&& __rg)
+ : _Base(from_range_t{}, std::forward<_Rg>(__rg)) { }
+
+ constexpr
+ inplace_vector(initializer_list<_Tp> __il)
+ : _Base(__il) { }
+
+ inplace_vector(const inplace_vector&) = default;
+ inplace_vector(inplace_vector&&) = default;
+
+ constexpr
+ ~inplace_vector() = default;
+
+ inplace_vector&
+ operator=(const inplace_vector&) = default;
+
+ inplace_vector&
+ operator=(inplace_vector&&) = default;
+
+ constexpr inplace_vector&
+ operator=(initializer_list<_Tp> __il)
+ {
+ _Base::operator=(__il);
+ return *this;
+ }
+
+ constexpr void
+ swap(inplace_vector& __x)
+ noexcept
+ { }
+ };
+} // namespace __debug
+
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+
+ template<typename _Tp, size_t _Nm, typename _Predicate>
+ constexpr size_t
+ erase_if(__debug::inplace_vector<_Tp, _Nm>& __cont, _Predicate
__pred)
+ {
+ if constexpr (_Nm != 0)
+ {
+ auto& __unsafe_cont = __cont._M_base();
+ const auto __osz = __cont.size();
+ const auto __end = __unsafe_cont.end();
+ auto __begin = std::__find_if(__unsafe_cont.begin(), __end,
__pred);
+ const auto __offset = __begin - __unsafe_cont.begin();
+ auto __removed =
+ std::__remove_if(__begin, __end, std::move(__pred));
+ if (__removed != __end)
+ {
+ __cont.erase(__niter_wrap(__cont.begin(), __removed),
+ __cont.end());
+ __cont._M_invalidate_after_nth(__offset);
Doesn't __cont.erase already do that invalidation?
Indeed, implementation reviewed.
+ return __osz - __cont.size();
+ }
+ }
+
+ return 0;
+ }
+
+ template<typename _Tp, size_t _Nm, typename _Up = _Tp>
+ constexpr size_t
+ erase(__debug::inplace_vector<_Tp, _Nm>& __cont, const _Up&
__value)
+ { return std::erase_if(__cont,
__gnu_cxx::__ops::__equal_to(__value)); }
+
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace std
+
+#endif // __glibcxx_inplace_vector
+#endif // _GLIBCXX_DEBUG_INPLACE_VECTOR
diff --git a/libstdc++-v3/include/debug/safe_base.h
b/libstdc++-v3/include/debug/safe_base.h
index 44622970792..76264d30656 100644
--- a/libstdc++-v3/include/debug/safe_base.h
+++ b/libstdc++-v3/include/debug/safe_base.h
@@ -254,12 +254,36 @@ namespace __gnu_debug
/** Notify all iterators that reference this sequence that the
sequence is being destroyed. */
_GLIBCXX20_CONSTEXPR
- ~_Safe_sequence_base()
+ ~_Safe_sequence_base() _GLIBCXX_NOEXCEPT
{
if (!std::__is_constant_evaluated())
this->_M_detach_all();
}
+ // Copy assignment invalidate all iterators.
+ _GLIBCXX20_CONSTEXPR
+ _Safe_sequence_base&
+ operator=(const _Safe_sequence_base&) _GLIBCXX_NOEXCEPT
+ {
+ if (!std::__is_constant_evaluated())
+ _M_invalidate_all();
+ return *this;
+ }
+
+#if __cplusplus >= 201103L
+ _GLIBCXX20_CONSTEXPR
+ _Safe_sequence_base&
+ operator=(_Safe_sequence_base&& __x) noexcept
+ {
+ if (std::__is_constant_evaluated())
+ return *this;
+
+ _M_invalidate_all();
+ __x._M_invalidate_all();
+ return *this;
+ }
+#endif
+
/** Detach all iterators, leaving them singular. */
void
_M_detach_all() const;
@@ -292,7 +316,7 @@ namespace __gnu_debug
_M_get_mutex() const _GLIBCXX_USE_NOEXCEPT;
/** Invalidates all iterators. */
- void
+ _GLIBCXX20_CONSTEXPR void
_M_invalidate_all() const
{ if (++_M_version == 0) _M_version = 1; }
diff --git a/libstdc++-v3/include/debug/safe_container.h
b/libstdc++-v3/include/debug/safe_container.h
index 3341806fd59..2d0fbb8110e 100644
--- a/libstdc++-v3/include/debug/safe_container.h
+++ b/libstdc++-v3/include/debug/safe_container.h
@@ -86,17 +86,22 @@ namespace __gnu_debug
{ }
#endif
- // Copy assignment invalidate all iterators.
- _GLIBCXX20_CONSTEXPR
+#if __cplusplus < 201103L
_Safe_container&
- operator=(const _Safe_container&) _GLIBCXX_NOEXCEPT
+ operator=(const _Safe_container& __x)
{
- if (!std::__is_constant_evaluated())
- this->_M_invalidate_all();
+ _Base::operator=(__x);
Is this refactoring required for inplace_vector or is it an unrelated
change?
The _GLIBCXX_DEBUG inplace_vector is inheriting directly from
_Safe_sequence<> compared to other containers that inherit from
_Safe_container<>. This is why I noticed that those operators were not
implement at the right level and so fix those.
return *this;
}
-#if __cplusplus >= 201103L
+ void
+ _M_swap(const _Safe_container& __x) const throw()
+ { _Base::_M_swap(__x); }
+#else
+ _GLIBCXX20_CONSTEXPR
+ _Safe_container&
+ operator=(const _Safe_container&) noexcept = default;
+
_GLIBCXX20_CONSTEXPR
_Safe_container&
operator=(_Safe_container&& __x) noexcept
@@ -146,10 +151,6 @@ namespace __gnu_debug
_M_swap_base(__x);
}
-#else
- void
- _M_swap(const _Safe_container& __x) const throw()
- { _Base::_M_swap(__x); }
#endif
};
diff --git a/libstdc++-v3/include/Makefile.am b/libstdc++-v3/include/Makefile.am
index ae7a7ca9073..7d65c6f3ab3 100644
--- a/libstdc++-v3/include/Makefile.am
+++ b/libstdc++-v3/include/Makefile.am
@@ -971,6 +971,7 @@ debug_headers = \
${debug_srcdir}/forward_list \
${debug_srcdir}/functions.h \
${debug_srcdir}/helper_functions.h \
+ ${debug_srcdir}/inplace_vector \
${debug_srcdir}/list \
${debug_srcdir}/map \
${debug_srcdir}/macros.h \
diff --git a/libstdc++-v3/include/Makefile.in b/libstdc++-v3/include/Makefile.in
index f07e2326816..acf8ae9be44 100644
--- a/libstdc++-v3/include/Makefile.in
+++ b/libstdc++-v3/include/Makefile.in
@@ -1308,6 +1308,7 @@ debug_freestanding = \
@GLIBCXX_HOSTED_TRUE@ ${debug_srcdir}/forward_list \
@GLIBCXX_HOSTED_TRUE@ ${debug_srcdir}/functions.h \
@GLIBCXX_HOSTED_TRUE@ ${debug_srcdir}/helper_functions.h \
+@GLIBCXX_HOSTED_TRUE@ ${debug_srcdir}/inplace_vector \
@GLIBCXX_HOSTED_TRUE@ ${debug_srcdir}/list \
@GLIBCXX_HOSTED_TRUE@ ${debug_srcdir}/map \
@GLIBCXX_HOSTED_TRUE@ ${debug_srcdir}/macros.h \
diff --git a/libstdc++-v3/include/debug/functions.h
b/libstdc++-v3/include/debug/functions.h
index c5f5582b005..4e6fdae7193 100644
--- a/libstdc++-v3/include/debug/functions.h
+++ b/libstdc++-v3/include/debug/functions.h
@@ -53,15 +53,19 @@ namespace __gnu_debug
* assertion statement because, e.g., we are in a constructor.
*/
template<typename _InputIterator>
- inline _InputIterator
+ _GLIBCXX20_CONSTEXPR inline _InputIterator
__check_valid_range(const _InputIterator& __first,
const _InputIterator& __last,
const char* __file,
unsigned int __line,
const char* __function)
{
- __glibcxx_check_valid_range_at(__first, __last,
- __file, __line, __function);
+ if (!std::__is_constant_evaluated())
+ {
+ __glibcxx_check_valid_range_at(__first, __last,
+ __file, __line, __function);
+ }
+
return __first;
}
diff --git a/libstdc++-v3/include/debug/helper_functions.h
b/libstdc++-v3/include/debug/helper_functions.h
index 9395892b537..b9771034bf3 100644
--- a/libstdc++-v3/include/debug/helper_functions.h
+++ b/libstdc++-v3/include/debug/helper_functions.h
@@ -249,7 +249,7 @@ namespace __gnu_debug
}
template<typename _Iterator, typename _Sequence, typename _Category>
- bool
+ _GLIBCXX20_CONSTEXPR bool
__valid_range(const _Safe_iterator<_Iterator, _Sequence, _Category>&,
const _Safe_iterator<_Iterator, _Sequence, _Category>&,
typename _Distance_traits<_Iterator>::__type&);
@@ -272,7 +272,7 @@ namespace __gnu_debug
}
template<typename _Iterator, typename _Sequence, typename _Category>
- bool
+ _GLIBCXX20_CONSTEXPR bool
__valid_range(const _Safe_iterator<_Iterator, _Sequence, _Category>&,
const _Safe_iterator<_Iterator, _Sequence, _Category>&);
diff --git a/libstdc++-v3/include/debug/inplace_vector
b/libstdc++-v3/include/debug/inplace_vector
new file mode 100644
index 00000000000..c7e301efc62
--- /dev/null
+++ b/libstdc++-v3/include/debug/inplace_vector
@@ -0,0 +1,691 @@
+// Debugging inplace_vector implementation -*- C++ -*-
+
+// Copyright The GNU Toolchain Authors.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+// <http://www.gnu.org/licenses/>.
+
+/** @file debug/inplace_vector
+ * This file is a GNU debug extension to the Standard C++ Library.
+ */
+
+#ifndef _GLIBCXX_DEBUG_INPLACE_VECTOR
+#define _GLIBCXX_DEBUG_INPLACE_VECTOR 1
+
+#ifdef _GLIBCXX_SYSHDR
+#pragma GCC system_header
+#endif
+
+#include <debug/debug.h>
+
+namespace std _GLIBCXX_VISIBILITY(default) { namespace __debug {
+ template<typename _Tp, size_t _Nm> class inplace_vector;
+} } // namespace std::__debug
+
+#include <inplace_vector>
+
+#ifdef __glibcxx_inplace_vector // C++ >= 26
+
+#include <debug/safe_sequence.h>
+#include <debug/safe_iterator.h>
+
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+namespace __debug
+{
+ /// Class std::inplace_vector with safety/checking/debug instrumentation.
+ template<typename _Tp, size_t _Nm>
+ class inplace_vector
+ : public __gnu_debug::_Safe_sequence<inplace_vector<_Tp, _Nm>>
+ , public _GLIBCXX_STD_C::inplace_vector<_Tp, _Nm>
+ {
+ using _Base = _GLIBCXX_STD_C::inplace_vector<_Tp, _Nm>;
+ using _Base_iterator = typename _Base::iterator;
+ using _Base_const_iterator = typename _Base::const_iterator;
+ using _Equal = __gnu_debug::_Equal_to<_Base_const_iterator>;
+
+ template<typename _ItT, typename _SeqT, typename _CatT>
+ friend class ::__gnu_debug::_Safe_iterator;
+
+ public:
+ // types:
+ using value_type = _Base::value_type;
+ using pointer = _Base::pointer;
+ using const_pointer = _Base::const_pointer;
+ using reference = _Base::reference;
+ using const_reference = _Base::const_reference;
+ using size_type = _Base::size_type;
+ using difference_type = _Base::difference_type;
+ using iterator
+ = __gnu_debug::_Safe_iterator<_Base_iterator, inplace_vector>;
+ using const_iterator
+ = __gnu_debug::_Safe_iterator<_Base_const_iterator, inplace_vector>;
+ using reverse_iterator = std::reverse_iterator<iterator>;
+ using const_reverse_iterator = std::reverse_iterator<const_iterator>;
+
+ constexpr
+ inplace_vector() noexcept = default;
+
+ constexpr explicit
+ inplace_vector(size_type __n)
+ : _Base(__n) { }
+
+ constexpr
+ inplace_vector(size_type __n, const _Tp& __value)
+ : _Base(__n, __value) { }
+
+ template<__any_input_iterator _InputIterator>
+ constexpr
+ inplace_vector(_InputIterator __first, _InputIterator __last)
+ : _Base(__gnu_debug::__base(
+ __glibcxx_check_valid_constructor_range(__first, __last)),
+ __gnu_debug::__base(__last)) { }
+
+ template<__detail::__container_compatible_range<_Tp> _Rg>
+ constexpr
+ inplace_vector(from_range_t, _Rg&& __rg)
+ : _Base(from_range_t{}, std::forward<_Rg>(__rg)) { }
+
+ constexpr
+ inplace_vector(initializer_list<_Tp> __il)
+ : _Base(__il) { }
+
+ inplace_vector(const inplace_vector&) = default;
+ inplace_vector(inplace_vector&&) = default;
+ ~inplace_vector() = default;
+
+ inplace_vector&
+ operator=(const inplace_vector&) = default;
+
+ inplace_vector&
+ operator=(inplace_vector&&) = default;
+
+ constexpr inplace_vector&
+ operator=(initializer_list<_Tp> __il)
+ {
+ _Base::operator=(__il);
+ this->_M_invalidate_all();
+ return *this;
+ }
+
+ template<__any_input_iterator _InputIterator>
+ constexpr void
+ assign(_InputIterator __first, _InputIterator __last)
+ {
+ typename __gnu_debug::_Distance_traits<_InputIterator>::__type __dist;
+ __glibcxx_check_valid_range2(__first, __last, __dist);
+
+ const auto __size = size();
+ const auto __end = _Base::end();
+ if (__dist.second >= __gnu_debug::__dp_sign)
+ _Base::assign(__gnu_debug::__unsafe(__first),
+ __gnu_debug::__unsafe(__last));
+ else
+ _Base::assign(__first, __last);
+
+ if (size() < __size)
+ _M_invalidate_after_nth(size());
+ else if (size() > __size)
+ this->_M_invalidate_if(_Equal(__end));
+ }
+
+ template<__detail::__container_compatible_range<_Tp> _Rg>
+ constexpr void
+ assign_range(_Rg&& __rg)
+ {
+ _Base::assign_range(std::forward<_Rg>(__rg));
+ this->_M_invalidate_all();
+ }
+
+ constexpr void
+ assign(size_type __n, const _Tp& __u)
+ {
+ _Base::assign(__n, __u);
+ this->_M_invalidate_all();
+ }
+
+ constexpr void
+ assign(initializer_list<_Tp> __il)
+ {
+ _Base::assign(__il);
+ this->_M_invalidate_all();
+ }
+
+ // iterators
+ [[nodiscard]]
+ constexpr iterator
+ begin() noexcept
+ { return { _Base::begin(), this }; }
+
+ [[nodiscard]]
+ constexpr const_iterator
+ begin() const noexcept
+ { return { _Base::begin(), this }; }
+
+ [[nodiscard]]
+ constexpr iterator
+ end() noexcept
+ { return { _Base::end(), this }; }
+
+ [[nodiscard]]
+ constexpr const_iterator
+ end() const noexcept
+ { return { _Base::end(), this }; }
+
+ [[nodiscard]]
+ constexpr reverse_iterator
+ rbegin() noexcept
+ { return reverse_iterator(end()); }
+
+ [[nodiscard]]
+ constexpr const_reverse_iterator
+ rbegin() const noexcept
+ { return const_reverse_iterator(end()); }
+
+ [[nodiscard]]
+ constexpr reverse_iterator
+ rend() noexcept { return reverse_iterator(begin()); }
+
+ [[nodiscard]]
+ constexpr const_reverse_iterator
+ rend() const noexcept { return const_reverse_iterator(begin()); }
+
+ [[nodiscard]]
+ constexpr const_iterator
+ cbegin() const noexcept
+ { return { _Base::cbegin(), this }; }
+
+ [[nodiscard]]
+ constexpr const_iterator
+ cend() const noexcept
+ { return { _Base::cend(), this }; }
+
+ [[nodiscard]]
+ constexpr const_reverse_iterator
+ crbegin() const noexcept { return rbegin(); }
+
+ [[nodiscard]]
+ constexpr const_reverse_iterator
+ crend() const noexcept { return rend(); }
+
+ using _Base::empty;
+ using _Base::size;
+ using _Base::max_size;
+ using _Base::capacity;
+
+ constexpr void
+ resize(size_type __n)
+ {
+ _Base::resize(__n);
+ _M_invalidate_after_nth(__n);
+ }
+
+ constexpr void
+ resize(size_type __n, const _Tp& __c)
+ {
+ _Base::resize(__n, __c);
+ _M_invalidate_after_nth(__n);
+ }
+
+ using _Base::reserve;
+ using _Base::shrink_to_fit;
+
+ // element access
+ [[nodiscard]]
+ constexpr reference
+ operator[](size_type __n)
+ {
+ __glibcxx_check_subscript(__n);
+ return _Base::operator[](__n);
+ }
+
+ [[nodiscard]]
+ constexpr const_reference
+ operator[](size_type __n) const
+ {
+ __glibcxx_check_subscript(__n);
+ return _Base::operator[](__n);
+ }
+
+ using _Base::at;
+
+ [[nodiscard]]
+ constexpr reference
+ front()
+ {
+ __glibcxx_check_nonempty();
+ return data()[0];
+ }
+
+ [[nodiscard]]
+ constexpr const_reference
+ front() const
+ {
+ __glibcxx_check_nonempty();
+ return data()[0];
+ }
+
+ [[nodiscard]]
+ constexpr reference
+ back()
+ {
+ __glibcxx_check_nonempty();
+ return data()[size() - 1];
+ }
+
+ [[nodiscard]]
+ constexpr const_reference
+ back() const
+ {
+ __glibcxx_check_nonempty();
+ return data()[size() - 1];
+ }
+
+ using _Base::data;
+
+ template<typename... _Args>
+ constexpr _Tp&
+ emplace_back(_Args&&... __args)
+ {
+ const auto __end = _Base::cend();
+ _Tp& __res = _Base::emplace_back(std::forward<_Args>(__args)...);
+ this->_M_invalidate_if(_Equal(__end));
+ return __res;
+ }
+
+ constexpr _Tp&
+ push_back(const _Tp& __x)
+ { return emplace_back(__x); }
+
+ constexpr _Tp&
+ push_back(_Tp&& __x)
+ { return emplace_back(std::move(__x)); }
+
+ template<__detail::__container_compatible_range<_Tp> _Rg>
+ constexpr void
+ append_range(_Rg&& __rg)
+ {
+ const auto __size = size();
+ const auto __end = _Base::cend();
+ _Base::append_range(__rg);
+ if (size() != __size)
+ this->_M_invalidate_if(_Equal(__end));
+ }
+
+ constexpr void
+ pop_back()
+ {
+ __glibcxx_check_nonempty();
+ _M_invalidate_after_nth(_Base::size() - 1);
+ _Base::pop_back();
+ }
+
+ template<typename... _Args>
+ constexpr _Tp*
+ try_emplace_back(_Args&&... __args)
+ {
+ auto __end = _Base::cend();
+ _Tp* __res = _Base::try_emplace_back(std::forward<_Args>(__args)...);
+
+ if (__res)
+ this->_M_invalidate_if(_Equal(__end));
+
+ return __res;
+ }
+
+ constexpr _Tp*
+ try_push_back(const _Tp& __x)
+ {
+ const auto __end = _Base::cend();
+ _Tp* __res = _Base::try_push_back(__x);
+
+ if (__res)
+ this->_M_invalidate_if(_Equal(__end));
+
+ return __res;
+ }
+
+ constexpr _Tp*
+ try_push_back(_Tp&& __x)
+ {
+ const auto __end = _Base::cend();
+ _Tp* __res = _Base::try_push_back(std::move(__x));
+
+ if (__res)
+ this->_M_invalidate_if(_Equal(__end));
+
+ return __res;
+ }
+
+ template<__detail::__container_compatible_range<_Tp> _Rg>
+ constexpr ranges::borrowed_iterator_t<_Rg>
+ try_append_range(_Rg&& __rg)
+ {
+ const auto __size = size();
+ const auto __end = _Base::cend();
+ auto __res = _Base::try_append_range(__rg);
+ if (size() != __size)
+ this->_M_invalidate_if(_Equal(__end));
+
+ return __res;
+ }
+
+ template<typename... _Args>
+ constexpr _Tp&
+ unchecked_emplace_back(_Args&&... __args)
+ {
+ const auto __end = _Base::cend();
+ _Tp& __res =
+ _Base::unchecked_emplace_back(std::forward<_Args>(__args)...);
+
+ this->_M_invalidate_if(_Equal(__end));
+
+ return __res;
+ }
+
+ constexpr _Tp&
+ unchecked_push_back(const _Tp& __x)
+ { return unchecked_emplace_back(__x); }
+
+ constexpr _Tp&
+ unchecked_push_back(_Tp&& __x)
+ { return unchecked_emplace_back(std::move(__x)); }
+
+ template<typename... _Args>
+ constexpr iterator
+ emplace(const_iterator __position, _Args&&... __args)
+ {
+ if (std::is_constant_evaluated())
+ return iterator(_Base::emplace(__position.base(),
+ std::forward<_Args>(__args)...),
+ this);
+
+ __glibcxx_check_insert(__position);
+ const difference_type __offset = __position.base() - _Base::cbegin();
+ _Base_iterator __res = _Base::emplace(__position.base(),
+ std::forward<_Args>(__args)...);
+ _M_invalidate_after_nth(__offset);
+ return { __res, this };
+ }
+
+ constexpr iterator
+ insert(const_iterator __position, const _Tp& __x)
+ { return emplace(__position, __x); }
+
+ constexpr iterator
+ insert(const_iterator __position, _Tp&& __x)
+ { return emplace(__position, std::move(__x)); }
+
+ 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);
+ const difference_type __offset = __position.base() - _Base::cbegin();
+ _Base_iterator __res = _Base::insert(__position.base(), __n, __x);
+ _M_invalidate_after_nth(__offset);
+ return { __res, this };
+ }
+
+ template<__any_input_iterator _InputIterator>
+ 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);
+
+ const difference_type __offset = __position.base() - _Base::cbegin();
+ _Base_iterator __res;
+ if (__dist.second >= __gnu_debug::__dp_sign)
+ __res = _Base::insert(__position.base(),
+ __gnu_debug::__unsafe(__first),
+ __gnu_debug::__unsafe(__last));
+ else
+ __res = _Base::insert(__position.base(), __first, __last);
+
+ _M_invalidate_after_nth(__offset);
+ return { __res, this };
+ }
+
+ template<__detail::__container_compatible_range<_Tp> _Rg>
+ constexpr iterator
+ insert_range(const_iterator __position, _Rg&& __rg)
+ {
+ const auto __size = size();
+ const difference_type __offset = __position.base() - _Base::cbegin();
+ auto __res = _Base::insert_range(__position.base(), __rg);
+ if (size() > __size)
+ this->_M_invalidate_after_nth(__offset);
+
+ return iterator(__res, this);
+ }
+
+ constexpr iterator
+ insert(const_iterator __position, initializer_list<_Tp> __il)
+ {
+ if (std::is_constant_evaluated())
+ return iterator(_Base::insert(__position.base(), __il), this);
+
+ __glibcxx_check_insert(__position);
+ const auto __size = size();
+ difference_type __offset = __position.base() - _Base::begin();
+ _Base_iterator __res = _Base::insert(__position.base(), __il);
+ if (size() > __size)
+ this->_M_invalidate_after_nth(__offset);
+ return iterator(__res, this);
+ }
+
+ constexpr iterator
+ erase(const_iterator __position)
+ {
+ if (std::is_constant_evaluated())
+ return iterator(_Base::erase(__position.base()), this);
+
+ __glibcxx_check_erase(__position);
+ difference_type __offset = __position.base() - _Base::cbegin();
+ _Base_iterator __res = _Base::erase(__position.base());
+ this->_M_invalidate_after_nth(__offset);
+ return iterator(__res, this);
+ }
+
+ constexpr iterator
+ erase(const_iterator __first, const_iterator __last)
+ {
+ if (std::is_constant_evaluated())
+ return iterator(_Base::erase(__first.base(), __last.base()),
+ this);
+
+ __glibcxx_check_erase_range(__first, __last);
+
+ if (__first.base() != __last.base())
+ {
+ difference_type __offset = __first.base() - _Base::cbegin();
+ _Base_iterator __res = _Base::erase(__first.base(),
+ __last.base());
+ this->_M_invalidate_after_nth(__offset);
+ return { __res, this };
+ }
+ else
+ return { _Base::begin() + (__first.base() - _Base::cbegin()), this };
+ }
+
+ constexpr void
+ swap(inplace_vector& __x)
+ noexcept(is_nothrow_swappable_v<_Tp> &&
is_nothrow_move_constructible_v<_Tp>)
+ {
+ this->_M_invalidate_all();
+ __x._M_invalidate_all();
+ _Base::swap(__x);
+ }
+
+ constexpr void
+ clear() noexcept
+ {
+ _Base::clear();
+ this->_M_invalidate_all();
+ }
+
+ constexpr friend bool
+ operator==(const inplace_vector& __x, const inplace_vector& __y)
+ { return __x._M_base() == __y._M_base(); }
+
+ constexpr friend auto
+ operator<=>(const inplace_vector& __x, const inplace_vector& __y)
+ requires requires (const _Tp __t) {
+ { __t < __t } -> __detail::__boolean_testable;
+ }
+ { return __x._M_base() <=> __y._M_base(); }
+
+ constexpr friend void
+ swap(inplace_vector& __x, inplace_vector& __y)
+ noexcept( noexcept(__x.swap(__y)) )
+ { __x.swap(__y); }
+
+ private:
+ constexpr _Base&
+ _M_base() noexcept { return *this; }
+
+ constexpr const _Base&
+ _M_base() const noexcept { return *this; }
+
+ constexpr void
+ _M_invalidate_after_nth(difference_type __n) noexcept
+ {
+ using _After_nth
+ = __gnu_debug::_After_nth_from<_Base_const_iterator>;
+ this->_M_invalidate_if(_After_nth(__n, _Base::cbegin()));
+ }
+ };
+
+ // specialization for zero capacity, that is required to be trivally copyable
+ // and empty regardless of _Tp.
+ template<typename _Tp>
+ class inplace_vector<_Tp, 0>
+ : public _GLIBCXX_STD_C::inplace_vector<_Tp, 0>
+ {
+ using _Base = _GLIBCXX_STD_C::inplace_vector<_Tp, 0>;
+
+ public:
+ // types:
+ using value_type = _Base::value_type;
+ using pointer = _Base::pointer;
+ using const_pointer = _Base::const_pointer;
+ using reference = _Base::reference;
+ using const_reference = _Base::const_reference;
+ using size_type = _Base::size_type;
+ using difference_type = _Base::difference_type;
+ using iterator = _Base::iterator;
+ using const_iterator = _Base::const_iterator;
+ using reverse_iterator = _Base::reverse_iterator;
+ using const_reverse_iterator = _Base::const_reverse_iterator;
+
+ inplace_vector() = default;
+
+ constexpr explicit
+ inplace_vector(size_type __n) : _Base(__n) { }
+
+ constexpr
+ inplace_vector(size_type __n, const _Tp& __value)
+ : _Base(__n, __value) { }
+
+ template<__any_input_iterator _InputIterator>
+ constexpr
+ inplace_vector(_InputIterator __first, _InputIterator __last)
+ : _Base(__gnu_debug::__base(
+ __glibcxx_check_valid_constructor_range(__first, __last)),
+ __gnu_debug::__base(__last)) { }
+
+ template <__detail::__container_compatible_range<_Tp> _Rg>
+ constexpr
+ inplace_vector(from_range_t, _Rg&& __rg)
+ : _Base(from_range_t{}, std::forward<_Rg>(__rg)) { }
+
+ constexpr
+ inplace_vector(initializer_list<_Tp> __il)
+ : _Base(__il) { }
+
+ inplace_vector(const inplace_vector&) = default;
+ inplace_vector(inplace_vector&&) = default;
+
+ constexpr
+ ~inplace_vector() = default;
+
+ inplace_vector&
+ operator=(const inplace_vector&) = default;
+
+ inplace_vector&
+ operator=(inplace_vector&&) = default;
+
+ constexpr inplace_vector&
+ operator=(initializer_list<_Tp> __il)
+ {
+ _Base::operator=(__il);
+ return *this;
+ }
+
+ constexpr void
+ swap(inplace_vector& __x)
+ noexcept
+ { }
+ };
+} // namespace __debug
+
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+
+ template<typename _Tp, size_t _Nm, typename _Predicate>
+ constexpr size_t
+ erase_if(__debug::inplace_vector<_Tp, _Nm>& __cont, _Predicate __pred)
+ {
+ if constexpr (_Nm != 0)
+ {
+ _GLIBCXX_STD_C::inplace_vector<_Tp, _Nm>& __ucont = __cont;
+ const auto __osz = __cont.size();
+ const auto __end = __ucont.end();
+ auto __removed = std::__remove_if(__ucont.begin(), __end,
+ std::move(__pred));
+ if (__removed != __end)
+ {
+ __cont.erase(__niter_wrap(__cont.cbegin(), __removed),
+ __cont.cend());
+ return __osz - __cont.size();
+ }
+ }
+
+ return 0;
+ }
+
+ template<typename _Tp, size_t _Nm, typename _Up = _Tp>
+ constexpr size_t
+ erase(__debug::inplace_vector<_Tp, _Nm>& __cont, const _Up& __value)
+ { return std::erase_if(__cont, __gnu_cxx::__ops::__equal_to(__value)); }
+
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace std
+
+#endif // __glibcxx_inplace_vector
+#endif // _GLIBCXX_DEBUG_INPLACE_VECTOR
diff --git a/libstdc++-v3/include/debug/safe_base.h
b/libstdc++-v3/include/debug/safe_base.h
index 44622970792..7491cc0ebe2 100644
--- a/libstdc++-v3/include/debug/safe_base.h
+++ b/libstdc++-v3/include/debug/safe_base.h
@@ -254,12 +254,30 @@ namespace __gnu_debug
/** Notify all iterators that reference this sequence that the
sequence is being destroyed. */
_GLIBCXX20_CONSTEXPR
- ~_Safe_sequence_base()
+ ~_Safe_sequence_base() _GLIBCXX_NOEXCEPT
{
if (!std::__is_constant_evaluated())
this->_M_detach_all();
}
+ // Copy assignment invalidate all iterators.
+ _GLIBCXX20_CONSTEXPR _Safe_sequence_base&
+ operator=(const _Safe_sequence_base&) _GLIBCXX_NOEXCEPT
+ {
+ _M_invalidate_all();
+ return *this;
+ }
+
+#if __cplusplus >= 201103L
+ _GLIBCXX20_CONSTEXPR _Safe_sequence_base&
+ operator=(_Safe_sequence_base&& __x) noexcept
+ {
+ _M_invalidate_all();
+ __x._M_invalidate_all();
+ return *this;
+ }
+#endif
+
/** Detach all iterators, leaving them singular. */
void
_M_detach_all() const;
@@ -292,7 +310,7 @@ namespace __gnu_debug
_M_get_mutex() const _GLIBCXX_USE_NOEXCEPT;
/** Invalidates all iterators. */
- void
+ _GLIBCXX20_CONSTEXPR void
_M_invalidate_all() const
{ if (++_M_version == 0) _M_version = 1; }
diff --git a/libstdc++-v3/include/debug/safe_container.h
b/libstdc++-v3/include/debug/safe_container.h
index 3341806fd59..2d0fbb8110e 100644
--- a/libstdc++-v3/include/debug/safe_container.h
+++ b/libstdc++-v3/include/debug/safe_container.h
@@ -86,17 +86,22 @@ namespace __gnu_debug
{ }
#endif
- // Copy assignment invalidate all iterators.
- _GLIBCXX20_CONSTEXPR
+#if __cplusplus < 201103L
_Safe_container&
- operator=(const _Safe_container&) _GLIBCXX_NOEXCEPT
+ operator=(const _Safe_container& __x)
{
- if (!std::__is_constant_evaluated())
- this->_M_invalidate_all();
+ _Base::operator=(__x);
return *this;
}
-#if __cplusplus >= 201103L
+ void
+ _M_swap(const _Safe_container& __x) const throw()
+ { _Base::_M_swap(__x); }
+#else
+ _GLIBCXX20_CONSTEXPR
+ _Safe_container&
+ operator=(const _Safe_container&) noexcept = default;
+
_GLIBCXX20_CONSTEXPR
_Safe_container&
operator=(_Safe_container&& __x) noexcept
@@ -146,10 +151,6 @@ namespace __gnu_debug
_M_swap_base(__x);
}
-#else
- void
- _M_swap(const _Safe_container& __x) const throw()
- { _Base::_M_swap(__x); }
#endif
};
diff --git a/libstdc++-v3/include/debug/safe_iterator.h
b/libstdc++-v3/include/debug/safe_iterator.h
index e0b1b46939c..80ed9570ecb 100644
--- a/libstdc++-v3/include/debug/safe_iterator.h
+++ b/libstdc++-v3/include/debug/safe_iterator.h
@@ -1114,21 +1114,31 @@ namespace __gnu_debug
/** Safe iterators know how to check if they form a valid range. */
template<typename _Iterator, typename _Sequence, typename _Category>
+ _GLIBCXX20_CONSTEXPR
inline bool
__valid_range(const _Safe_iterator<_Iterator, _Sequence,
_Category>& __first,
const _Safe_iterator<_Iterator, _Sequence,
_Category>& __last,
typename _Distance_traits<_Iterator>::__type& __dist)
- { return __first._M_valid_range(__last, __dist); }
+ {
+ if (std::__is_constant_evaluated())
+ return true;
+
+ return __first._M_valid_range(__last, __dist);
+ }
template<typename _Iterator, typename _Sequence, typename _Category>
+ _GLIBCXX20_CONSTEXPR
inline bool
__valid_range(const _Safe_iterator<_Iterator, _Sequence,
_Category>& __first,
const _Safe_iterator<_Iterator, _Sequence,
_Category>& __last)
{
+ if (std::__is_constant_evaluated())
+ return true;
+
typename _Distance_traits<_Iterator>::__type __dist;
return __first._M_valid_range(__last, __dist);
}
diff --git a/libstdc++-v3/include/debug/safe_sequence.h
b/libstdc++-v3/include/debug/safe_sequence.h
index e10474aae79..c908d1e47a9 100644
--- a/libstdc++-v3/include/debug/safe_sequence.h
+++ b/libstdc++-v3/include/debug/safe_sequence.h
@@ -46,6 +46,7 @@ namespace __gnu_debug
_Type __value;
public:
+ _GLIBCXX20_CONSTEXPR
explicit _Not_equal_to(const _Type& __v) : __value(__v) { }
bool
@@ -61,6 +62,7 @@ namespace __gnu_debug
_Type __value;
public:
+ _GLIBCXX20_CONSTEXPR
explicit _Equal_to(const _Type& __v) : __value(__v) { }
bool
@@ -80,6 +82,7 @@ namespace __gnu_debug
difference_type _M_n;
public:
+ _GLIBCXX20_CONSTEXPR
_After_nth_from(const difference_type& __n, const _Iterator& __base)
: _M_base(__base), _M_n(__n) { }
@@ -113,7 +116,7 @@ namespace __gnu_debug
true. @c __pred will be invoked with the normal iterators nested
in the safe ones. */
template<typename _Predicate>
- void
+ _GLIBCXX20_CONSTEXPR void
_M_invalidate_if(_Predicate __pred) const;
/** Transfers all iterators @c x that reference @c from sequence,
@@ -132,10 +135,31 @@ namespace __gnu_debug
class _Safe_node_sequence
: public _Safe_sequence<_Sequence>
{
+ public:
+ _GLIBCXX20_CONSTEXPR _Safe_node_sequence&
+ operator=(const _Safe_node_sequence&) _GLIBCXX_NOEXCEPT
+ {
+ _M_invalidate_all();
+ return *this;
+ }
+
+#if __cplusplus >= 201103L
+ _GLIBCXX20_CONSTEXPR _Safe_node_sequence&
+ operator=(_Safe_node_sequence&& __x) noexcept
+ {
+ _M_invalidate_all();
+ __x._M_invalidate_all();
+ return *this;
+ }
+#endif
+
protected:
- void
+ _GLIBCXX20_CONSTEXPR void
_M_invalidate_all() const
{
+ if (std::__is_constant_evaluated())
+ return;
+
typedef typename _Sequence::const_iterator _Const_iterator;
typedef typename _Const_iterator::iterator_type _Base_const_iterator;
typedef __gnu_debug::_Not_equal_to<_Base_const_iterator> _Not_equal;
diff --git a/libstdc++-v3/include/debug/safe_sequence.tcc
b/libstdc++-v3/include/debug/safe_sequence.tcc
index 053361dff3c..720a1842752 100644
--- a/libstdc++-v3/include/debug/safe_sequence.tcc
+++ b/libstdc++-v3/include/debug/safe_sequence.tcc
@@ -33,10 +33,13 @@ namespace __gnu_debug
{
template<typename _Sequence>
template<typename _Predicate>
- void
+ _GLIBCXX20_CONSTEXPR void
_Safe_sequence<_Sequence>::
_M_invalidate_if(_Predicate __pred) const
{
+ if (std::__is_constant_evaluated())
+ return;
+
typedef typename _Sequence::iterator iterator;
typedef typename _Sequence::const_iterator const_iterator;
diff --git a/libstdc++-v3/include/std/inplace_vector
b/libstdc++-v3/include/std/inplace_vector
index 7aa6f9d4ab2..0f7716cb64d 100644
--- a/libstdc++-v3/include/std/inplace_vector
+++ b/libstdc++-v3/include/std/inplace_vector
@@ -35,7 +35,7 @@
#define __glibcxx_want_inplace_vector
#include <bits/version.h>
-#ifdef __glibcxx_inplace_vector // C++ >= 26
+#ifdef __glibcxx_inplace_vector // C++ >= 26
#include <compare>
#include <initializer_list>
#include <bits/range_access.h>
@@ -49,6 +49,7 @@
namespace std _GLIBCXX_VISIBILITY(default)
{
_GLIBCXX_BEGIN_NAMESPACE_VERSION
+_GLIBCXX_BEGIN_NAMESPACE_CONTAINER
// [indirect], class template indirect
template<typename _Tp, size_t _Nm>
@@ -1329,32 +1330,40 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
{ }
};
+_GLIBCXX_END_NAMESPACE_CONTAINER
+
template<typename _Tp, size_t _Nm, typename _Predicate>
constexpr size_t
- erase_if(inplace_vector<_Tp, _Nm>& __cont, _Predicate __pred)
+ erase_if(_GLIBCXX_STD_C::inplace_vector<_Tp, _Nm>& __cont,
+ _Predicate __pred)
{
- using namespace __gnu_cxx;
- const auto __osz = __cont.size();
- const auto __end = __cont.end();
- auto __removed = std::__remove_if(__cont.begin(), __end,
- std::move(__pred));
- if (__removed != __end)
+ if constexpr (_Nm != 0)
{
- __cont.erase(__niter_wrap(__cont.begin(), __removed),
- __cont.end());
- return __osz - __cont.size();
+ const auto __osz = __cont.size();
+ const auto __end = __cont.end();
+ auto __removed = std::__remove_if(__cont.begin(), __end,
+ std::move(__pred));
+ if (__removed != __end)
+ {
+ __cont.erase(__removed, __end);
+ return __osz - __cont.size();
+ }
}
+
return 0;
}
-
template<typename _Tp, size_t _Nm, typename _Up = _Tp>
constexpr size_t
- erase(inplace_vector<_Tp, _Nm>& __cont, const _Up& __value)
+ erase(_GLIBCXX_STD_C::inplace_vector<_Tp, _Nm>& __cont, const _Up& __value)
{ return std::erase_if(__cont, __gnu_cxx::__ops::__equal_to(__value)); }
_GLIBCXX_END_NAMESPACE_VERSION
} // namespace
+#ifdef _GLIBCXX_DEBUG
+# include <debug/inplace_vector>
+#endif
+
#endif // __glibcxx_inplace_vector
#endif // _GLIBCXX_INPLACE_VECTOR
diff --git a/libstdc++-v3/testsuite/23_containers/inplace_vector/cons/1.cc
b/libstdc++-v3/testsuite/23_containers/inplace_vector/cons/1.cc
index e9c2cdc8665..45685c2becc 100644
--- a/libstdc++-v3/testsuite/23_containers/inplace_vector/cons/1.cc
+++ b/libstdc++-v3/testsuite/23_containers/inplace_vector/cons/1.cc
@@ -24,7 +24,7 @@ struct U
};
// n5008 inplace.vector.overview says for inplace_vector<T, 0>
-// provides trivial copy/move/default cosntructpr regardless of T
+// provides trivial copy/move/default constructor regardless of T
struct Z
{
constexpr Z(int) {}
@@ -52,11 +52,13 @@
static_assert(!std::is_trivially_default_constructible_v<std::inplace_vector<N,
static_assert(!std::is_trivially_default_constructible_v<std::inplace_vector<D,
2>>);
static_assert(!std::is_trivially_default_constructible_v<std::inplace_vector<U,
2>>);
+#if !_GLIBCXX_DEBUG
static_assert(std::is_trivially_destructible_v<std::inplace_vector<int, 2>>);
static_assert(std::is_trivially_destructible_v<std::inplace_vector<X, 2>>);
static_assert(std::is_trivially_destructible_v<std::inplace_vector<N, 2>>);
static_assert(!std::is_trivially_destructible_v<std::inplace_vector<D, 2>>);
static_assert(std::is_trivially_destructible_v<std::inplace_vector<U, 2>>);
+#endif
static_assert(std::is_nothrow_default_constructible_v<std::inplace_vector<int,
0>>);
static_assert(std::is_nothrow_default_constructible_v<std::inplace_vector<X,
0>>);
diff --git a/libstdc++-v3/testsuite/23_containers/inplace_vector/copy.cc
b/libstdc++-v3/testsuite/23_containers/inplace_vector/copy.cc
index d149e63970c..917eebd80f7 100644
--- a/libstdc++-v3/testsuite/23_containers/inplace_vector/copy.cc
+++ b/libstdc++-v3/testsuite/23_containers/inplace_vector/copy.cc
@@ -72,12 +72,14 @@
static_assert(!std::is_nothrow_copy_constructible_v<std::inplace_vector<N<false,
static_assert(std::is_nothrow_copy_constructible_v<std::inplace_vector<D, 2>>);
static_assert(!std::is_nothrow_copy_constructible_v<std::inplace_vector<U,
2>>);
+#if !_GLIBCXX_DEBUG
static_assert(std::is_trivially_copy_constructible_v<std::inplace_vector<int,
2>>);
static_assert(!std::is_trivially_copy_constructible_v<std::inplace_vector<X,
2>>);
static_assert(!std::is_trivially_copy_constructible_v<std::inplace_vector<N<true,
true>, 2>>);
// is_trivially_copy_constructible_v checks destructor
static_assert(!std::is_trivially_copy_constructible_v<std::inplace_vector<D,
2>>);
static_assert(std::is_trivially_copy_constructible_v<std::inplace_vector<U,
2>>);
+#endif
static_assert(std::is_copy_assignable_v<std::inplace_vector<int, 2>>);
static_assert(std::is_copy_assignable_v<std::inplace_vector<X, 2>>);
@@ -96,6 +98,7 @@
static_assert(!std::is_nothrow_copy_assignable_v<std::inplace_vector<N<false, fa
static_assert(std::is_nothrow_copy_assignable_v<std::inplace_vector<D, 2>>);
static_assert(!std::is_nothrow_copy_assignable_v<std::inplace_vector<U, 2>>);
+#if !_GLIBCXX_DEBUG
// conditional noexcept here is libstdc++ extension,
static_assert(std::is_trivially_copy_assignable_v<std::inplace_vector<int,
2>>);
static_assert(!std::is_trivially_copy_assignable_v<std::inplace_vector<X, 2>>);
@@ -103,6 +106,7 @@
static_assert(!std::is_trivially_copy_assignable_v<std::inplace_vector<N<true, t
// destructor is not trivial
static_assert(!std::is_trivially_copy_assignable_v<std::inplace_vector<D, 2>>);
static_assert(std::is_trivially_copy_assignable_v<std::inplace_vector<U, 2>>);
+#endif
static_assert(std::is_nothrow_copy_constructible_v<std::inplace_vector<int,
0>>);
static_assert(std::is_nothrow_copy_constructible_v<std::inplace_vector<X, 0>>);
diff --git
a/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/assign1_neg.cc
b/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/assign1_neg.cc
new file mode 100644
index 00000000000..37c80c32bbd
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/assign1_neg.cc
@@ -0,0 +1,16 @@
+// { dg-do run { target c++26 xfail *-*-* } }
+// { dg-require-debug-mode "" }
+
+#include <inplace_vector>
+#include <debug/checks.h>
+
+void test01()
+{
+ __gnu_test::check_assign1<std::inplace_vector<int, 10> >();
+}
+
+int main()
+{
+ test01();
+ return 0;
+}
diff --git
a/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/assign2_neg.cc
b/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/assign2_neg.cc
new file mode 100644
index 00000000000..ff6c9a73acc
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/assign2_neg.cc
@@ -0,0 +1,16 @@
+// { dg-do run { target c++26 xfail *-*-* } }
+// { dg-require-debug-mode "" }
+
+#include <inplace_vector>
+#include <debug/checks.h>
+
+void test01()
+{
+ __gnu_test::check_assign2<std::inplace_vector<int, 10>>();
+}
+
+int main()
+{
+ test01();
+ return 0;
+}
diff --git
a/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/assign3_neg.cc
b/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/assign3_neg.cc
new file mode 100644
index 00000000000..42f811d07e1
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/assign3_neg.cc
@@ -0,0 +1,16 @@
+// { dg-do run { target c++26 xfail *-*-* } }
+// { dg-require-debug-mode "" }
+
+#include <inplace_vector>
+#include <debug/checks.h>
+
+void test01()
+{
+ __gnu_test::check_assign3<std::inplace_vector<int, 10>>();
+}
+
+int main()
+{
+ test01();
+ return 0;
+}
diff --git
a/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/assign4_backtrace_neg.cc
b/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/assign4_backtrace_neg.cc
new file mode 100644
index 00000000000..dec72289fbc
--- /dev/null
+++
b/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/assign4_backtrace_neg.cc
@@ -0,0 +1,17 @@
+// { dg-do run { target c++26 xfail *-*-* } }
+// { dg-options "-D_GLIBCXX_DEBUG_BACKTRACE -lstdc++exp" }
+// { dg-require-cpp-feature-test __cpp_lib_stacktrace }
+
+#include <debug/inplace_vector>
+#include <debug/checks.h>
+
+void test01()
+{
+ __gnu_test::check_assign1<__gnu_debug::inplace_vector<int, 10>>();
+}
+
+int main()
+{
+ test01();
+ return 0;
+}
diff --git
a/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/assign4_neg.cc
b/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/assign4_neg.cc
new file mode 100644
index 00000000000..4bed3456e78
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/assign4_neg.cc
@@ -0,0 +1,15 @@
+// { dg-do run { target c++26 xfail *-*-* } }
+
+#include <debug/inplace_vector>
+#include <debug/checks.h>
+
+void test01()
+{
+ __gnu_test::check_assign1<__gnu_debug::inplace_vector<int, 10>>();
+}
+
+int main()
+{
+ test01();
+ return 0;
+}
diff --git
a/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/construct1_neg.cc
b/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/construct1_neg.cc
new file mode 100644
index 00000000000..28ede4c47b9
--- /dev/null
+++
b/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/construct1_neg.cc
@@ -0,0 +1,16 @@
+// { dg-do run { target c++26 xfail *-*-* } }
+// { dg-require-debug-mode "" }
+
+#include <inplace_vector>
+#include <debug/checks.h>
+
+void test01()
+{
+ __gnu_test::check_construct1<std::inplace_vector<int, 10> >();
+}
+
+int main()
+{
+ test01();
+ return 0;
+}
diff --git
a/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/construct2_neg.cc
b/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/construct2_neg.cc
new file mode 100644
index 00000000000..be37ddeaaf2
--- /dev/null
+++
b/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/construct2_neg.cc
@@ -0,0 +1,16 @@
+// { dg-do run { target c++26 xfail *-*-* } }
+// { dg-require-debug-mode "" }
+
+#include <inplace_vector>
+#include <debug/checks.h>
+
+void test01()
+{
+ __gnu_test::check_construct2<std::inplace_vector<int, 10> >();
+}
+
+int main()
+{
+ test01();
+ return 0;
+}
diff --git
a/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/construct3_neg.cc
b/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/construct3_neg.cc
new file mode 100644
index 00000000000..80861831b48
--- /dev/null
+++
b/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/construct3_neg.cc
@@ -0,0 +1,16 @@
+// { dg-do run { target c++26 xfail *-*-* } }
+// { dg-require-debug-mode "" }
+
+#include <inplace_vector>
+#include <debug/checks.h>
+
+void test01()
+{
+ __gnu_test::check_construct3<std::inplace_vector<int, 10> >();
+}
+
+int main()
+{
+ test01();
+ return 0;
+}
diff --git
a/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/construct4_neg.cc
b/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/construct4_neg.cc
new file mode 100644
index 00000000000..099b35727ae
--- /dev/null
+++
b/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/construct4_neg.cc
@@ -0,0 +1,15 @@
+// { dg-do run { target c++26 xfail *-*-* } }
+
+#include <debug/inplace_vector>
+#include <debug/checks.h>
+
+void test01()
+{
+ __gnu_test::check_construct1<__gnu_debug::inplace_vector<int, 10> >();
+}
+
+int main()
+{
+ test01();
+ return 0;
+}
diff --git
a/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/debug_functions.cc
b/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/debug_functions.cc
new file mode 100644
index 00000000000..bc5ed50113f
--- /dev/null
+++
b/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/debug_functions.cc
@@ -0,0 +1,34 @@
+// { dg-do run { target c++26 } }
+// { dg-require-debug-mode "" }
+
+#include <inplace_vector>
+#include <testsuite_hooks.h>
+
+void test02()
+{
+ using namespace __gnu_debug;
+
+ std::inplace_vector<int, 10> v1(3, 1);
+ VERIFY( !__check_singular(v1.begin()) );
+ auto it = v1.begin();
+ VERIFY( !__check_singular(it) );
+
+ VERIFY( !__check_singular(v1.end()) );
+ it = v1.end();
+ VERIFY( !__check_singular(it) );
+
+ v1.clear();
+
+ VERIFY( it._M_singular() );
+ VERIFY( __check_singular(it) );
+
+ it = v1.end();
+ VERIFY( !it._M_singular() );
+ VERIFY( !__check_singular(it) );
+}
+
+int main()
+{
+ test02();
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/erase.cc
b/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/erase.cc
new file mode 100644
index 00000000000..94da94627f3
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/erase.cc
@@ -0,0 +1,35 @@
+// { dg-do run { target c++26 } }
+// { dg-require-debug-mode "" }
+
+#include <inplace_vector>
+#include <testsuite_hooks.h>
+
+void test01()
+{
+ std::inplace_vector<int, 10> v;
+
+ for (int i = 0; i != 10; ++i)
+ v.push_back(i);
+
+ auto before = v.begin() + 4;
+ auto last = v.end() - 1;
+
+ VERIFY( std::erase(v, 6) == 1 );
+
+ VERIFY(before._M_dereferenceable());
+ VERIFY(last._M_singular());
+}
+
+void test02()
+{
+ std::inplace_vector<int, 0> v;
+
+ VERIFY( std::erase(v, 6) == 0 );
+}
+
+int main()
+{
+ test01();
+ test02();
+ return 0;
+}
diff --git
a/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/insert1_neg.cc
b/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/insert1_neg.cc
new file mode 100644
index 00000000000..f85cfaa90b4
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/insert1_neg.cc
@@ -0,0 +1,16 @@
+// { dg-do run { target c++26 xfail *-*-* } }
+// { dg-require-debug-mode "" }
+
+#include <inplace_vector>
+#include <debug/checks.h>
+
+void test01()
+{
+ __gnu_test::check_insert1<std::inplace_vector<int, 10>>();
+}
+
+int main()
+{
+ test01();
+ return 0;
+}
diff --git
a/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/insert2_neg.cc
b/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/insert2_neg.cc
new file mode 100644
index 00000000000..6a203696ec9
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/insert2_neg.cc
@@ -0,0 +1,16 @@
+// { dg-do run { target c++26 xfail *-*-* } }
+// { dg-require-debug-mode "" }
+
+#include <inplace_vector>
+#include <debug/checks.h>
+
+void test01()
+{
+ __gnu_test::check_insert2<std::inplace_vector<int, 10>>();
+}
+
+int main()
+{
+ test01();
+ return 0;
+}
diff --git
a/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/insert3_neg.cc
b/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/insert3_neg.cc
new file mode 100644
index 00000000000..63f6e05d655
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/insert3_neg.cc
@@ -0,0 +1,16 @@
+// { dg-do run { target c++26 xfail *-*-* } }
+// { dg-require-debug-mode "" }
+
+#include <inplace_vector>
+#include <debug/checks.h>
+
+void test01()
+{
+ __gnu_test::check_insert3<std::inplace_vector<int, 10>>();
+}
+
+int main()
+{
+ test01();
+ return 0;
+}
diff --git
a/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/insert4_neg.cc
b/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/insert4_neg.cc
new file mode 100644
index 00000000000..59e9f4b1722
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/insert4_neg.cc
@@ -0,0 +1,15 @@
+// { dg-do run { target c++26 xfail *-*-* } }
+
+#include <debug/inplace_vector>
+#include <debug/checks.h>
+
+void test01()
+{
+ __gnu_test::check_insert1<__gnu_debug::inplace_vector<int, 10>>();
+}
+
+int main()
+{
+ test01();
+ return 0;
+}
diff --git
a/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/insert5_neg.cc
b/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/insert5_neg.cc
new file mode 100644
index 00000000000..e1fbd65b711
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/insert5_neg.cc
@@ -0,0 +1,16 @@
+// { dg-do run { target c++26 xfail *-*-* } }
+// { dg-require-debug-mode "" }
+
+#include <inplace_vector>
+#include <debug/checks.h>
+
+void test01()
+{
+ __gnu_test::check_insert4<std::inplace_vector<int, 10>>();
+}
+
+int main()
+{
+ test01();
+ return 0;
+}
diff --git
a/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/insert7_neg.cc
b/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/insert7_neg.cc
new file mode 100644
index 00000000000..c59453cc518
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/insert7_neg.cc
@@ -0,0 +1,24 @@
+// { dg-do run { target c++26 xfail *-*-* } }
+
+#include <memory>
+#include <iterator>
+#include <debug/inplace_vector>
+
+void
+test01()
+{
+ __gnu_debug::inplace_vector<std::unique_ptr<int>, 10> v;
+
+ v.emplace_back(new int(0));
+ v.emplace_back(new int(1));
+
+ v.insert(begin(v) + 1,
+ make_move_iterator(begin(v)),
+ make_move_iterator(end(v)));
+}
+
+int
+main()
+{
+ test01();
+}
diff --git
a/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/invalidation/1.cc
b/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/invalidation/1.cc
new file mode 100644
index 00000000000..1a852739de0
--- /dev/null
+++
b/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/invalidation/1.cc
@@ -0,0 +1,33 @@
+// { dg-do run { target c++26 } }
+
+#include <debug/inplace_vector>
+#include <testsuite_hooks.h>
+
+using __gnu_debug::inplace_vector;
+
+// Assignment
+void test01()
+{
+ inplace_vector<int, 30> v1;
+ inplace_vector<int, 30> v2;
+
+ auto i = v1.end();
+ VERIFY(!i._M_dereferenceable() && !i._M_singular());
+
+ v1 = v2;
+ VERIFY(i._M_singular());
+
+ i = v1.end();
+ v1.assign(v2.begin(), v2.end());
+ VERIFY( !i._M_singular() );
+
+ i = v1.end();
+ v1.assign(17, 42);
+ VERIFY(i._M_singular());
+}
+
+int main()
+{
+ test01();
+ return 0;
+}
diff --git
a/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/invalidation/2.cc
b/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/invalidation/2.cc
new file mode 100644
index 00000000000..22d512ca107
--- /dev/null
+++
b/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/invalidation/2.cc
@@ -0,0 +1,34 @@
+// { dg-do run { target c++26 } }
+
+#include <debug/inplace_vector>
+#include <testsuite_hooks.h>
+
+using __gnu_debug::inplace_vector;
+
+// Resize
+void test01()
+{
+ inplace_vector<int, 50> v(10, 17);
+ v.reserve(20);
+
+ auto before = v.begin() + 6;
+ auto at = before + 1;
+ auto after = at + 1;
+
+ // Shrink.
+ v.resize(7);
+ VERIFY(before._M_dereferenceable());
+ VERIFY(at._M_singular());
+ VERIFY(after._M_singular());
+
+ // Grow.
+ before = v.begin() + 6;
+ v.resize(17);
+ VERIFY(before._M_dereferenceable());
+}
+
+int main()
+{
+ test01();
+ return 0;
+}
diff --git
a/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/invalidation/3.cc
b/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/invalidation/3.cc
new file mode 100644
index 00000000000..7b742131d48
--- /dev/null
+++
b/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/invalidation/3.cc
@@ -0,0 +1,43 @@
+// { dg-do run { target c++26 } }
+
+#include <debug/inplace_vector>
+#include <testsuite_hooks.h>
+
+using __gnu_debug::inplace_vector;
+
+// Insert
+void test01()
+{
+ inplace_vector<int, 100> v(10, 17);
+ v.reserve(30);
+
+ // Insert a single element
+ auto before = v.begin() + 6;
+ auto at = before + 1;
+ auto after = at;
+ at = v.insert(at, 42);
+ VERIFY(before._M_dereferenceable());
+ VERIFY(at._M_dereferenceable());
+ VERIFY(after._M_singular());
+
+ // Insert multiple copies
+ before = v.begin() + 6;
+ at = before + 1;
+ v.insert(at, 3, 42);
+ VERIFY(before._M_dereferenceable());
+ VERIFY(at._M_singular());
+
+ // Insert iterator range
+ static int data[] = { 2, 3, 5, 7 };
+ before = v.begin() + 6;
+ at = before + 1;
+ v.insert(at, &data[0], &data[0] + 4);
+ VERIFY(before._M_dereferenceable());
+ VERIFY(at._M_singular());
+}
+
+int main()
+{
+ test01();
+ return 0;
+}
diff --git
a/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/invalidation/4.cc
b/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/invalidation/4.cc
new file mode 100644
index 00000000000..7393f1ba4ee
--- /dev/null
+++
b/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/invalidation/4.cc
@@ -0,0 +1,40 @@
+// { dg-do run { target c++26 } }
+
+#include <debug/inplace_vector>
+#include <testsuite_hooks.h>
+
+using __gnu_debug::inplace_vector;
+
+// Erase
+void test04()
+{
+ inplace_vector<int, 30> v(20, 42);
+
+ // Single element erase
+ auto before = v.begin();
+ auto at = before + 3;
+ auto after = at;
+ at = v.erase(at);
+ VERIFY(before._M_dereferenceable());
+ VERIFY(at._M_dereferenceable());
+ VERIFY(after._M_singular());
+
+ // Multiple element erase
+ before = v.begin();
+ at = before + 3;
+ v.erase(at, at + 3);
+ VERIFY(before._M_dereferenceable());
+ VERIFY(at._M_singular());
+
+ // clear()
+ before = v.begin();
+ VERIFY(before._M_dereferenceable());
+ v.clear();
+ VERIFY(before._M_singular());
+}
+
+int main()
+{
+ test04();
+ return 0;
+}
diff --git
a/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/invalidation/append_range.cc
b/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/invalidation/append_range.cc
new file mode 100644
index 00000000000..8a793ec92b6
--- /dev/null
+++
b/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/invalidation/append_range.cc
@@ -0,0 +1,45 @@
+// { dg-do run { target c++26 } }
+
+#include <debug/inplace_vector>
+#include <testsuite_hooks.h>
+
+using __gnu_debug::inplace_vector;
+
+void test01()
+{
+ inplace_vector<int, 100> v(10, 17);
+ inplace_vector<int, 10> v1(10, 19);
+
+ auto before = v.begin() + 6;
+ auto last = v.end();
+ auto end = last--;
+
+ v.append_range(v1);
+
+ VERIFY(before._M_dereferenceable());
+ VERIFY(last._M_dereferenceable());
+ VERIFY(end._M_singular());
+}
+
+void test02()
+{
+ inplace_vector<int, 100> v(10, 17);
+ inplace_vector<int, 0> v1;
+
+ auto before = v.begin() + 6;
+ auto last = v.end();
+ auto end = last--;
+
+ v.append_range(v1);
+
+ VERIFY(before._M_dereferenceable());
+ VERIFY(last._M_dereferenceable());
+ VERIFY(!end._M_singular());
+}
+
+int main()
+{
+ test01();
+ test02();
+ return 0;
+}
diff --git
a/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/invalidation/erase.cc
b/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/invalidation/erase.cc
new file mode 100644
index 00000000000..6e899d72b79
--- /dev/null
+++
b/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/invalidation/erase.cc
@@ -0,0 +1,36 @@
+// { dg-do run { target c++26 } }
+
+#include <debug/inplace_vector>
+#include <testsuite_hooks.h>
+
+using __gnu_debug::inplace_vector;
+
+void test01()
+{
+ inplace_vector<int, 10> v;
+
+ for (int i = 0; i != 10; ++i)
+ v.push_back(i);
+
+ auto before = v.begin() + 4;
+ auto last = v.end() - 1;
+
+ VERIFY( std::erase(v, 6) == 1 );
+
+ VERIFY(before._M_dereferenceable());
+ VERIFY(last._M_singular());
+}
+
+void test02()
+{
+ inplace_vector<int, 0> v;
+
+ VERIFY( std::erase(v, 6) == 0 );
+}
+
+int main()
+{
+ test01();
+ test02();
+ return 0;
+}
diff --git
a/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/invalidation/pop_back.cc
b/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/invalidation/pop_back.cc
new file mode 100644
index 00000000000..4c1a0433887
--- /dev/null
+++
b/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/invalidation/pop_back.cc
@@ -0,0 +1,27 @@
+// { dg-do run { target c++26 } }
+
+#include <debug/inplace_vector>
+#include <testsuite_hooks.h>
+
+using __gnu_debug::inplace_vector;
+
+void test01()
+{
+ inplace_vector<int, 100> v(10, 17);
+
+ auto before = v.begin() + 6;
+ auto last = v.end();
+ auto end = last--;
+
+ v.pop_back();
+
+ VERIFY(before._M_dereferenceable());
+ VERIFY(last._M_singular());
+ VERIFY(end._M_singular());
+}
+
+int main()
+{
+ test01();
+ return 0;
+}
diff --git
a/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/invalidation/push_back.cc
b/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/invalidation/push_back.cc
new file mode 100644
index 00000000000..f269364cf5b
--- /dev/null
+++
b/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/invalidation/push_back.cc
@@ -0,0 +1,53 @@
+// { dg-do run { target c++26 } }
+
+#include <debug/inplace_vector>
+#include <testsuite_hooks.h>
+
+using __gnu_debug::inplace_vector;
+
+void test01()
+{
+ inplace_vector<int, 100> v(10, 17);
+
+ auto before = v.begin() + 6;
+ auto last = v.end();
+ auto end = last--;
+
+ v.push_back(42);
+
+ VERIFY(before._M_dereferenceable());
+ VERIFY(last._M_dereferenceable());
+ VERIFY(end._M_singular());
+}
+
+#if __cpp_exceptions
+void test02()
+{
+ inplace_vector<int, 10> v(10, 17);
+
+ auto before = v.begin() + 6;
+ auto last = v.end();
+ auto end = last--;
+ try
+ {
+ v.push_back(42);
+ VERIFY( false );
+ }
+ catch (std::bad_alloc&)
+ {
+ }
+
+ VERIFY(before._M_dereferenceable());
+ VERIFY(last._M_dereferenceable());
+ VERIFY(!end._M_singular());
+}
+#endif
+
+int main()
+{
+ test01();
+#if __cpp_exceptions
+ test02();
+#endif
+ return 0;
+}
diff --git
a/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/invalidation/swap.cc
b/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/invalidation/swap.cc
new file mode 100644
index 00000000000..3e5ab7409b6
--- /dev/null
+++
b/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/invalidation/swap.cc
@@ -0,0 +1,53 @@
+// { dg-do run { target c++26 } }
+
+#include <debug/inplace_vector>
+#include <testsuite_hooks.h>
+
+using __gnu_debug::inplace_vector;
+
+void test01()
+{
+ inplace_vector<int, 10> v1;
+ inplace_vector<int, 10> v2;
+
+ for (int i = 0; i != 10; ++i)
+ {
+ v1.push_back(i);
+ v2.push_back(i);
+ }
+
+ auto it1 = v1.begin();
+ auto it2 = v2.begin();
+
+ std::swap(v1, v2);
+
+ VERIFY(it1._M_singular());
+ VERIFY(it2._M_singular());
+}
+
+void test02()
+{
+ inplace_vector<int, 10> v1;
+ inplace_vector<int, 10> v2;
+
+ for (int i = 0; i != 10; ++i)
+ {
+ v1.push_back(i);
+ v2.push_back(i);
+ }
+
+ auto it1 = v1.begin();
+ auto it2 = v2.begin();
+
+ swap(v1, v2);
+
+ VERIFY(it1._M_singular());
+ VERIFY(it2._M_singular());
+}
+
+int main()
+{
+ test01();
+ test02();
+ return 0;
+}
diff --git
a/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/invalidation/try_append_range.cc
b/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/invalidation/try_append_range.cc
new file mode 100644
index 00000000000..ae4ac418f50
--- /dev/null
+++
b/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/invalidation/try_append_range.cc
@@ -0,0 +1,45 @@
+// { dg-do run { target c++26 } }
+
+#include <debug/inplace_vector>
+#include <testsuite_hooks.h>
+
+using __gnu_debug::inplace_vector;
+
+void test01()
+{
+ inplace_vector<int, 100> v(10, 17);
+ inplace_vector<int, 10> v1(10, 19);
+
+ auto before = v.begin() + 6;
+ auto last = v.end();
+ auto end = last--;
+
+ v.try_append_range(v1);
+
+ VERIFY(before._M_dereferenceable());
+ VERIFY(last._M_dereferenceable());
+ VERIFY(end._M_singular());
+}
+
+void test02()
+{
+ inplace_vector<int, 100> v(10, 17);
+ inplace_vector<int, 0> v1;
+
+ auto before = v.begin() + 6;
+ auto last = v.end();
+ auto end = last--;
+
+ v.try_append_range(v1);
+
+ VERIFY(before._M_dereferenceable());
+ VERIFY(last._M_dereferenceable());
+ VERIFY(!end._M_singular());
+}
+
+int main()
+{
+ test01();
+ test02();
+ return 0;
+}
diff --git
a/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/invalidation/try_emplace_back.cc
b/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/invalidation/try_emplace_back.cc
new file mode 100644
index 00000000000..f7c8c7a9ba2
--- /dev/null
+++
b/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/invalidation/try_emplace_back.cc
@@ -0,0 +1,27 @@
+// { dg-do run { target c++26 } }
+
+#include <debug/inplace_vector>
+#include <testsuite_hooks.h>
+
+using __gnu_debug::inplace_vector;
+
+void test01()
+{
+ inplace_vector<int, 100> v(10, 17);
+
+ auto before = v.begin() + 6;
+ auto last = v.end();
+ auto end = last--;
+
+ VERIFY( v.try_emplace_back(42) != nullptr );
+
+ VERIFY(before._M_dereferenceable());
+ VERIFY(last._M_dereferenceable());
+ VERIFY(end._M_singular());
+}
+
+int main()
+{
+ test01();
+ return 0;
+}
diff --git
a/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/invalidation/try_push_back.cc
b/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/invalidation/try_push_back.cc
new file mode 100644
index 00000000000..04fc010e500
--- /dev/null
+++
b/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/invalidation/try_push_back.cc
@@ -0,0 +1,45 @@
+// { dg-do run { target c++26 } }
+
+#include <debug/inplace_vector>
+#include <vector>
+#include <testsuite_hooks.h>
+
+using __gnu_debug::inplace_vector;
+
+void test01()
+{
+ inplace_vector<int, 100> v(10, 17);
+
+ auto before = v.begin() + 6;
+ auto last = v.end();
+ auto end = last--;
+
+ VERIFY( v.try_push_back(42) != nullptr );
+
+ VERIFY(before._M_dereferenceable());
+ VERIFY(last._M_dereferenceable());
+ VERIFY(end._M_singular());
+}
+
+void test02()
+{
+ std::vector<int> vv { 0, 1, 2, 3, 4, 5 };
+ inplace_vector<std::vector<int>, 100> v(10, vv);
+
+ auto before = v.begin() + 6;
+ auto last = v.end();
+ auto end = last--;
+
+ VERIFY( v.try_push_back(std::move(vv)) != nullptr );
+
+ VERIFY(before._M_dereferenceable());
+ VERIFY(last._M_dereferenceable());
+ VERIFY(end._M_singular());
+}
+
+int main()
+{
+ test01();
+ test02();
+ return 0;
+}
diff --git
a/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/invalidation/unchecked_emplace_back.cc
b/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/invalidation/unchecked_emplace_back.cc
new file mode 100644
index 00000000000..0d173d5885d
--- /dev/null
+++
b/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/invalidation/unchecked_emplace_back.cc
@@ -0,0 +1,27 @@
+// { dg-do run { target c++26 } }
+
+#include <debug/inplace_vector>
+#include <testsuite_hooks.h>
+
+using __gnu_debug::inplace_vector;
+
+void test01()
+{
+ inplace_vector<int, 100> v(10, 17);
+
+ auto before = v.begin() + 6;
+ auto last = v.end();
+ auto end = last--;
+
+ v.unchecked_emplace_back(42);
+
+ VERIFY(before._M_dereferenceable());
+ VERIFY(last._M_dereferenceable());
+ VERIFY(end._M_singular());
+}
+
+int main()
+{
+ test01();
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/inplace_vector/move.cc
b/libstdc++-v3/testsuite/23_containers/inplace_vector/move.cc
index 5abcc8764bd..e8703e027fe 100644
--- a/libstdc++-v3/testsuite/23_containers/inplace_vector/move.cc
+++ b/libstdc++-v3/testsuite/23_containers/inplace_vector/move.cc
@@ -91,12 +91,14 @@
static_assert(!std::is_nothrow_move_constructible_v<std::inplace_vector<N<false,
static_assert(std::is_nothrow_move_constructible_v<std::inplace_vector<D, 2>>);
static_assert(!std::is_nothrow_move_constructible_v<std::inplace_vector<U,
2>>);
+#if !_GLIBCXX_DEBUG
static_assert(std::is_trivially_move_constructible_v<std::inplace_vector<int,
2>>);
static_assert(!std::is_trivially_move_constructible_v<std::inplace_vector<X,
2>>);
static_assert(!std::is_trivially_move_constructible_v<std::inplace_vector<N<true,
true>, 2>>);
// is_trivially_move_constructible_v checks destructor
static_assert(!std::is_trivially_move_constructible_v<std::inplace_vector<D,
2>>);
static_assert(std::is_trivially_move_constructible_v<std::inplace_vector<U,
2>>);
+#endif
static_assert(std::is_move_assignable_v<std::inplace_vector<int, 2>>);
static_assert(std::is_move_assignable_v<std::inplace_vector<X, 2>>);
@@ -115,12 +117,14 @@
static_assert(!std::is_nothrow_move_assignable_v<std::inplace_vector<N<false, fa
static_assert(std::is_nothrow_move_assignable_v<std::inplace_vector<D, 2>>);
static_assert(!std::is_nothrow_move_assignable_v<std::inplace_vector<U, 2>>);
+#if !_GLIBCXX_DEBUG
static_assert(std::is_trivially_move_assignable_v<std::inplace_vector<int,
2>>);
static_assert(!std::is_trivially_move_assignable_v<std::inplace_vector<X, 2>>);
static_assert(!std::is_trivially_move_assignable_v<std::inplace_vector<N<true,
true>, 2>>);
// destructor is not trivial
static_assert(!std::is_trivially_move_assignable_v<std::inplace_vector<D, 2>>);
static_assert(std::is_trivially_move_assignable_v<std::inplace_vector<U, 2>>);
+#endif
static_assert(std::is_nothrow_swappable_v<std::inplace_vector<int, 2>>);
static_assert(!std::is_nothrow_swappable_v<std::inplace_vector<X, 2>>);
diff --git a/libstdc++-v3/testsuite/util/debug/checks.h
b/libstdc++-v3/testsuite/util/debug/checks.h
index 938cddabf6d..528c021b1d7 100644
--- a/libstdc++-v3/testsuite/util/debug/checks.h
+++ b/libstdc++-v3/testsuite/util/debug/checks.h
@@ -19,10 +19,12 @@
#include <vector>
#include <deque>
#include <list>
+#include <inplace_vector>
#ifndef _GLIBCXX_DEBUG
# include <debug/vector>
# include <debug/deque>
# include <debug/list>
+# include <debug/inplace_vector>
#endif
#include <testsuite_hooks.h>
@@ -88,10 +90,11 @@ namespace __gnu_test
void
check_assign1()
{
+ using namespace std;
typedef _Tp cont_type;
typedef typename cont_type::value_type cont_val_type;
typedef typename CopyableValueType<cont_val_type>::value_type val_type;
- typedef std::vector<val_type> vector_type;
+ typedef _GLIBCXX_STD_C::vector<val_type> vector_type;
generate_unique<val_type> gu;
@@ -116,10 +119,11 @@ namespace __gnu_test
void
check_assign2()
{
+ using namespace std;
typedef _Tp cont_type;
typedef typename cont_type::value_type cont_val_type;
typedef typename CopyableValueType<cont_val_type>::value_type val_type;
- typedef std::vector<val_type> vector_type;
+ typedef _GLIBCXX_STD_C::vector<val_type> vector_type;
generate_unique<val_type> gu;
@@ -170,10 +174,11 @@ namespace __gnu_test
void
check_construct1()
{
+ using namespace std;
typedef _Tp cont_type;
typedef typename cont_type::value_type cont_val_type;
typedef typename CopyableValueType<cont_val_type>::value_type val_type;
- typedef std::vector<val_type> vector_type;
+ typedef _GLIBCXX_STD_C::vector<val_type> vector_type;
generate_unique<val_type> gu;
@@ -193,10 +198,11 @@ namespace __gnu_test
void
check_construct2()
{
+ using namespace std;
typedef _Tp cont_type;
typedef typename cont_type::value_type cont_val_type;
typedef typename CopyableValueType<cont_val_type>::value_type val_type;
- typedef std::vector<val_type> vector_type;
+ typedef _GLIBCXX_STD_C::vector<val_type> vector_type;
generate_unique<val_type> gu;
@@ -267,6 +273,13 @@ namespace __gnu_test
: InsertRangeHelperAux<std::list<_Tp1, _Tp2> >
{ };
+#ifdef __glibcxx_inplace_vector // C++ >= 26
+ template<typename _Tp, size_t _Nm>
+ struct InsertRangeHelper<std::inplace_vector<_Tp, _Nm> >
+ : InsertRangeHelperAux<std::inplace_vector<_Tp, _Nm> >
+ { };
+#endif
+
#ifndef _GLIBCXX_DEBUG
template <typename _Tp1, typename _Tp2>
struct InsertRangeHelper<__gnu_debug::vector<_Tp1, _Tp2> >
@@ -282,16 +295,24 @@ namespace __gnu_test
struct InsertRangeHelper<__gnu_debug::list<_Tp1, _Tp2> >
: InsertRangeHelperAux<__gnu_debug::list<_Tp1, _Tp2> >
{ };
+
+# ifdef __glibcxx_inplace_vector // C++ >= 26
+ template<typename _Tp, size_t _Nm>
+ struct InsertRangeHelper<__gnu_debug::inplace_vector<_Tp, _Nm> >
+ : InsertRangeHelperAux<__gnu_debug::inplace_vector<_Tp, _Nm> >
+ { };
+# endif
#endif
template<typename _Tp>
void
check_insert1()
{
+ using namespace std;
typedef _Tp cont_type;
typedef typename cont_type::value_type cont_val_type;
typedef typename CopyableValueType<cont_val_type>::value_type val_type;
- typedef std::vector<val_type> vector_type;
+ typedef _GLIBCXX_STD_C::vector<val_type> vector_type;
generate_unique<val_type> gu;
@@ -315,10 +336,11 @@ namespace __gnu_test
void
check_insert2()
{
+ using namespace std;
typedef _Tp cont_type;
typedef typename cont_type::value_type cont_val_type;
typedef typename CopyableValueType<cont_val_type>::value_type val_type;
- typedef std::vector<val_type> vector_type;
+ typedef _GLIBCXX_STD_C::vector<val_type> vector_type;
generate_unique<val_type> gu;
@@ -369,10 +391,11 @@ namespace __gnu_test
void
check_insert4()
{
+ using namespace std;
typedef _Tp cont_type;
typedef typename cont_type::value_type cont_val_type;
typedef typename CopyableValueType<cont_val_type>::value_type val_type;
- typedef std::list<val_type> list_type;
+ typedef _GLIBCXX_STD_C::list<val_type> list_type;
generate_unique<val_type> gu;