https://gcc.gnu.org/g:a6cb4f459e781eb066290f3bbcd0569901e372b1
commit r17-4164-ga6cb4f459e781eb066290f3bbcd0569901e372b1 Author: Tomasz KamiĆski <[email protected]> Date: Fri Sep 11 10:23:33 2026 +0200 libstdc++: Expand constexpr support for inplace_vector per P3726R2 [PR125845, PR124121]. 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. Furthermore 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. Diff: --- 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 +++++++++------------- .../testsuite/23_containers/inplace_vector/copy.cc | 18 +---- .../inplace_vector/modifiers/assign.cc | 9 +-- .../inplace_vector/modifiers/erase.cc | 8 +- .../inplace_vector/modifiers/multi_insert.cc | 14 +--- .../inplace_vector/modifiers/single_insert.cc | 9 +-- .../testsuite/23_containers/inplace_vector/move.cc | 33 ++------ .../23_containers/inplace_vector/version.cc | 12 +++ 11 files changed, 121 insertions(+), 151 deletions(-) diff --git a/libstdc++-v3/include/bits/version.def b/libstdc++-v3/include/bits/version.def index 3f314ffe1ee0..36f8c9c31cf4 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 16b7425269a3..e79ea5043d74 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 a2b5f31be923..b16edcb98d9a 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 2982af277858..264fba572ca0 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 11260c63313c..a2f5e7d3486b 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 577c10477086..27c2f09db844 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 8b82ab4189cd..98818d60750b 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,10 @@ 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>(); - } + test_erase<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 bde66847a34c..4b36b5151ed2 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 2b5e76a6f63f..ffe5ed3374df 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 8b5c3e9f247f..5419dc0edb67 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 493e86dc6dd2..73be2eeff4f3 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
