[PATCH] libstdc++: Expand constexpr support for inplace_vector per P3726R2 [PR125845, PR124121].
Jonathan Wakely
jwakely@redhat.com
Fri Sep 11 12:15:11 GMT 2026
On Fri, 11 Sept 2026 at 13:01, Tomasz Kamiński <tkaminsk@redhat.com> wrote:
>
> This implements remaining part of the P3726R2, "Adjustments to Union
> Lifetime Rules", by using std::start_lifetime in inplace_vector::_M_init.
>
> The alternative branch no longer uses std::start_lifetime_as, that was
> preventing optimizations (see PR124121), it is not required as GCC treats
> any write to union as potentially changing active member Further when
> available __builtin_constexpr_diag is used to emit better error message.
> TODO comment is also removed, as suggested new call is not supported until
> clang 23.
>
> libstdc++-v3/ChangeLog:
>
> PR libstdc++/125845
> PR libstdc++/124121
> * include/bits/version.def (start_lifetime): Move before
> inplace_vector.
> (constexpr_inplace_vector): Define.
> * include/bits/version.h: Regenerate.
> * include/std/inplace_vector (__cpp_lib_constexpr_inplace_vector):
> Define.
> (inplace_vector::_M_init): Use std::start_lifetime instead of
> std::start_lifetime_as, when available. Emit error using
> __builtin_constexpr_diag.
> * testsuite/23_containers/inplace_vector/cons/1.cc: Enable and
> andd compile time tests for non-trivial types.
> * testsuite/23_containers/inplace_vector/copy.cc: Likewise.
> * testsuite/23_containers/inplace_vector/modifiers/assign.cc:
> Likewise.
> * testsuite/23_containers/inplace_vector/modifiers/erase.cc:
> Likewise.
> * testsuite/23_containers/inplace_vector/modifiers/multi_insert.cc:
> Likewise.
> * testsuite/23_containers/inplace_vector/modifiers/single_insert.cc:
> Likewise.
> * testsuite/23_containers/inplace_vector/move.cc: Likewise.
> * testsuite/23_containers/inplace_vector/version.cc: Test value of
> __cpp_lib_constexpr_inplace_vector.
> ---
> Tested on x86_64-linux. All *inplace_vector* test also passed in
> all standard modes. OK for trunk?
OK for trunk.
>
> Should we backport the changes to alternative branch (removing
> start_lifetime_as) to GCC-16?
Yes, I think the builtin_constexpr_diag failure would be a nice
improvement on the branch.
>
> libstdc++-v3/include/bits/version.def | 27 ++++--
> libstdc++-v3/include/bits/version.h | 30 ++++---
> libstdc++-v3/include/std/inplace_vector | 22 +++--
> .../23_containers/inplace_vector/cons/1.cc | 90 ++++++++-----------
> .../23_containers/inplace_vector/copy.cc | 18 +---
> .../inplace_vector/modifiers/assign.cc | 9 +-
> .../inplace_vector/modifiers/erase.cc | 7 +-
> .../inplace_vector/modifiers/multi_insert.cc | 14 +--
> .../inplace_vector/modifiers/single_insert.cc | 9 +-
> .../23_containers/inplace_vector/move.cc | 33 ++-----
> .../23_containers/inplace_vector/version.cc | 12 +++
> 11 files changed, 120 insertions(+), 151 deletions(-)
>
> diff --git a/libstdc++-v3/include/bits/version.def b/libstdc++-v3/include/bits/version.def
> index 3f314ffe1ee..36f8c9c31cf 100644
> --- a/libstdc++-v3/include/bits/version.def
> +++ b/libstdc++-v3/include/bits/version.def
> @@ -2315,6 +2315,15 @@ ftms = {
> };
> };
>
> +ftms = {
> + name = start_lifetime;
> + values = {
> + v = 202603;
> + cxxmin = 26;
> + extra_cond = "__has_builtin(__builtin_start_lifetime)";
> + };
> +};
> +
> ftms = {
> // 202406 P0843R14 inplace_vector
> // 202603 P3981R2 Better return types in std::inplace_vector and std::exception_ptr_cast
> @@ -2326,6 +2335,15 @@ ftms = {
> };
> };
>
> +ftms = {
> + name = constexpr_inplace_vector;
> + values = {
> + v = 202502;
> + cxxmin = 26;
> + extra_cond = "__glibcxx_start_lifetime";
> + };
> +};
> +
> ftms = {
> name = indirect;
> values = {
> @@ -2665,15 +2683,6 @@ ftms = {
> };
> };
>
> -ftms = {
> - name = start_lifetime;
> - values = {
> - v = 202603;
> - cxxmin = 26;
> - extra_cond = "__has_builtin(__builtin_start_lifetime)";
> - };
> -};
> -
> // Standard test specifications.
> stds[97] = ">= 199711L";
> stds[03] = ">= 199711L";
> diff --git a/libstdc++-v3/include/bits/version.h b/libstdc++-v3/include/bits/version.h
> index 16b7425269a..e79ea5043d7 100644
> --- a/libstdc++-v3/include/bits/version.h
> +++ b/libstdc++-v3/include/bits/version.h
> @@ -2561,6 +2561,16 @@
> #endif /* !defined(__cpp_lib_modules) */
> #undef __glibcxx_want_modules
>
> +#if !defined(__cpp_lib_start_lifetime)
> +# if (__cplusplus > 202302L) && (__has_builtin(__builtin_start_lifetime))
> +# define __glibcxx_start_lifetime 202603L
> +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_start_lifetime)
> +# define __cpp_lib_start_lifetime 202603L
> +# endif
> +# endif
> +#endif /* !defined(__cpp_lib_start_lifetime) */
> +#undef __glibcxx_want_start_lifetime
> +
> #if !defined(__cpp_lib_inplace_vector)
> # if (__cplusplus > 202302L)
> # define __glibcxx_inplace_vector 202603L
> @@ -2571,6 +2581,16 @@
> #endif /* !defined(__cpp_lib_inplace_vector) */
> #undef __glibcxx_want_inplace_vector
>
> +#if !defined(__cpp_lib_constexpr_inplace_vector)
> +# if (__cplusplus > 202302L) && (__glibcxx_start_lifetime)
> +# define __glibcxx_constexpr_inplace_vector 202502L
> +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_constexpr_inplace_vector)
> +# define __cpp_lib_constexpr_inplace_vector 202502L
> +# endif
> +# endif
> +#endif /* !defined(__cpp_lib_constexpr_inplace_vector) */
> +#undef __glibcxx_want_constexpr_inplace_vector
> +
> #if !defined(__cpp_lib_indirect)
> # if (__cplusplus > 202302L) && _GLIBCXX_HOSTED
> # define __glibcxx_indirect 202502L
> @@ -2954,14 +2974,4 @@
> #endif /* !defined(__cpp_lib_hardened_view_interface) */
> #undef __glibcxx_want_hardened_view_interface
>
> -#if !defined(__cpp_lib_start_lifetime)
> -# if (__cplusplus > 202302L) && (__has_builtin(__builtin_start_lifetime))
> -# define __glibcxx_start_lifetime 202603L
> -# if defined(__glibcxx_want_all) || defined(__glibcxx_want_start_lifetime)
> -# define __cpp_lib_start_lifetime 202603L
> -# endif
> -# endif
> -#endif /* !defined(__cpp_lib_start_lifetime) */
> -#undef __glibcxx_want_start_lifetime
> -
> #undef __glibcxx_want_all
> diff --git a/libstdc++-v3/include/std/inplace_vector b/libstdc++-v3/include/std/inplace_vector
> index a2b5f31be92..b16edcb98d9 100644
> --- a/libstdc++-v3/include/std/inplace_vector
> +++ b/libstdc++-v3/include/std/inplace_vector
> @@ -32,6 +32,7 @@
>
> #pragma GCC system_header
>
> +#define __glibcxx_want_constexpr_inplace_vector
> #define __glibcxx_want_hardened_inplace_vector
> #define __glibcxx_want_inplace_vector
> #include <bits/version.h>
> @@ -853,22 +854,25 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
> constexpr void
> _M_init()
> {
> - if !consteval
> +#if __glibcxx_start_lifetime
> + std::start_lifetime(_M_elems);
> +#else
> + if consteval
> {
> -#if __glibcxx_start_lifetime_as
> - std::start_lifetime_as_array<_Tp>(data(), _Nm);
> -#endif
> - }
> - else
> - {
> - // TODO: use new(_M_elems) _Tp[_Nm]() once PR121068 is fixed
> if constexpr (is_trivially_default_constructible_v<_Tp>
> && is_trivially_copyable_v<_Tp>)
> for (size_t __i = 0; __i < _Nm; ++__i)
> _M_elems[__i] = _Tp();
> else
> - __builtin_unreachable(); // only trivial types are supported at compile time
> +# if __has_builtin(__builtin_constexpr_diag)
> + __builtin_constexpr_diag(2, "",
> + "std::inplace_vector supports only trivally copyable and "
> + "trivially default constructible types at compile time");
> +# else
> + __builtin_unreachable();
> +# endif
> }
> +#endif
> }
>
> static constexpr void
> diff --git a/libstdc++-v3/testsuite/23_containers/inplace_vector/cons/1.cc b/libstdc++-v3/testsuite/23_containers/inplace_vector/cons/1.cc
> index 2982af27785..264fba572ca 100644
> --- a/libstdc++-v3/testsuite/23_containers/inplace_vector/cons/1.cc
> +++ b/libstdc++-v3/testsuite/23_containers/inplace_vector/cons/1.cc
> @@ -108,13 +108,6 @@ test_default()
> VERIFY( z0.empty() );
> VERIFY( z0.begin() == z0.end() );
>
> -#ifdef __cpp_lib_constexpr_inplace_vector
> -#error remove the consteval check
> -#endif
> - if consteval {
> - return;
> - }
> -
> std::inplace_vector<X, 5> cx;
> VERIFY( cx.size() == 0 );
> VERIFY( cx.capacity() == 5 );
> @@ -192,13 +185,6 @@ test_n()
> #endif
> #endif
>
> -#ifdef __cpp_lib_constexpr_inplace_vector
> -#error remove the consteval check
> -#endif
> - if consteval {
> - return;
> - }
> -
> std::inplace_vector<X, 5> cx(3);
> VERIFY( cx.size() == 3 );
> VERIFY( cx.capacity() == 5 );
> @@ -269,13 +255,6 @@ test_n_val()
> #endif
> #endif
>
> -#ifdef __cpp_lib_constexpr_inplace_vector
> -#error remove the consteval check
> -#endif
> - if consteval {
> - return;
> - }
> -
> std::inplace_vector<X, 5> cx(4);
> VERIFY( cx.size() == 4 );
> VERIFY( cx.capacity() == 5 );
> @@ -320,45 +299,38 @@ test_initializer_list()
> VERIFY( z0.empty() );
> VERIFY( z0.begin() == z0.end() );
>
> -#ifdef __cpp_exceptions
> -#ifndef __cpp_lib_constexpr_exceptions
> - if not consteval {
> -#endif
> - try
> - {
> - std::inplace_vector<int, 2> ct{11, 22, 33};
> - VERIFY(false);
> - }
> - catch (std::bad_alloc const&)
> - {
> - }
> -
> - try
> - {
> - std::inplace_vector<int, 0> ct{11, 22};
> - VERIFY(false);
> - }
> - catch (std::bad_alloc const&)
> - {
> - }
> -#ifndef __cpp_lib_constexpr_exceptions
> - }
> -#endif
> -#endif
> -
> -#ifdef __cpp_lib_constexpr_inplace_vector
> -#error remove the consteval check
> -#endif
> - if consteval {
> - return;
> - }
> -
> std::inplace_vector<X, 5> cx{X(), X(), X(), X()};
> VERIFY( cx.size() == 4 );
> VERIFY( cx.capacity() == 5 );
> VERIFY( not cx.empty() );
> VERIFY( cx.begin() + 4 == cx.end() );
> (void) cx[3];
> +
> +#ifdef __cpp_exceptions
> +# ifndef __cpp_lib_constexpr_exceptions
> + if consteval {
> + return;
> + }
> +# endif
> +
> + try
> + {
> + std::inplace_vector<int, 2> ct{11, 22, 33};
> + VERIFY(false);
> + }
> + catch (std::bad_alloc const&)
> + {
> + }
> +
> + try
> + {
> + std::inplace_vector<int, 0> ct{11, 22};
> + VERIFY(false);
> + }
> + catch (std::bad_alloc const&)
> + {
> + }
> +#endif
> }
>
> constexpr std::inplace_vector<int, 0> e0;
> @@ -375,6 +347,16 @@ constexpr std::inplace_vector<int, 5> g5 = [] {
> return res;
> }();
>
> +constexpr std::inplace_vector<X, 5> h1;
> +constexpr std::inplace_vector<X, 5> h2(2, X());
> +constexpr std::inplace_vector<X, 5> h3 = h2;
> +constexpr std::inplace_vector<X, 5> h4{X(), X(), X()};
> +constexpr std::inplace_vector<X, 5> h5 = [] {
> + std::inplace_vector<X, 5> res;
> + res = h3;
> + return res;
> +}();
> +
> int main()
> {
> auto tests = [] {
> diff --git a/libstdc++-v3/testsuite/23_containers/inplace_vector/copy.cc b/libstdc++-v3/testsuite/23_containers/inplace_vector/copy.cc
> index 11260c63313..a2f5e7d3486 100644
> --- a/libstdc++-v3/testsuite/23_containers/inplace_vector/copy.cc
> +++ b/libstdc++-v3/testsuite/23_containers/inplace_vector/copy.cc
> @@ -160,13 +160,6 @@ test_ctor()
> auto c5 = materialize<5, int>({1, 2, 3, 4, 5});
> VERIFY( eq(c5, {1, 2, 3, 4, 5}) );
>
> -#ifdef __cpp_lib_constexpr_inplace_vector
> -#error remove the consteval check
> -#endif
> - if consteval {
> - return;
> - }
> -
> auto x0 = materialize<3, X>({});
> VERIFY( x0.empty() );
>
> @@ -206,13 +199,6 @@ test_assign()
> c = materialize<5, int>({});
> VERIFY( c.empty() );
>
> -#ifdef __cpp_lib_constexpr_inplace_vector
> -#error remove the consteval check
> -#endif
> - if consteval {
> - return;
> - }
> -
> std::inplace_vector<X, 5> x;
> x = materialize<5, X>({});
> VERIFY( x.empty() );
> @@ -238,6 +224,10 @@ constexpr auto t1 = materialize<3, int>({});
> constexpr auto t2 = materialize<3, int>({1, 2});
> constexpr auto t3 = materialize<3, int>({11, 22, 33});
>
> +constexpr auto u1 = materialize<3, X>({});
> +constexpr auto u2 = materialize<3, X>({1, 2});
> +constexpr auto u3 = materialize<3, X>({11, 22, 33});
> +
> int main()
> {
> auto tests = [] {
> diff --git a/libstdc++-v3/testsuite/23_containers/inplace_vector/modifiers/assign.cc b/libstdc++-v3/testsuite/23_containers/inplace_vector/modifiers/assign.cc
> index 577c1047708..27c2f09db84 100644
> --- a/libstdc++-v3/testsuite/23_containers/inplace_vector/modifiers/assign.cc
> +++ b/libstdc++-v3/testsuite/23_containers/inplace_vector/modifiers/assign.cc
> @@ -407,15 +407,10 @@ int main()
> test_assign_empty<0, int>();
> test_assign_empty<0, X>();
> test_assign_empty<2, int>();
> + test_assign_empty<2, X>();
>
> test_assigns<int>();
> -#ifdef __cpp_lib_constexpr_inplace_vector
> -#error uncomemnt test_inserts<X>()
> -#endif
> - if !consteval {
> - test_assign_empty<2, X>();
> - test_assigns<X>();
> - }
> + test_assigns<X>();
>
> test_iota<long long>();
> #ifdef __SIZEOF_INT128__
> diff --git a/libstdc++-v3/testsuite/23_containers/inplace_vector/modifiers/erase.cc b/libstdc++-v3/testsuite/23_containers/inplace_vector/modifiers/erase.cc
> index 8b82ab4189c..36096da4feb 100644
> --- a/libstdc++-v3/testsuite/23_containers/inplace_vector/modifiers/erase.cc
> +++ b/libstdc++-v3/testsuite/23_containers/inplace_vector/modifiers/erase.cc
> @@ -101,14 +101,9 @@ int main()
> test_erase_all_or_none<0, X>();
>
> test_erase_all_or_none<4, int>();
> + test_erase_all_or_none<4, X>();
>
> test_erase<int>();
> -#ifdef __cpp_lib_constexpr_inplace_vector
> -#error uncomemnt test_inserts<X>()
> -#endif
> - if ! consteval {
> - test_erase_all_or_none<4, X>();
> - }
> return true;
> };
>
> 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 bde66847a34..4b36b5151ed 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
> @@ -562,11 +562,11 @@ test_iota()
> VERIFY( eq<T>(v, {a, 15}) );
>
> #ifdef __cpp_exceptions
> -#ifndef __cpp_lib_constexpr_exceptions
> +# ifndef __cpp_lib_constexpr_exceptions
> if consteval {
> return;
> }
> -#endif
> +# endif
> constexpr T max = std::numeric_limits<T>::max();
> try
> {
> @@ -615,7 +615,6 @@ test_iota()
> {
> }
> VERIFY( prefix<T>(vc, {a, 15}) );
> -
> #endif
> }
>
> @@ -625,15 +624,10 @@ int main()
> test_add_to_full<0, int>();
> test_add_to_full<0, X>();
> test_add_to_full<4, int>();
> + test_add_to_full<4, X>();
>
> test_inserts<int>();
> -#ifdef __cpp_lib_constexpr_inplace_vector
> -#error uncomemnt test_inserts<X>()
> -#endif
> - if !consteval {
> - test_add_to_full<4, X>();
> - test_inserts<X>();
> - }
> + test_inserts<X>();
>
> test_iota<long long>();
> #ifdef __SIZEOF_INT128__
> 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 2b5e76a6f63..ffe5ed3374d 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
> @@ -216,17 +216,12 @@ int main()
> test_add_to_full<0, Y>();
>
> test_add_to_full<4, int>();
> + test_add_to_full<4, X>();
> test_add_to_full<4, Y>();
>
> test_inserts<int>();
> test_inserts<Y>();
> -#ifdef __cpp_lib_constexpr_inplace_vector
> -#error enable tests bellow
> -#endif
> - if ! consteval {
> - test_add_to_full<4, X>();
> - test_inserts<X>();
> - }
> + test_inserts<X>();
> return true;
> };
>
> diff --git a/libstdc++-v3/testsuite/23_containers/inplace_vector/move.cc b/libstdc++-v3/testsuite/23_containers/inplace_vector/move.cc
> index 8b5c3e9f247..5419dc0edb6 100644
> --- a/libstdc++-v3/testsuite/23_containers/inplace_vector/move.cc
> +++ b/libstdc++-v3/testsuite/23_containers/inplace_vector/move.cc
> @@ -67,7 +67,7 @@ struct Z
> template<size_t N, typename T>
> constexpr std::inplace_vector<T, N>
> materialize(std::initializer_list<int> il)
> - {
> + {
> std::inplace_vector<T, N> res;
> for (int x : il)
> res.emplace_back(x);
> @@ -199,13 +199,6 @@ test_ctor()
> auto c5 = materialize<5, int>({1, 2, 3, 4, 5});
> VERIFY( eq(c5, {1, 2, 3, 4, 5}) );
>
> -#ifdef __cpp_lib_constexpr_inplace_vector
> -#error remove the consteval check
> -#endif
> - if consteval {
> - return;
> - }
> -
> auto x0 = materialize<3, X>({});
> VERIFY( x0.empty() );
>
> @@ -235,7 +228,7 @@ test_assign()
>
> c = materialize<5, int>({1, 2, 3});
> VERIFY( eq(c, {1, 2, 3}) );
> -
> +
> c = materialize<5, int>({1, 2, 3, 4, 5});
> VERIFY( eq(c, {1, 2, 3, 4, 5}) );
>
> @@ -245,20 +238,13 @@ test_assign()
> c = materialize<5, int>({});
> VERIFY( c.empty() );
>
> -#ifdef __cpp_lib_constexpr_inplace_vector
> -#error remove the consteval check
> -#endif
> - if consteval {
> - return;
> - }
> -
> std::inplace_vector<X, 5> x;
> x = materialize<5, X>({});
> VERIFY( x.empty() );
>
> x = materialize<5, X>({1, 2, 3});
> VERIFY( eq(x, {1, 2, 3}) );
> -
> +
> x = materialize<5, X>({1, 2, 3, 4, 5});
> VERIFY( eq(x, {1, 2, 3, 4, 5}) );
>
> @@ -279,7 +265,7 @@ test_swap()
> e0a.swap(e0b);
> VERIFY( e0a.empty() );
> VERIFY( e0b.empty() );
> -
> +
> std::inplace_vector<X, 0> e1a, e1b;
> swap(e1a, e1b);
> VERIFY( e1a.empty() );
> @@ -314,13 +300,6 @@ test_swap()
> VERIFY( eq(c3, {1, 2, 3}) );
> VERIFY( eq(c5, {1, 2, 3, 4, 5}) );
>
> -#ifdef __cpp_lib_constexpr_inplace_vector
> -#error remove the consteval check
> -#endif
> - if consteval {
> - return;
> - }
> -
> std::inplace_vector<X, 5> x0;
> std::inplace_vector<X, 5> x3 = {1, 2, 3};
> std::inplace_vector<X, 5> x5 = {1, 2, 3, 4, 5};
> @@ -348,6 +327,10 @@ constexpr auto t1 = materialize<3, int>({});
> constexpr auto t2 = materialize<3, int>({1, 2});
> constexpr auto t3 = materialize<3, int>({11, 22, 33});
>
> +constexpr auto u1 = materialize<3, X>({});
> +constexpr auto u2 = materialize<3, X>({1, 2});
> +constexpr auto u3 = materialize<3, X>({11, 22, 33});
> +
> int main()
> {
> auto tests = [] {
> diff --git a/libstdc++-v3/testsuite/23_containers/inplace_vector/version.cc b/libstdc++-v3/testsuite/23_containers/inplace_vector/version.cc
> index 493e86dc6dd..73be2eeff4f 100644
> --- a/libstdc++-v3/testsuite/23_containers/inplace_vector/version.cc
> +++ b/libstdc++-v3/testsuite/23_containers/inplace_vector/version.cc
> @@ -9,6 +9,12 @@
> # error "Feature-test macro for inplace_vector has wrong value in <inplace_vector>"
> #endif
>
> +#ifndef __cpp_lib_constexpr_inplace_vector
> +# error "Feature-test macro for constexpr_inplace_vector missing in <constexpr_inplace_vector>"
> +#elif __cpp_lib_constexpr_inplace_vector != 202502LL
> +# error "Feature-test macro for constexpr_inplace_vector has wrong value in <constexpr_inplace_vector>"
> +#endif
> +
> #undef __cpp_lib_inplace_vector
>
> #include <version>
> @@ -18,3 +24,9 @@
> #elif __cpp_lib_inplace_vector != 202603L
> # error "Feature-test macro for inplace_vector has wrong value in <version>"
> #endif
> +
> +#ifndef __cpp_lib_constexpr_inplace_vector
> +# error "Feature-test macro for constexpr_inplace_vector missing in <constexpr_inplace_vector>"
> +#elif __cpp_lib_constexpr_inplace_vector != 202502LL
> +# error "Feature-test macro for constexpr_inplace_vector has wrong value in <constexpr_inplace_vector>"
> +#endif
> --
> 2.55.0
>
More information about the Libstdc++
mailing list