[PATCH] libstdc++: Updated inplace_vector::try_ functions per P3981R2 and P4022R0.

Nathan Myers ncm@cantrip.org
Thu Apr 2 12:29:36 GMT 2026


LGTM.

About testsuite/23_containers/inplace_vector/version.cc ...
Should I have counterparts to this test for other feature
macros I add or alter?


On 4/2/26 6:41 AM, Tomasz Kamiński wrote:
> This paper removes the try_append_range from inplace_vector and changes the
> return type of try_emplace_back and try_push_back to optional<_Tp&> per:
> P4022R0: Remove try_append_range from inplace_vector for now.
> P3981R2: Better return types in std::inplace_vector and std::exception_ptr_cast.
> 
> The test are also expanded to cover type Y, that is convertible to optional<Y&>,
> and require return type to be constructed using in_place.
> 
> libstdc++-v3/ChangeLog:
> 
> 	* include/bits/version.def (inplace_vector): Bump to 202603.
> 	* include/bits/version.h: Regenerate.
> 	* include/std/inplace_vector (inplace_vector::try_emplace_back)
> 	(inplace_vector::try_push_back): Change return type to optional<_Tp&>
> 	and adjust implementation accordingly.
> 	(inplace_vector::try_append_range): Remove.
> 	* include/debug/inplace_vector (inplace_vector::try_emplace_back)
> 	(inplace_vector::try_push_back, inplace_vector::try_append_range):
> 	Likewise.
> 	* testsuite/23_containers/inplace_vector/modifiers/single_insert.cc:
> 	Updated check for the optional<T&> return. Added test for type
> 	convertible to optional<T&>
> 	* testsuite/23_containers/inplace_vector/debug/invalidation/try_emplace_back.cc:
> 	Use has_value() to check if engaged optional is returned.
> 	* testsuite/23_containers/inplace_vector/debug/invalidation/try_push_back.cc:
> 	Likewise.
> 	* testsuite/23_containers/inplace_vector/modifiers/multi_insert.cc:
> 	Remove try_append_range tests.
> 	* testsuite/23_containers/inplace_vector/debug/invalidation/try_append_range.cc:
> 	Removed.
> 	* testsuite/23_containers/inplace_vector/version.cc: Updated expected
> 	feature test macro value.
> ---
> The exception_ptr change need to be handled seprately, due it being
> defined in libsup++.
> 
> Testing on x86_64-linux. All *inplace_vector* test already passed.
> OK for trunk if all test finishes?
> 
>   libstdc++-v3/include/bits/version.def         |  5 +-
>   libstdc++-v3/include/bits/version.h           |  4 +-
>   libstdc++-v3/include/debug/inplace_vector     | 26 ++-----
>   libstdc++-v3/include/std/inplace_vector       | 70 +++++--------------
>   .../debug/invalidation/try_append_range.cc    | 45 ------------
>   .../debug/invalidation/try_emplace_back.cc    |  2 +-
>   .../debug/invalidation/try_push_back.cc       |  4 +-
>   .../inplace_vector/modifiers/multi_insert.cc  | 46 ------------
>   .../inplace_vector/modifiers/single_insert.cc | 41 ++++++++---
>   .../23_containers/inplace_vector/version.cc   |  4 +-
>   10 files changed, 66 insertions(+), 181 deletions(-)
>   delete mode 100644 libstdc++-v3/testsuite/23_containers/inplace_vector/debug/invalidation/try_append_range.cc
> 
> diff --git a/libstdc++-v3/include/bits/version.def b/libstdc++-v3/include/bits/version.def
> index ada8da88bc5..998223306e2 100644
> --- a/libstdc++-v3/include/bits/version.def
> +++ b/libstdc++-v3/include/bits/version.def
> @@ -2223,9 +2223,12 @@ ftms = {
>   };
>   
>   ftms = {
> +  // 202406 P0843R14 inplace_vector
> +  // 202603 P3981R2 Better return types in std::inplace_vector and std::exception_ptr_cast
> +  //        P4022R0 Remove try_append_range from inplace_vector for now
>     name = inplace_vector;
>     values = {
> -    v = 202406;
> +    v = 202603;
>       cxxmin = 26;
>     };
>   };
> diff --git a/libstdc++-v3/include/bits/version.h b/libstdc++-v3/include/bits/version.h
> index 0490e79dd41..cb3b9b0997e 100644
> --- a/libstdc++-v3/include/bits/version.h
> +++ b/libstdc++-v3/include/bits/version.h
> @@ -2488,9 +2488,9 @@
>   
>   #if !defined(__cpp_lib_inplace_vector)
>   # if (__cplusplus >  202302L)
> -#  define __glibcxx_inplace_vector 202406L
> +#  define __glibcxx_inplace_vector 202603L
>   #  if defined(__glibcxx_want_all) || defined(__glibcxx_want_inplace_vector)
> -#   define __cpp_lib_inplace_vector 202406L
> +#   define __cpp_lib_inplace_vector 202603L
>   #  endif
>   # endif
>   #endif /* !defined(__cpp_lib_inplace_vector) */
> diff --git a/libstdc++-v3/include/debug/inplace_vector b/libstdc++-v3/include/debug/inplace_vector
> index 750b0a7343c..e579e8636f9 100644
> --- a/libstdc++-v3/include/debug/inplace_vector
> +++ b/libstdc++-v3/include/debug/inplace_vector
> @@ -338,11 +338,12 @@ namespace __debug
>         }
>   
>         template<typename... _Args>
> -	constexpr _Tp*
> +	constexpr optional<_Tp&>
>   	try_emplace_back(_Args&&... __args)
>   	{
>   	  auto __end = _Base::cend();
> -	  _Tp* __res = _Base::try_emplace_back(std::forward<_Args>(__args)...);
> +	  optional<_Tp&> __res
> +	    = _Base::try_emplace_back(std::forward<_Args>(__args)...);
>   
>   	  if (__res)
>   	    this->_M_invalidate_if(_Equal(__end));
> @@ -350,11 +351,11 @@ namespace __debug
>   	  return __res;
>   	}
>   
> -      constexpr _Tp*
> +      constexpr optional<_Tp&>
>         try_push_back(const _Tp& __x)
>         {
>   	const auto __end = _Base::cend();
> -	_Tp* __res = _Base::try_push_back(__x);
> +	optional<_Tp&> __res = _Base::try_push_back(__x);
>   
>   	if (__res)
>   	  this->_M_invalidate_if(_Equal(__end));
> @@ -362,11 +363,11 @@ namespace __debug
>   	return __res;
>         }
>   
> -      constexpr _Tp*
> +      constexpr optional<_Tp&>
>         try_push_back(_Tp&& __x)
>         {
>   	const auto __end = _Base::cend();
> -	_Tp* __res = _Base::try_push_back(std::move(__x));
> +	optional<_Tp&> __res = _Base::try_push_back(std::move(__x));
>   
>   	if (__res)
>   	  this->_M_invalidate_if(_Equal(__end));
> @@ -374,19 +375,6 @@ namespace __debug
>   	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)
> diff --git a/libstdc++-v3/include/std/inplace_vector b/libstdc++-v3/include/std/inplace_vector
> index c22a9e1f9b4..5ad92332a02 100644
> --- a/libstdc++-v3/include/std/inplace_vector
> +++ b/libstdc++-v3/include/std/inplace_vector
> @@ -38,6 +38,7 @@
>   #ifdef __glibcxx_inplace_vector // C++ >= 26
>   #include <compare>
>   #include <initializer_list>
> +#include <optional>
>   #include <bits/stdexcept_throw.h>
>   #include <bits/range_access.h>
>   #include <bits/ranges_base.h> // borrowed_iterator_t, __detail::__container_compatible_range
> @@ -550,63 +551,31 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
>         }
>   
>         template<typename... _Args>
> -	constexpr _Tp*
> +	constexpr optional<_Tp&>
>   	try_emplace_back(_Args&&... __args)
>   	{
>   	  if (_M_size >= _Nm) [[unlikely]]
> -	    return nullptr;
> -	  auto& __r = unchecked_emplace_back(std::forward<_Args>(__args)...);
> -	  return __builtin_addressof(__r);
> +	    return nullopt;
> +	  return optional<_Tp&>(in_place,
> +		   unchecked_emplace_back(std::forward<_Args>(__args)...));
>   	}
>   
> -      constexpr _Tp*
> +      constexpr optional<_Tp&>
>         try_push_back(const _Tp& __x)
>         {
>   	if (_M_size >= _Nm) [[unlikely]]
> -	  return nullptr;
> -	return __builtin_addressof(unchecked_emplace_back(__x));
> +	  return nullopt;
> +	return optional<_Tp&>(in_place, unchecked_emplace_back(__x));
>         }
>   
> -      constexpr _Tp*
> +      constexpr optional<_Tp&>
>         try_push_back(_Tp&& __x)
>         {
>   	if (_M_size >= _Nm) [[unlikely]]
> -	  return nullptr;
> -	return __builtin_addressof(unchecked_emplace_back(std::move(__x)));
> +	  return nullopt;
> +	return optional<_Tp&>(in_place, unchecked_emplace_back(std::move(__x)));
>         }
>   
> -      template<__detail::__container_compatible_range<_Tp> _Rg>
> -	constexpr ranges::borrowed_iterator_t<_Rg>
> -	try_append_range(_Rg&& __rg)
> -	{
> -	  if constexpr (ranges::sized_range<_Rg>)
> -	    {
> -	      auto __n = ranges::distance(__rg);
> -	      if (__n == 0) [[unlikely]]
> -		return ranges::begin(__rg);
> -
> -	      const auto __end = data() + _M_size;
> -	      const size_t __avail = _Nm - size();
> -	      if (__n <= __avail)
> -		_M_size += size_type(__n);
> -	      else
> -		{
> -		  __n = __avail;
> -		  _M_size = _Nm;
> -		}
> -	      return ranges::uninitialized_copy_n(
> -		       ranges::begin(__rg), __n,
> -		       __end, unreachable_sentinel).in;
> -	    }
> -	  else
> -	    {
> -	      ranges::subrange<pointer> __tail(data() + _M_size, data() + _Nm);
> -	      auto [__in, __out] = ranges::uninitialized_copy(__rg, __tail);
> -	      _M_size = __out - data();
> -	      return std::move(__in);
> -	    }
> -	}
> -
>         template<typename... _Args>
>   	constexpr _Tp&
>   	unchecked_emplace_back(_Args&&... __args)
> @@ -1208,22 +1177,17 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
>         { __builtin_trap(); }
>   
>         template<typename... _Args>
> -	constexpr _Tp*
> +        constexpr optional<_Tp&>
>   	try_emplace_back(_Args&&...)
> -	{ return nullptr; }
> +	{ return nullopt; }
>   
> -      constexpr _Tp*
> +      constexpr optional<_Tp&>
>         try_push_back(const _Tp&)
> -      { return nullptr; }
> +      { return nullopt; }
>   
> -      constexpr _Tp*
> +      constexpr optional<_Tp&>
>         try_push_back(_Tp&&)
> -      { return nullptr; }
> -
> -      template<__detail::__container_compatible_range<_Tp> _Rg>
> -	constexpr ranges::borrowed_iterator_t<_Rg>
> -	try_append_range(_Rg&& __rg)
> -	{ return ranges::begin(__rg); }
> +      { return nullopt; }
>   
>         template<typename... _Args>
>   	[[noreturn]]
> 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
> deleted file mode 100644
> index ae4ac418f50..00000000000
> --- a/libstdc++-v3/testsuite/23_containers/inplace_vector/debug/invalidation/try_append_range.cc
> +++ /dev/null
> @@ -1,45 +0,0 @@
> -// { 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
> index f7c8c7a9ba2..606d478a0dc 100644
> --- 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
> @@ -13,7 +13,7 @@ void test01()
>     auto last = v.end();
>     auto end = last--;
>   
> -  VERIFY( v.try_emplace_back(42) != nullptr );
> +  VERIFY( v.try_emplace_back(42).has_value() );
>   
>     VERIFY(before._M_dereferenceable());
>     VERIFY(last._M_dereferenceable());
> 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
> index 04fc010e500..96af2b65b72 100644
> --- 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
> @@ -14,7 +14,7 @@ void test01()
>     auto last = v.end();
>     auto end = last--;
>   
> -  VERIFY( v.try_push_back(42) != nullptr );
> +  VERIFY( v.try_push_back(42).has_value() );
>   
>     VERIFY(before._M_dereferenceable());
>     VERIFY(last._M_dereferenceable());
> @@ -30,7 +30,7 @@ void test02()
>     auto last = v.end();
>     auto end = last--;
>   
> -  VERIFY( v.try_push_back(std::move(vv)) != nullptr );
> +  VERIFY( v.try_push_back(std::move(vv)).has_value() );
>   
>     VERIFY(before._M_dereferenceable());
>     VERIFY(last._M_dereferenceable());
> diff --git a/libstdc++-v3/testsuite/23_containers/inplace_vector/modifiers/multi_insert.cc b/libstdc++-v3/testsuite/23_containers/inplace_vector/modifiers/multi_insert.cc
> index 454163892ad..e5a482cdc65 100644
> --- a/libstdc++-v3/testsuite/23_containers/inplace_vector/modifiers/multi_insert.cc
> +++ b/libstdc++-v3/testsuite/23_containers/inplace_vector/modifiers/multi_insert.cc
> @@ -54,16 +54,6 @@ test_add_to_full_it()
>   
>     std::inplace_vector<T, N> v(std::from_range, std::span(a, a+N));
>   
> -  Range r1(a, a);
> -  auto rit1 = v.try_append_range(r1);
> -  VERIFY( eq<T>(v, {a, N}) );
> -  VERIFY( rit1.base() == a );
> -
> -  SizedRange r2(a, a);
> -  auto rit2 = v.try_append_range(r2);
> -  VERIFY( eq<T>(v, {a, N}) );
> -  VERIFY( rit2.base() == a );
> -
>     v.append_range(Range(a, a));
>     VERIFY( eq<T>(v, {a, N}) );
>     v.append_range(SizedRange(a, a));
> @@ -93,17 +83,6 @@ test_add_to_full_it()
>     VERIFY( eq<T>(v, {a, N}) );
>     VERIFY( it == v.begin() );
>   
> -  // Inserting non-empty range
> -  Range r3(a+3, a+5);
> -  auto rit3 = v.try_append_range(r3);
> -  VERIFY( eq<T>(v, {a, N}) );
> -  VERIFY( rit3.base() == a+3 );
> -
> -  SizedRange r4(a+2, a+5);
> -  auto rit4 = v.try_append_range(r4);
> -  VERIFY( eq<T>(v, {a, N}) );
> -  VERIFY( rit4.base() == a+2 );
> -
>   #ifdef __cpp_exceptions
>   #ifndef __cpp_lib_constexpr_exceptions
>     if consteval {
> @@ -265,30 +244,6 @@ test_append_range()
>   #endif
>   }
>   
> -template<typename Range>
> -constexpr void
> -test_try_append_range()
> -{
> -  using T = std::ranges::range_value_t<Range>;
> -  T a[]{1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25};
> -
> -  std::inplace_vector<T, 20> v;
> -  Range r1 = Range(a, a+10);
> -  auto it1 = v.try_append_range(r1);
> -  VERIFY( eq<T>(v, {a, 10}) );
> -  VERIFY( it1.base() == a+10 );
> -
> -  Range r2 = Range(a+10, a+15);
> -  auto it2 = v.try_append_range(r2);
> -  VERIFY( eq<T>(v, {a, 15}) );
> -  VERIFY( it2.base() == a+15 );
> -
> -  Range r3 = Range(a+15, a+25);
> -  auto it3 = v.try_append_range(r3);
> -  VERIFY( eq<T>(v, {a, 20}) );
> -  VERIFY( it3.base() == a+20 );
> -}
> -
>   template<typename Range>
>   constexpr void
>   test_insert_range()
> @@ -357,7 +312,6 @@ constexpr void
>   do_test_ranges()
>   {
>     test_append_range<Range>();
> -  test_try_append_range<Range>();
>     test_insert_range<Range>();
>   }
>   
> diff --git a/libstdc++-v3/testsuite/23_containers/inplace_vector/modifiers/single_insert.cc b/libstdc++-v3/testsuite/23_containers/inplace_vector/modifiers/single_insert.cc
> index 92bd765982e..245af928800 100644
> --- a/libstdc++-v3/testsuite/23_containers/inplace_vector/modifiers/single_insert.cc
> +++ b/libstdc++-v3/testsuite/23_containers/inplace_vector/modifiers/single_insert.cc
> @@ -3,6 +3,7 @@
>   #include <inplace_vector>
>   
>   #include <span>
> +#include <optional>
>   #include <testsuite_hooks.h>
>   
>   struct X
> @@ -18,6 +19,20 @@ struct X
>     friend auto operator<=>(const X&, const X&) = default;
>   };
>   
> +// Type that is convertible to optional<Y&>
> +struct Y
> +{
> +  Y() = default;
> +  constexpr Y(int p) : v(p) {}
> +
> +  constexpr operator std::optional<Y&>()
> +  { return std::nullopt; }
> +
> +  int v;
> +
> +  friend auto operator<=>(const Y&, const Y&) = default;
> +};
> +
>   template<typename T, typename V, size_t N>
>   constexpr bool
>   eq(const std::inplace_vector<V, N>& l, std::span<const T> r) {
> @@ -40,11 +55,11 @@ test_add_to_full()
>   
>     std::inplace_vector<T, N> v(std::from_range, std::span(a, a+N));
>   
> -  VERIFY( v.try_emplace_back(1) == nullptr );
> +  VERIFY( !v.try_emplace_back(1).has_value() );
>     VERIFY( eq<T>(v, {a, N}) );
> -  VERIFY( v.try_push_back(T(1)) == nullptr );
> +  VERIFY( !v.try_push_back(T(1)).has_value() );
>     VERIFY( eq<T>(v, {a, N}) );
> -  VERIFY( v.try_push_back(c) == nullptr );
> +  VERIFY( !v.try_push_back(c).has_value() );
>     VERIFY( eq<T>(v, {a, N}) );
>   
>   #ifdef __cpp_exceptions
> @@ -149,15 +164,18 @@ test_inserts()
>     v.unchecked_push_back(c);
>     VERIFY( eq<T>(v, {a+3, 6}) );
>   
> -  T* ptr = v.try_emplace_back(7);
> +  std::optional<T&> opt = v.try_emplace_back(7);
>     VERIFY( eq<T>(v, {a+3, 7}) );
> -  VERIFY( ptr = &v.back() );
> -  ptr = v.try_push_back(T(8));
> +  VERIFY( opt.has_value() );
> +  VERIFY( &*opt == &v.back() );
> +  opt = v.try_push_back(T(8));
>     VERIFY( eq<T>(v, {a+3, 8}) );
> -  VERIFY( ptr = &v.back() );
> -  ptr = v.try_push_back(c);
> +  VERIFY( opt.has_value() );
> +  VERIFY( &*opt == &v.back() );
> +  opt = v.try_push_back(c);
>     VERIFY( eq<T>(v, {a+3, 9}) );
> -  VERIFY( ptr = &v.back() );
> +  VERIFY( opt.has_value() );
> +  VERIFY( &*opt == &v.back() );
>   
>     auto it = v.emplace(v.end(), 10);
>     VERIFY( eq<T>(v, {a+3, 10}) );
> @@ -195,12 +213,15 @@ int main()
>     auto test_all = [] {
>       test_add_to_full<0, int>();
>       test_add_to_full<0, X>();
> +    test_add_to_full<0, Y>();
>   
>       test_add_to_full<4, int>();
> +    test_add_to_full<4, Y>();
>   
>       test_inserts<int>();
> +    test_inserts<Y>();
>   #ifdef __cpp_lib_constexpr_inplace_vector
> -#error uncomemnt test_inserts<X>()
> +#error enable tests bellow
>   #endif
>       if ! consteval {
>         test_add_to_full<4, X>();
> diff --git a/libstdc++-v3/testsuite/23_containers/inplace_vector/version.cc b/libstdc++-v3/testsuite/23_containers/inplace_vector/version.cc
> index a5bbdb8464b..493e86dc6dd 100644
> --- a/libstdc++-v3/testsuite/23_containers/inplace_vector/version.cc
> +++ b/libstdc++-v3/testsuite/23_containers/inplace_vector/version.cc
> @@ -5,7 +5,7 @@
>   
>   #ifndef __cpp_lib_inplace_vector
>   # error "Feature-test macro for inplace_vector missing in <inplace_vector>"
> -#elif __cpp_lib_inplace_vector != 202406L
> +#elif __cpp_lib_inplace_vector != 202603L
>   # error "Feature-test macro for inplace_vector has wrong value in <inplace_vector>"
>   #endif
>   
> @@ -15,6 +15,6 @@
>   
>   #ifndef __cpp_lib_inplace_vector
>   # error "Feature-test macro for inplace_vector missing in <version>"
> -#elif __cpp_lib_inplace_vector != 202406L
> +#elif __cpp_lib_inplace_vector != 202603L
>   # error "Feature-test macro for inplace_vector has wrong value in <version>"
>   #endif



More information about the Libstdc++ mailing list