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>