]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
libstdc++: [_GLIBCXX_DEBUG] Implement std::__debug::inplace_vector
authorFrançois Dumont <frs.dumont@gmail.com>
Mon, 22 Sep 2025 16:58:52 +0000 (18:58 +0200)
committerFrançois Dumont <fdumont@gcc.gnu.org>
Wed, 3 Dec 2025 05:56:27 +0000 (06:56 +0100)
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/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.

45 files changed:
libstdc++-v3/include/Makefile.am
libstdc++-v3/include/Makefile.in
libstdc++-v3/include/debug/functions.h
libstdc++-v3/include/debug/helper_functions.h
libstdc++-v3/include/debug/inplace_vector [new file with mode: 0644]
libstdc++-v3/include/debug/safe_base.h
libstdc++-v3/include/debug/safe_container.h
libstdc++-v3/include/debug/safe_iterator.h
libstdc++-v3/include/debug/safe_sequence.h
libstdc++-v3/include/debug/safe_sequence.tcc
libstdc++-v3/include/std/inplace_vector
libstdc++-v3/testsuite/23_containers/inplace_vector/cons/1.cc
libstdc++-v3/testsuite/23_containers/inplace_vector/copy.cc
libstdc++-v3/testsuite/23_containers/inplace_vector/debug/assign1_neg.cc [new file with mode: 0644]
libstdc++-v3/testsuite/23_containers/inplace_vector/debug/assign2_neg.cc [new file with mode: 0644]
libstdc++-v3/testsuite/23_containers/inplace_vector/debug/assign3_neg.cc [new file with mode: 0644]
libstdc++-v3/testsuite/23_containers/inplace_vector/debug/assign4_backtrace_neg.cc [new file with mode: 0644]
libstdc++-v3/testsuite/23_containers/inplace_vector/debug/assign4_neg.cc [new file with mode: 0644]
libstdc++-v3/testsuite/23_containers/inplace_vector/debug/construct1_neg.cc [new file with mode: 0644]
libstdc++-v3/testsuite/23_containers/inplace_vector/debug/construct2_neg.cc [new file with mode: 0644]
libstdc++-v3/testsuite/23_containers/inplace_vector/debug/construct3_neg.cc [new file with mode: 0644]
libstdc++-v3/testsuite/23_containers/inplace_vector/debug/construct4_neg.cc [new file with mode: 0644]
libstdc++-v3/testsuite/23_containers/inplace_vector/debug/debug_functions.cc [new file with mode: 0644]
libstdc++-v3/testsuite/23_containers/inplace_vector/debug/erase.cc [new file with mode: 0644]
libstdc++-v3/testsuite/23_containers/inplace_vector/debug/insert1_neg.cc [new file with mode: 0644]
libstdc++-v3/testsuite/23_containers/inplace_vector/debug/insert2_neg.cc [new file with mode: 0644]
libstdc++-v3/testsuite/23_containers/inplace_vector/debug/insert3_neg.cc [new file with mode: 0644]
libstdc++-v3/testsuite/23_containers/inplace_vector/debug/insert4_neg.cc [new file with mode: 0644]
libstdc++-v3/testsuite/23_containers/inplace_vector/debug/insert5_neg.cc [new file with mode: 0644]
libstdc++-v3/testsuite/23_containers/inplace_vector/debug/insert7_neg.cc [new file with mode: 0644]
libstdc++-v3/testsuite/23_containers/inplace_vector/debug/invalidation/1.cc [new file with mode: 0644]
libstdc++-v3/testsuite/23_containers/inplace_vector/debug/invalidation/2.cc [new file with mode: 0644]
libstdc++-v3/testsuite/23_containers/inplace_vector/debug/invalidation/3.cc [new file with mode: 0644]
libstdc++-v3/testsuite/23_containers/inplace_vector/debug/invalidation/4.cc [new file with mode: 0644]
libstdc++-v3/testsuite/23_containers/inplace_vector/debug/invalidation/append_range.cc [new file with mode: 0644]
libstdc++-v3/testsuite/23_containers/inplace_vector/debug/invalidation/erase.cc [new file with mode: 0644]
libstdc++-v3/testsuite/23_containers/inplace_vector/debug/invalidation/pop_back.cc [new file with mode: 0644]
libstdc++-v3/testsuite/23_containers/inplace_vector/debug/invalidation/push_back.cc [new file with mode: 0644]
libstdc++-v3/testsuite/23_containers/inplace_vector/debug/invalidation/swap.cc [new file with mode: 0644]
libstdc++-v3/testsuite/23_containers/inplace_vector/debug/invalidation/try_append_range.cc [new file with mode: 0644]
libstdc++-v3/testsuite/23_containers/inplace_vector/debug/invalidation/try_emplace_back.cc [new file with mode: 0644]
libstdc++-v3/testsuite/23_containers/inplace_vector/debug/invalidation/try_push_back.cc [new file with mode: 0644]
libstdc++-v3/testsuite/23_containers/inplace_vector/debug/invalidation/unchecked_emplace_back.cc [new file with mode: 0644]
libstdc++-v3/testsuite/23_containers/inplace_vector/move.cc
libstdc++-v3/testsuite/util/debug/checks.h

index ae7a7ca9073ad2b5acae36f4096a8fbf1fa8d39a..7d65c6f3ab312415f47068f0018929b993e21d0f 100644 (file)
@@ -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 \
index f07e2326816b0bf899815b918774049424fcc7e2..acf8ae9be441c635073f1e0f78e0207672a7f975 100644 (file)
@@ -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 \
index c5f5582b0050d21b2b19e3081ba45017d62246a7..4e6fdae7193575c6fd3eb0594fdbabfdd1aec02d 100644 (file)
@@ -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;
     }
 
index 9395892b537c5768ddc10baf30beaa1e7d02b2fa..b9771034bf348f117ea5f419b518a0ed70fe7f39 100644 (file)
@@ -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 (file)
index 0000000..c7e301e
--- /dev/null
@@ -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
index 44622970792b3255d2bcb5126200a97ed1f053a9..7491cc0ebe2f10fafe9a832a3ae63976a15d7834 100644 (file)
@@ -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; }
 
index 3341806fd596f841421b94b3c8f474d2ba52d427..2d0fbb8110e0a3bdd2583343af47f88f1a3d57f2 100644 (file)
@@ -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
     };
 
index e0b1b46939c3c3f45a30d6cc70790729e4f929a3..80ed9570ecb472ded5eaaa9b9183d61e131663a9 100644 (file)
@@ -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);
     }
index e10474aae79ca74b4202cda093e2bf42341b23b7..c908d1e47a90368a3a14f3b1c260a1a8ab35f382 100644 (file)
@@ -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;
index 053361dff3c058c3a6779b2d64a35f2b9618cbef..720a1842752525400977f004597b7921b25440f5 100644 (file)
@@ -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;
 
index 7aa6f9d4ab28941cd971339da1d1993cbc3dc694..0f7716cb64de8dfd48e8d7e9aa8e17742a6c9d32 100644 (file)
@@ -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
index e9c2cdc8665a6eb0fd90a4e23d0ac963cc70a050..45685c2beccff34ddc22a41e8a3f45d71d1ccefb 100644 (file)
@@ -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>>);
index d149e63970c9c04c9bb2c9419aaa0a2644b8940a..917eebd80f7c5633f2c9ebf697408e085452409b 100644 (file)
@@ -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 (file)
index 0000000..37c80c3
--- /dev/null
@@ -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 (file)
index 0000000..ff6c9a7
--- /dev/null
@@ -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 (file)
index 0000000..42f811d
--- /dev/null
@@ -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 (file)
index 0000000..dec7228
--- /dev/null
@@ -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 (file)
index 0000000..4bed345
--- /dev/null
@@ -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 (file)
index 0000000..28ede4c
--- /dev/null
@@ -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 (file)
index 0000000..be37dde
--- /dev/null
@@ -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 (file)
index 0000000..8086183
--- /dev/null
@@ -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 (file)
index 0000000..099b357
--- /dev/null
@@ -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 (file)
index 0000000..bc5ed50
--- /dev/null
@@ -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 (file)
index 0000000..94da946
--- /dev/null
@@ -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 (file)
index 0000000..f85cfaa
--- /dev/null
@@ -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 (file)
index 0000000..6a20369
--- /dev/null
@@ -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 (file)
index 0000000..63f6e05
--- /dev/null
@@ -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 (file)
index 0000000..59e9f4b
--- /dev/null
@@ -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 (file)
index 0000000..e1fbd65
--- /dev/null
@@ -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 (file)
index 0000000..c59453c
--- /dev/null
@@ -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 (file)
index 0000000..1a85273
--- /dev/null
@@ -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 (file)
index 0000000..22d512c
--- /dev/null
@@ -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 (file)
index 0000000..7b74213
--- /dev/null
@@ -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 (file)
index 0000000..7393f1b
--- /dev/null
@@ -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 (file)
index 0000000..8a793ec
--- /dev/null
@@ -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 (file)
index 0000000..6e899d7
--- /dev/null
@@ -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 (file)
index 0000000..4c1a043
--- /dev/null
@@ -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 (file)
index 0000000..f269364
--- /dev/null
@@ -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 (file)
index 0000000..3e5ab74
--- /dev/null
@@ -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 (file)
index 0000000..ae4ac41
--- /dev/null
@@ -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 (file)
index 0000000..f7c8c7a
--- /dev/null
@@ -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 (file)
index 0000000..04fc010
--- /dev/null
@@ -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 (file)
index 0000000..0d173d5
--- /dev/null
@@ -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;
+}
index 5abcc8764bd5fc20216a3dc282e4098f8ccdcfb4..e8703e027fe3f4ee1b0bb6b91ce76ad27a236b47 100644 (file)
@@ -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>>);
index 938cddabf6d3d8eb26f1af708fba7447f0162497..528c021b1d75a113a9b808ae29671711e0606965 100644 (file)
 #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;