https://gcc.gnu.org/bugzilla/show_bug.cgi?id=87106

--- Comment #25 from Jonathan Wakely <redi at gcc dot gnu.org> ---
I think that's the answer, yes (although I haven't refreshed my memory of the
issues completely). A call to memmove does not begin the lifetime of any
objects at the destination address.

For types that are trivially-copyable but not trivial we could consider doing a
first pass over the range to default-initialize the destination objects, then
do the memmove to overwrite them with the desired values. In theory, the
optimizer would realize the default-initializations are dead stores and
completely remove that first loop (but only after the semantic checks have
concluded that we are obeying the languages rules and have no undefined
behaviour).

So change the bitwise_relocatable condition to is_trivially_copyable &&
is_default_constructible and make __relocate_a_1 do something like this
(completely untested, typing as I think about it):

  template<typename _Tp, typename = void>
    struct __is_bitwise_relocatable
    : __and_<is_trivially_copyable<_Tp>, is_default_constructible<_Tp>> { };

  template <typename _Tp, typename _Up>
    inline __enable_if_t<std::__is_bitwise_relocatable<_Tp>::value, _Tp*>
    __relocate_a_1(_Tp* __first, _Tp* __last,
                   _Tp* __result, allocator<_Up>& a) noexcept
    {
      ptrdiff_t __count = __last - __first;
      if (__count > 0)
        {
          if constexpr (!is_trivial_v<T>)
            {
#ifdef __OPTIMIZE__
              // begin lifetime of destination objects
              std::__uninitialized_default_novalue_n(result, result + count);
#else
              // can't do bitwise relocation today
              for (ptrdiff_t i = 0; i < count; ++i)
                __relocate_object_a(result + i, first + i, a);
              return result + count;
#endif         
            }
          __builtin_memmove(__result, __first, __count * sizeof(_Tp));
        }
      return __result + __count;
    }

Reply via email to