[PATCH] libstdc++, v2: library side of C++26 P2786R13 - Trivial Relocatability [PR119064]
Tomasz Kaminski
tkaminsk@redhat.com
Tue Aug 26 13:28:43 GMT 2025
On Tue, Aug 26, 2025 at 3:23 PM Jakub Jelinek <jakub@redhat.com> wrote:
> On Mon, Jul 14, 2025 at 12:11:18PM +0200, Tomasz Kaminski wrote:
> > We have a preference to use [[likely]] attribute when possible.
>
> Done.
>
> > > + for (; __first != __last; ++__first, ++__result)
> > > + {
> > > + if constexpr (is_array_v<_Tp>)
> > > + std::relocate(std::begin(*__first), std::end(*__first),
> > > + &(*__result)[0]);
> > >
> > We should use std::addressof or __builtin_addressof here to avoid using
> > operator& found by ADL. The standard uses start_lifetime_as here (
> > https://eel.is/c++draft/memory#obj.lifetime-18.3.1),
> > with the intent of constructing array and making pointer arithmetic on
> > __res well-formed.
>
> Used std::addressof for now (until start_lifetime_as is added).
>
> > I was expecting this to be ill-formed at compile time, as we never
> > start the lifetime of array S[6] inside the a, so I believed things like
> > pointer
> > arithmetic on sf would be ill-formed. In other words I believe that this
> > test
> > would require invoking start_lifetime_as.
> >
> > But continuing on that, is there any reason to use unsigned char array
> > for this test, instead of having arrays instead of unamed union as source
> > and destination:
> > union { S a[6]; };
> > union { S b[6]; };
> > This will still allow manual memory management, but will make code more
> > readable, at least for me.
> >
> > Jonathan, do you have preference here?
>
> Here is an updated patch, which has 2 functions, test_relocate
> is as before but without constexpr and
> - tr = ::new(&a[1]) T(42);
> + tr = ::new(&b[1]) T(42);
> fix and then test_relocate_constexpr which uses array of S and
> just destructs all members of the array before doing placement new
> again into it, std::relocate etc. And finally at the end of function
> it constructs there S objects in all elements again.
>
> I have no idea how to test the array cases at constant evaluation
> time, placement new doesn't return pointer to array and I get
> complains about reinterpret_cast not being valid during constant evaluation
> time.
>
I have posted a working example in another thread. Note, that relocating
arrays
is not supported at compile time, as specified by standard.
>
> So, this patch just tests non-array std::relocate at both runtime and
> constexpr time, everything else at runtime only.
>
> 2025-07-16 Jakub Jelinek <jakub@redhat.com>
>
> PR c++/119064
> * include/bits/version.def (trivially_relocatable): New.
> * include/bits/version.h: Regenerate.
> * include/std/type_traits (std::is_trivially_relocatable,
> std::is_nothrow_relocatable, std::is_replaceable): New traits.
> std::is_trivially_relocatable_v, std::is_nothrow_relocatable_v,
> std::is_replaceable_v): New trait variable templates.
> * include/std/memory (__glibcxx_want_trivially_relocatable): Define
> before including bits/version.h.
> (std::trivially_relocate): New template function.
> (std::relocate): Likewise.
> * testsuite/std/memory/relocate/relocate.cc: New test.
>
> --- libstdc++-v3/include/bits/version.def.jj 2025-07-16
> 07:06:05.645224306 +0200
> +++ libstdc++-v3/include/bits/version.def 2025-07-16
> 11:51:19.121688727 +0200
> @@ -2059,6 +2059,15 @@ ftms = {
> };
> };
>
> +ftms = {
> + name = trivially_relocatable;
> + values = {
> + v = 202502;
> + cxxmin = 26;
> + extra_cond = "__cpp_trivial_relocatability >= 202502L";
> + };
> +};
> +
> // Standard test specifications.
> stds[97] = ">= 199711L";
> stds[03] = ">= 199711L";
> --- libstdc++-v3/include/bits/version.h.jj 2025-07-16
> 07:06:14.934235823 +0200
> +++ libstdc++-v3/include/bits/version.h 2025-07-16 11:51:19.122688713 +0200
> @@ -2309,4 +2309,14 @@
> #endif /* !defined(__cpp_lib_constexpr_exceptions) &&
> defined(__glibcxx_want_constexpr_exceptions) */
> #undef __glibcxx_want_constexpr_exceptions
>
> +#if !defined(__cpp_lib_trivially_relocatable)
> +# if (__cplusplus > 202302L) && (__cpp_trivial_relocatability >= 202502L)
> +# define __glibcxx_trivially_relocatable 202502L
> +# if defined(__glibcxx_want_all) ||
> defined(__glibcxx_want_trivially_relocatable)
> +# define __cpp_lib_trivially_relocatable 202502L
> +# endif
> +# endif
> +#endif /* !defined(__cpp_lib_trivially_relocatable) &&
> defined(__glibcxx_want_trivially_relocatable) */
> +#undef __glibcxx_want_trivially_relocatable
> +
> #undef __glibcxx_want_all
> --- libstdc++-v3/include/std/type_traits.jj 2025-07-15
> 14:49:29.976515413 +0200
> +++ libstdc++-v3/include/std/type_traits 2025-07-16
> 11:51:19.122688713 +0200
> @@ -4280,6 +4280,60 @@ template<typename _Ret, typename _Fn, ty
>
> #endif // C++2a
>
> +#if __glibcxx_trivially_relocatable >= 202502L // C++ >= 26 &&
> __cpp_trivial_relocatability >= 202502
> + /// True if the type is a trivially relocatable type.
> + /// @since C++26
> +
> + template<typename _Tp>
> + struct is_trivially_relocatable
> +# if __has_builtin(__builtin_is_trivially_relocatable)
> + : bool_constant<__builtin_is_trivially_relocatable(_Tp)>
> +# else
> + : bool_constant<__builtin_is_cpp_trivially_relocatable(_Tp)>
> +# endif
> + { };
> +
> + template<typename _Tp>
> + struct is_nothrow_relocatable
> +# if _GLIBCXX_USE_BUILTIN_TRAIT(__builtin_is_nothrow_relocatable)
> + : bool_constant<__builtin_is_nothrow_relocatable(_Tp)>
> +# else
> + : public __or_<is_trivially_relocatable<_Tp>,
> +
> __and_<is_nothrow_move_constructible<remove_all_extents<_Tp>>,
> +
> is_nothrow_destructible<remove_all_extends<_Tp>>>>::type
> +# endif
> + { };
> +
> + template<typename _Tp>
> + struct is_replaceable
> + : bool_constant<__builtin_is_replaceable(_Tp)>
> + { };
> +
> + /// @ingroup variable_templates
> + /// @since C++26
> + template<typename _Tp>
> + inline constexpr bool is_trivially_relocatable_v
> +# if __has_builtin(__builtin_is_trivially_relocatable)
> + = __builtin_is_trivially_relocatable(_Tp);
> +# else
> + = __builtin_is_cpp_trivially_relocatable(_Tp);
> +# endif
> +
> + template<typename _Tp>
> + inline constexpr bool is_nothrow_relocatable_v
> +# if _GLIBCXX_USE_BUILTIN_TRAIT(__builtin_is_nothrow_relocatable)
> + = __builtin_is_nothrow_relocatable(_Tp);
> +# else
> + = (is_trivially_relocatable_v<_Tp>
> + || (is_nothrow_move_constructible_v<remove_all_extents<_Tp>>
> + && is_nothrow_destructible_v<remove_all_extents<_Tp>>);
> +# endif
> +
> + template<typename _Tp>
> + inline constexpr bool is_replaceable_v
> + = __builtin_is_replaceable(_Tp);
> +#endif
> +
> /// @} group metaprogramming
>
> _GLIBCXX_END_NAMESPACE_VERSION
> --- libstdc++-v3/include/std/memory.jj 2025-07-09 20:38:59.050627934 +0200
> +++ libstdc++-v3/include/std/memory 2025-07-16 11:51:50.888265934 +0200
> @@ -122,6 +122,7 @@
> #define __glibcxx_want_to_address
> #define __glibcxx_want_transparent_operators
> #define __glibcxx_want_smart_ptr_owner_equality
> +#define __glibcxx_want_trivially_relocatable
> #include <bits/version.h>
>
> #if __cplusplus >= 201103L && __cplusplus <= 202002L && _GLIBCXX_HOSTED
> @@ -171,6 +172,121 @@ _GLIBCXX_END_NAMESPACE_VERSION
> } // namespace
> #endif // C++11 to C++20
>
> +#ifdef __cpp_lib_trivially_relocatable
> +namespace std _GLIBCXX_VISIBILITY(default)
> +{
> +_GLIBCXX_BEGIN_NAMESPACE_VERSION
> +
> + template<typename _Tp>
> + [[__gnu__::__always_inline__]]
> + inline _Tp*
> + trivially_relocate(_Tp* __first, _Tp* __last, _Tp* __result) noexcept
> + {
> + static_assert(is_trivially_relocatable_v<_Tp> && !is_const_v<_Tp>);
> + if (__first == __result)
> + return __last;
> +#if __has_builtin(__builtin_trivially_relocate)
> + __builtin_trivially_relocate(__result, __first, __last - __first);
> +#else
> + __builtin_memmove(static_cast<void*>(__result),
> + static_cast<const void*>(__first),
> + (__last - __first) * sizeof(_Tp));
> +#endif
> + return __result + (__last - __first);
> + }
> +
> + template<typename _Tp>
> + constexpr _Tp*
> + relocate(_Tp* __first, _Tp* __last, _Tp* __result) noexcept
> + {
> + static_assert(is_nothrow_relocatable_v<_Tp> && !is_const_v<_Tp>);
> + if !consteval
> + {
> + if constexpr (is_trivially_relocatable_v<_Tp>)
> + return std::trivially_relocate(__first, __last, __result);
> + }
> + if (__first == __result)
> + return __last;
> + if (__first == __last)
> + return __result;
> +
> + size_t __n = __last - __first;
> + if constexpr (is_move_constructible_v<_Tp>)
> + {
> + if !consteval
> + {
> + // If there is no overlap, move everything first and then
> + // destruct.
> + if ((__UINTPTR_TYPE__)__last <= (__UINTPTR_TYPE__)__result
> + || ((__UINTPTR_TYPE__)(__result + __n)
> + <= (__UINTPTR_TYPE__)__first))
> + {
> + __result = std::uninitialized_move(__first, __last,
> + __result);
> + std::destroy(__first, __last);
> + return __result;
> + }
> + }
> + }
> +
> + bool __fwd = true;
> + if consteval
> + {
> + // Use __builtin_constant_p to determine if __result and __first
> + // point into the same object, if they don't, there is no overlap
> + // and so either __fwd or !__fwd is fine.
> + if (__builtin_constant_p (__result < __first)
> + && __result > __first
> + && __result < __last)
> + __fwd = false;
> + }
> + else
> + {
> + __fwd = ((__UINTPTR_TYPE__)__result - (__UINTPTR_TYPE__)__first
> + >= (__UINTPTR_TYPE__)__last -
> (__UINTPTR_TYPE__)__first);
> + }
> + if (__fwd) [[likely]]
> + {
> + for (; __first != __last; ++__first, ++__result)
> + {
> + if constexpr (is_array_v<_Tp>)
> + std::relocate(std::begin(*__first), std::end(*__first),
> + std::addressof(*__result)[0]);
> + else
> + {
> + ::new(__result) _Tp(std::move(*__first));
> + __first->~_Tp();
> + }
> + }
> + return __result;
> + }
> + else
> + {
> + _Tp *__ret = __result + __n;
> + for (__result = __ret; __last != __first; )
> + {
> + --__last;
> + --__result;
> + if constexpr (is_array_v<_Tp>)
> + std::relocate(std::begin(*__last), std::end(*__last),
> + std::addressof(*__result)[0]);
> + else
> + {
> + ::new(__result) _Tp(std::move(*__last));
> + __last->~_Tp();
> + }
> + }
> + return __ret;
> + }
> + // If at constand evaluation is_trivially_relocatable_v<_Tp>
> + // but not is_move_constructible_V<_Tp>, fail.
> + __builtin_unreachable();
> + }
> +
> +_GLIBCXX_END_NAMESPACE_VERSION
> +} // namespace
> +#endif
> +
> #ifdef __cpp_lib_parallel_algorithm // C++ >= 17 && HOSTED
> // Parallel STL algorithms
> # if _PSTL_EXECUTION_POLICIES_DEFINED
> --- libstdc++-v3/testsuite/std/memory/relocate/relocate.cc.jj 2025-07-16
> 11:51:19.124688687 +0200
> +++ libstdc++-v3/testsuite/std/memory/relocate/relocate.cc 2025-07-16
> 12:45:01.656814019 +0200
> @@ -0,0 +1,398 @@
> +// { dg-do run { target c++26 } }
> +
> +#include <memory>
> +
> +#include <testsuite_hooks.h>
> +#include <testsuite_allocator.h>
> +
> +struct S trivially_relocatable_if_eligible
> +{
> + constexpr S() : s(0) {}
> + constexpr S(int x) : s(x) {}
> + constexpr S(S&& x) : s(x.s) {}
> + constexpr S& operator=(S&& x) { s = x.s; return *this; }
> + unsigned char s;
> +};
> +
> +struct T
> +{
> + constexpr T() : t(0) {}
> + constexpr T(int x) : t(x) {}
> + constexpr T(T&& x) noexcept : t(x.t) {}
> + constexpr T& operator=(T&& x) { t = x.t; return *this; }
> + unsigned char t;
> +};
> +
> +static_assert(std::is_trivially_relocatable_v<S>);
> +static_assert(std::is_nothrow_relocatable_v<S>);
> +static_assert(std::is_nothrow_relocatable_v<T>);
> +
> +void
> +test_relocate()
> +{
>
I would prefer this function to be templated on the tested type (S or T),
instead of having the code duplicated. This should reduce the test code by
half.
> + unsigned char a[20], b[20], c[20], d[20];
> + S *sf, *sl, *sr;
> + T *tf, *tl, *tr;
> + sf = ::new(&a[2]) S(11);
> + tf = ::new(&b[2]) T(11);
> + for (int i = 3; i < 8; ++i)
> + {
> + sl = ::new(&a[i]) S(i + 9);
> + tl = ::new(&b[i]) T(i + 9);
> + }
> + ++sl;
> + ++tl;
> + sr = ::new(&c[5]) S(42);
> + tr = ::new(&d[5]) T(42);
> + sr->~S();
> + tr->~T();
> + VERIFY( std::relocate(sf, sl, sr) == sr + 6 );
> + VERIFY( std::relocate(tf, tl, tr) == tr + 6 );
> + for (int i = 0; i < 6; ++i)
> + {
> + VERIFY( sr->s == i + 11 );
> + VERIFY( tr->t == i + 11 );
> + sr->~S();
> + tr->~T();
> + ++sr;
> + ++tr;
> + }
> + sf = ::new(&a[2]) S(11);
> + tf = ::new(&b[2]) T(11);
> + for (int i = 3; i < 8; ++i)
> + {
> + sl = ::new(&a[i]) S(i + 9);
> + tl = ::new(&b[i]) T(i + 9);
> + }
> + ++sl;
> + ++tl;
> + sr = ::new(&a[1]) S(42);
> + tr = ::new(&b[1]) T(42);
> + sr->~S();
> + tr->~T();
> + VERIFY( std::relocate(sf, sl, sr) == sr + 6 );
> + VERIFY( std::relocate(tf, tl, tr) == tr + 6 );
> + for (int i = 0; i < 6; ++i)
> + {
> + VERIFY( sr->s == i + 11 );
> + VERIFY( tr->t == i + 11 );
> + sr->~S();
> + tr->~T();
> + ++sr;
> + ++tr;
> + }
> + sf = ::new(&a[2]) S(11);
> + tf = ::new(&b[2]) T(11);
> + for (int i = 3; i < 8; ++i)
> + {
> + sl = ::new(&a[i]) S(i + 9);
> + tl = ::new(&b[i]) T(i + 9);
> + }
> + ++sl;
> + ++tl;
> + sr = sf + 1;
> + tr = tf + 1;
> + VERIFY( std::relocate(sf, sl, sr) == sr + 6 );
> + VERIFY( std::relocate(tf, tl, tr) == tr + 6 );
> + for (int i = 0; i < 6; ++i)
> + {
> + VERIFY( sr->s == i + 11 );
> + VERIFY( tr->t == i + 11 );
> + sr->~S();
> + tr->~T();
> + ++sr;
> + ++tr;
> + }
> +}
> +
> +constexpr void
> +test_relocate_constexpr()
> +{
> + S a[20], c[20];
> + T b[20], d[20];
>
+ for (int i = 0; i < 20; ++i)
> + {
> + a[i].~S();
> + b[i].~T();
> + c[i].~S();
> + d[i].~T();
> + }
>
Instead of destroying and then re-constructing local objects, you could now
use trivial_union
that I have sent in another email, to store the arrays.
> + S *sf, *sl, *sr;
> + T *tf, *tl, *tr;
> + sf = ::new(&a[2]) S(11);
> + tf = ::new(&b[2]) T(11);
> + for (int i = 3; i < 8; ++i)
> + {
> + sl = ::new(&a[i]) S(i + 9);
> + tl = ::new(&b[i]) T(i + 9);
> + }
> + ++sl;
> + ++tl;
> + sr = ::new(&c[5]) S(42);
> + tr = ::new(&d[5]) T(42);
> + sr->~S();
> + tr->~T();
> + VERIFY( std::relocate(sf, sl, sr) == sr + 6 );
> + VERIFY( std::relocate(tf, tl, tr) == tr + 6 );
> + for (int i = 0; i < 6; ++i)
> + {
> + VERIFY( sr->s == i + 11 );
> + VERIFY( tr->t == i + 11 );
> + sr->~S();
> + tr->~T();
> + ++sr;
> + ++tr;
> + }
> + sf = ::new(&a[2]) S(11);
> + tf = ::new(&b[2]) T(11);
> + for (int i = 3; i < 8; ++i)
> + {
> + sl = ::new(&a[i]) S(i + 9);
> + tl = ::new(&b[i]) T(i + 9);
> + }
> + ++sl;
> + ++tl;
> + sr = ::new(&a[1]) S(42);
> + tr = ::new(&b[1]) T(42);
> + sr->~S();
> + tr->~T();
> + VERIFY( std::relocate(sf, sl, sr) == sr + 6 );
> + VERIFY( std::relocate(tf, tl, tr) == tr + 6 );
> + for (int i = 0; i < 6; ++i)
> + {
> + VERIFY( sr->s == i + 11 );
> + VERIFY( tr->t == i + 11 );
> + sr->~S();
> + tr->~T();
> + ++sr;
> + ++tr;
> + }
> + sf = ::new(&a[2]) S(11);
> + tf = ::new(&b[2]) T(11);
> + for (int i = 3; i < 8; ++i)
> + {
> + sl = ::new(&a[i]) S(i + 9);
> + tl = ::new(&b[i]) T(i + 9);
> + }
> + ++sl;
> + ++tl;
> + sr = sf + 1;
> + tr = tf + 1;
> + VERIFY( std::relocate(sf, sl, sr) == sr + 6 );
> + VERIFY( std::relocate(tf, tl, tr) == tr + 6 );
> + for (int i = 0; i < 6; ++i)
> + {
> + VERIFY( sr->s == i + 11 );
> + VERIFY( tr->t == i + 11 );
> + sr->~S();
> + tr->~T();
> + ++sr;
> + ++tr;
> + }
> + for (int i = 0; i < 20; ++i)
> + {
> + ::new(&a[i]) S(0);
> + ::new(&b[i]) T(0);
> + ::new(&c[i]) S(0);
> + ::new(&d[i]) T(0);
> + }
> +}
> +
> +void
> +test_relocate_array()
> +{
> + unsigned char a[20], b[20], c[20], d[20];
> + using SA = S[2];
> + using TA = T[2];
> + SA *sf, *sl, *sr;
> + TA *tf, *tl, *tr;
> + sf = (SA *)(::new(&a[2]) SA{11, 12});
> + tf = (TA *)(::new(&b[2]) TA{11, 12});
> + for (int i = 0; i < 5; ++i)
> + {
> + sl = (SA *)(::new(&a[4 + 2 * i]) SA{13 + 2 * i, 14 + 2 * i});
> + tl = (TA *)(::new(&b[4 + 2 * i]) TA{13 + 2 * i, 14 + 2 * i});
> + }
> + ++sl;
> + ++tl;
> + sr = (SA *)(::new(&c[6]) SA{42, 42});
> + tr = (TA *)(::new(&d[6]) TA{42, 42});
> + (*sr)[0].~S();
> + (*sr)[1].~S();
> + (*tr)[0].~T();
> + (*tr)[1].~T();
> + VERIFY( std::relocate(sf, sl, sr) == sr + 6 );
> + VERIFY( std::relocate(tf, tl, tr) == tr + 6 );
> + for (int i = 0; i < 6; ++i)
> + {
> + VERIFY( (*sr)[0].s == 2 * i + 11 && (*sr)[1].s == 2 * i + 12 );
> + VERIFY( (*tr)[0].t == 2 * i + 11 && (*tr)[1].t == 2 * i + 12 );
> + (*sr)[0].~S();
> + (*sr)[1].~S();
> + (*tr)[0].~T();
> + (*tr)[1].~T();
> + ++sr;
> + ++tr;
> + }
> + sf = (SA *)(::new(&a[2]) SA{11, 12});
> + tf = (TA *)(::new(&b[2]) TA{11, 12});
> + for (int i = 0; i < 5; ++i)
> + {
> + sl = (SA *)(::new(&a[4 + 2 * i]) SA{13 + 2 * i, 14 + 2 * i});
> + tl = (TA *)(::new(&b[4 + 2 * i]) TA{13 + 2 * i, 14 + 2 * i});
> + }
> + ++sl;
> + ++tl;
> + sr = (SA *)(::new(&a[0]) SA{42, 42});
> + tr = (TA *)(::new(&b[0]) TA{42, 42});
> + (*sr)[0].~S();
> + (*sr)[1].~S();
> + (*tr)[0].~T();
> + (*tr)[1].~T();
> + VERIFY( std::relocate(sf, sl, sr) == sr + 6 );
> + VERIFY( std::relocate(tf, tl, tr) == tr + 6 );
> + for (int i = 0; i < 6; ++i)
> + {
> + VERIFY( (*sr)[0].s == 2 * i + 11 && (*sr)[1].s == 2 * i + 12 );
> + VERIFY( (*tr)[0].t == 2 * i + 11 && (*tr)[1].t == 2 * i + 12 );
> + (*sr)[0].~S();
> + (*sr)[1].~S();
> + (*tr)[0].~T();
> + (*tr)[1].~T();
> + ++sr;
> + ++tr;
> + }
> + sf = (SA *)(::new(&a[2]) SA{11, 12});
> + tf = (TA *)(::new(&b[2]) TA{11, 12});
> + for (int i = 0; i < 5; ++i)
> + {
> + sl = (SA *)(::new(&a[4 + 2 * i]) SA{13 + 2 * i, 14 + 2 * i});
> + tl = (TA *)(::new(&b[4 + 2 * i]) TA{13 + 2 * i, 14 + 2 * i});
> + }
> + ++sl;
> + ++tl;
> + sr = sf + 1;
> + tr = tf + 1;
> + VERIFY( std::relocate(sf, sl, sr) == sr + 6 );
> + VERIFY( std::relocate(tf, tl, tr) == tr + 6 );
> + for (int i = 0; i < 6; ++i)
> + {
> + VERIFY( (*sr)[0].s == 2 * i + 11 && (*sr)[1].s == 2 * i + 12 );
> + VERIFY( (*tr)[0].t == 2 * i + 11 && (*tr)[1].t == 2 * i + 12 );
> + (*sr)[0].~S();
> + (*sr)[1].~S();
> + (*tr)[0].~T();
> + (*tr)[1].~T();
> + ++sr;
> + ++tr;
> + }
> +}
> +
> +void
> +test_trivially_relocate()
> +{
> + unsigned char a[20], c[20];
> + S *sf, *sl, *sr;
> + sf = ::new(&a[2]) S(11);
> + for (int i = 3; i < 8; ++i)
> + sl = ::new(&a[i]) S(i + 9);
> + ++sl;
> + sr = ::new(&c[5]) S(42);
> + sr->~S();
> + VERIFY( std::trivially_relocate(sf, sl, sr) == sr + 6 );
> + for (int i = 0; i < 6; ++i)
> + {
> + VERIFY( sr->s == i + 11 );
> + sr->~S();
> + ++sr;
> + }
> + sf = ::new(&a[2]) S(11);
> + for (int i = 3; i < 8; ++i)
> + sl = ::new(&a[i]) S(i + 9);
> + ++sl;
> + sr = ::new(&a[1]) S(42);
> + sr->~S();
> + VERIFY( std::trivially_relocate(sf, sl, sr) == sr + 6 );
> + for (int i = 0; i < 6; ++i)
> + {
> + VERIFY( sr->s == i + 11 );
> + sr->~S();
> + ++sr;
> + }
> + sf = ::new(&a[2]) S(11);
> + for (int i = 3; i < 8; ++i)
> + sl = ::new(&a[i]) S(i + 9);
> + ++sl;
> + sr = sf + 1;
> + VERIFY( std::trivially_relocate(sf, sl, sr) == sr + 6 );
> + for (int i = 0; i < 6; ++i)
> + {
> + VERIFY( sr->s == i + 11 );
> + sr->~S();
> + ++sr;
> + }
> +}
> +
> +void
> +test_trivially_relocate_array()
> +{
> + unsigned char a[20], c[20];
> + using SA = S[2];
> + SA *sf, *sl, *sr;
> + sf = (SA *)(::new(&a[2]) SA{11, 12});
> + for (int i = 0; i < 5; ++i)
> + sl = (SA *)(::new(&a[4 + 2 * i]) SA{13 + 2 * i, 14 + 2 * i});
> + ++sl;
> + sr = (SA *)(::new(&c[6]) SA{42, 42});
> + (*sr)[0].~S();
> + (*sr)[1].~S();
> + VERIFY( std::trivially_relocate(sf, sl, sr) == sr + 6 );
> + for (int i = 0; i < 6; ++i)
> + {
> + VERIFY( (*sr)[0].s == 2 * i + 11 && (*sr)[1].s == 2 * i + 12 );
> + (*sr)[0].~S();
> + (*sr)[1].~S();
> + ++sr;
> + }
> + sf = (SA *)(::new(&a[2]) SA{11, 12});
> + for (int i = 0; i < 5; ++i)
> + sl = (SA *)(::new(&a[4 + 2 * i]) SA{13 + 2 * i, 14 + 2 * i});
> + ++sl;
> + sr = (SA *)(::new(&a[0]) SA{42, 42});
> + (*sr)[0].~S();
> + (*sr)[1].~S();
> + VERIFY( std::trivially_relocate(sf, sl, sr) == sr + 6 );
> + for (int i = 0; i < 6; ++i)
> + {
> + VERIFY( (*sr)[0].s == 2 * i + 11 && (*sr)[1].s == 2 * i + 12 );
> + (*sr)[0].~S();
> + (*sr)[1].~S();
> + ++sr;
> + }
> + sf = (SA *)(::new(&a[2]) SA{11, 12});
> + for (int i = 0; i < 5; ++i)
> + sl = (SA *)(::new(&a[4 + 2 * i]) SA{13 + 2 * i, 14 + 2 * i});
> + ++sl;
> + sr = sf + 1;
> + VERIFY( std::trivially_relocate(sf, sl, sr) == sr + 6 );
> + for (int i = 0; i < 6; ++i)
> + {
> + VERIFY( (*sr)[0].s == 2 * i + 11 && (*sr)[1].s == 2 * i + 12 );
> + (*sr)[0].~S();
> + (*sr)[1].~S();
> + ++sr;
> + }
> +}
> +
> +int main()
> +{
> + test_relocate();
> + test_relocate_constexpr();
> + test_trivially_relocate();
> + test_relocate_array();
> + test_trivially_relocate_array();
> + static_assert([] {
> + test_relocate_constexpr();
> + return true;
> + }());
> +}
>
> Jakub
>
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://gcc.gnu.org/pipermail/libstdc++/attachments/20250826/a9cdec0f/attachment-0001.htm>
More information about the Libstdc++
mailing list