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
On 11/3/25 22:17, François Dumont wrote:
Hi
Here is v2 with swap defined as inline friend.
I also did some simplifications like reducing the number of calls to
std::is_constant_evaluated.
François
On 11/3/25 07:23, François Dumont wrote:
On 11/3/25 07:08, François Dumont wrote:
On 11/2/25 04:09, Jonathan Wakely wrote:
On Sat, 1 Nov 2025, 21:10 François Dumont, <[email protected]>
wrote:
Hi
Here is the implementation of the std::__debug::inplace_vector.
It looks like this is going to repeat the assertions in e.g.
operator[], front, back etc because those already have assertions
in the base class.
This is I think unavoidable if you want to cover direct usages of
__gnu_debug::inplace_vector like in
23_containers/inplace_vector/debug/invalidation/*.cc tests.
I eventually had to introduce a dedicated std::erase_if/std::erase
implementation for the __debug version. When directly using
__gnu_debug::inplace_vector the std::erase_if was used
downcasting the
If it's converting to a base, it's upcasting.
inplace_vector into the std::inplace_vector base class so breaking
encapsulation. So we really need dedicated implementations and
I'll
prepare patches for other containers.
Why is the implicit cast a problem? We know that erase_if doesn't
iterate past the end, and only dereferences valid iterators. That's
one of the benefits of using erase_if: it ensures the container is
accessed safely.
The problem is that the std::__debug::inplace_vector is not aware of
the invalidated iterators.
Is encapsulation broken if a standard library function does that
implicit cast? Is it observable to users?
Yes, some iterators might not be invalidated as they should.
I also added tests for std::swap. Overloading it in std::
namespace
seems the best option to me. If it is defined in std::__debug::
as it
should then calls to std::swap in user code are replaced by the
generic
call to swap in move.h instead of calling inplace_vector<>::swap.
Users should call swap not std::swap. That was the consensus when
LWG discussed https://cplusplus.github.io/LWG/issue4250
Ok, I'll remove the test case with the call to std::swap then.
Should erase_if/erase be considered the same ?
It's the same problem with any standard library function that can
modify the container.
It
still works to invalidate iterators but is a major performance
issue. I
noticed this running in gdb, is there a way to test for call to
the
correct swap ?
I also wonder in
testsuite/23_containers/inplace_vector/debug/invalidation/swap.cc
test02
how gcc does to find the proper swap method on the unqualified
call ?
Argument Dependent Lookup ?
That's what it should be but container is in std::__debug:: whereas
the swap definition is in std::.
I'll have some more tests but with your remark above I think I'll
just defined swap as friend in std::__debug::inplace_vector like
it's done in std::inplace_vector.
Add _GLIBCXX_DEBUG std::inplace_vector implementation.
Unlike other _GLIBCXX_DEBUG containers the
std::__debug::inplace_vector is
inheriting privately from both
__gnu_debug::_Safe_sequence<> and
std::inplace_vector
classes to preserve encapsulation. Iterators won't be
created or
invalidated without
std::__debug::inplace_vector being aware. However
std::__debug::inplace_vector<T, 0>
inherits publicly from std::inplace_vector<T, 0> to
benefit from
the same std::
functions overloads.
libstdc++-v3/ChangeLog:
* include/Makefile.am (debug_headers): Add
inplace_vector.
* include/Makefile.in: Regenerate.
* include/debug/inplace_vector: New.
* include/debug/safe_base.h
(~_Safe_sequence_base()): Add
C++11 noexcept
qualification.
(_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 qualification.
* 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/23_containers/inplace_vector/debug/multithreaded_swap.cc:
New
test case.
* testsuite/util/debug/checks.h: Avoid using
_GLIBCXX_DEBUG
containers in test
implementations.
Tested under Linux x86_64.
Ok to commit ?
PR: https://forge.sourceware.org/gcc/gcc-TEST/pulls/119
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
+
+#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;
+
+ 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;
+
+ ~inplace_vector()
+ requires is_trivially_destructible_v<_Tp>
+ = default;
+
+ constexpr
+ ~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;
+
+ 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));
+
+ 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();
+ }
+
+ 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 _Base::front();
+ }
+
+ [[nodiscard]]
+ constexpr const_reference
+ front() const
+ {
+ __glibcxx_check_nonempty();
+ return _Base::front();
+ }
+
+ [[nodiscard]]
+ constexpr reference
+ back()
+ {
+ __glibcxx_check_nonempty();
+ return _Base::back();
+ }
+
+ [[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));
+
+ 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);
+ }
+
+ 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);
+
+ 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);
+ 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)
+ { 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);
+ 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);
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/std/inplace_vector
b/libstdc++-v3/include/std/inplace_vector
index 7aa6f9d4ab2..ea73348a684 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,36 @@ _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)
{
- __cont.erase(__niter_wrap(__cont.begin(), __removed),
- __cont.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..879e250141f
--- /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 after = std::next(before, 4);
+
+ VERIFY( std::erase(v, 6) == 1 );
+
+ VERIFY(before._M_dereferenceable());
+ VERIFY(after._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..e54bcfcf5ee
--- /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..0571973c78f
--- /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 after = std::next(before, 4);
+
+ VERIFY( std::erase(v, 6) == 1 );
+
+ VERIFY(before._M_dereferenceable());
+ VERIFY(after._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;