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.

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  <ja...@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()
+{
+  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();
+    }
+  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

Reply via email to