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

--- Comment #4 from Jonathan Wakely <redi at gcc dot gnu.org> ---
(In reply to Jan Hubicka from comment #2)
> --- a/libstdc++-v3/include/bits/stl_uninitialized.h
> +++ b/libstdc++-v3/include/bits/stl_uninitialized.h
> @@ -1130,7 +1130,58 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>         }
>        return __result + __count;
>      }
> +
> +  template <typename _Tp, typename _Allocator>
> +    _GLIBCXX20_CONSTEXPR
> +    inline __enable_if_t<std::__is_bitwise_relocatable<_Tp>::value, _Tp*>
> +    __relocate_a(_Tp * __restrict __first, _Tp *__last,
> +                _Tp * __restrict __result, _Allocator& __alloc) noexcept

This is wrong, we can't optimize arbitrary allocators, only when the allocator
is std::allocator<_Tp>. That's what the existing code is doing with the
indirection from __relocate_a to __relocate_a_1.

> +    {
> +      ptrdiff_t __count = __last - __first;
> +      if (__count > 0)
> +       {
> +#ifdef __cpp_lib_is_constant_evaluated
> +         if (std::is_constant_evaluated())
> +           {
> +             for (; __first != __last; ++__first, (void)++__result)

You don't need the (void) case here because __first and __result are both
pointers. That's only needed for the generic __relocate_a that deals with
arbitrary iterator types.

> +               {
> +                 // manually inline relocate_object_a to not lose restrict
> qualifiers

We don't care about restrict when is_constant_evaluated is true, we're not
optimizing this code. It just gets interpreted at compile time. There is no
reason to inline __relocate_object_a for the is_constant_evaluated case.


> +                 typedef std::allocator_traits<_Allocator> __traits;
> +                 __traits::construct(__alloc, __result,
> std::move(*__first));
> +                 __traits::destroy(__alloc, std::__addressof(*__first));
> +               }
> +             return __result;
> +           }
>  #endif
> +         __builtin_memcpy(__result, __first, __count * sizeof(_Tp));
> +       }
> +      return __result + __count;
> +    }
> +#endif
> +
> +  template <typename _Tp, typename _Allocator>
> +    _GLIBCXX20_CONSTEXPR
> +#if _GLIBCXX_HOSTED
> +    inline __enable_if_t<!std::__is_bitwise_relocatable<_Tp>::value, _Tp*>
> +#else
> +    inline _Tp *
> +#endif
> +    __relocate_a(_Tp * __restrict __first, _Tp *__last,
> +                _Tp * __restrict __result, _Allocator& __alloc)
> +    noexcept(noexcept(std::allocator_traits<_Allocator>::construct(__alloc,
> +                        __result, std::move(*__first)))
> +            && noexcept(std::allocator_traits<_Allocator>::destroy(
> +                           __alloc, std::__addressof(*__first))))
> +    {
> +      for (; __first != __last; ++__first, (void)++__result)
> +       {
> +         // manually inline relocate_object_a to not lose restrict
> qualifiers
> +         typedef std::allocator_traits<_Allocator> __traits;
> +         __traits::construct(__alloc, __result, std::move(*__first));
> +         __traits::destroy(__alloc, std::__addressof(*__first));
> +       }

I don't understand this overload at all. Is this overload the one that actually
gets used for your testcase? I think it should be, because std::pair<int, int>
is not bitwise_relocatable.

Why does the restrict qualifier get lost if we don't inline relocate_object_a?
That function is restrict-qualified as well.


> +      return __result;
> +    }
>  
>    template <typename _InputIterator, typename _ForwardIterator,
>             typename _Allocator>

Reply via email to