On Mon, Feb 16, 2026 at 8:29 PM Jonathan Wakely <[email protected]> wrote:
> On Mon, 16 Feb 2026 at 17:59, Avi Kivity <[email protected]> wrote: > > > > std::uninitialized_move{,_n} delegates to the corresponding > > std::uninitialized_copy() variant after wrapping with a move > > iterator, but the std::uninitialized_copy() doesn't unwrap the > > move iterator, therefore losing the memcpy optimization if the > > iterators were just pointers. > > > > Fix this by unwrapping the move iterator using __miter_base(). To > > prevent some greedy_ops tests starting to fail by consuming the > > pointer difference, we have to unwrap the move iterator before computing > > the iterator difference as well. > > > > libstdc++v3/Changelog: > > > > PR libstdc++/121789 > > * include/bits/stl_uninitialized.h (uninitialized_copy): > > Unwrap move iterators > > * > testsuite/20_util/specialized_algorithms/uninitialized_move/121789.cc: > > New test. > > --- > > > > Disclosure: I was assisted by AI. > > > > libstdc++-v3/include/bits/stl_uninitialized.h | 8 ++-- > > .../uninitialized_move/121789.cc | 37 +++++++++++++++++++ > > 2 files changed, 42 insertions(+), 3 deletions(-) > > create mode 100644 > libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_move/121789.cc > > > > diff --git a/libstdc++-v3/include/bits/stl_uninitialized.h > b/libstdc++-v3/include/bits/stl_uninitialized.h > > index 82e4ba2ff7b..fa9d896fefc 100644 > > --- a/libstdc++-v3/include/bits/stl_uninitialized.h > > +++ b/libstdc++-v3/include/bits/stl_uninitialized.h > > @@ -273,11 +273,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > > // We cannot tell when this condition is true in general, > > // so we rely on the __memcpyable trait. > > > > #if __cplusplus >= 201103L > > using _Dest = decltype(std::__niter_base(__result)); > > - using _Src = decltype(std::__niter_base(__first)); > > + using _Src = > decltype(std::__miter_base(std::__niter_base(__first))); > > using _ValT = typename > iterator_traits<_ForwardIterator>::value_type; > > > > #if __glibcxx_raw_memory_algorithms >= 202411L // >= C++26 > > if consteval { > > return std::__do_uninit_copy(__first, __last, __result); > > @@ -285,16 +285,18 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > > #endif > > if constexpr (!__is_trivially_constructible(_ValT, > decltype(*__first))) > > return std::__do_uninit_copy(__first, __last, __result); > > else if constexpr (__memcpyable<_Dest, _Src>::__value) > > { > > - ptrdiff_t __n = __last - __first; > > + ptrdiff_t __n > > + = std::__miter_base(std::__niter_base(__last)) > > + - std::__miter_base(std::__niter_base(__first)); > > This change seems completely unnecessary (I blame the AI assistance). > > It is necessary. Without it, 23_containers/vector/types/1.cc will not compile since greedy_ops' operator- will fight with the move iterator's operator-. I mentioned it in the commit changelog. Perhaps std::distance() is better here. > > > if (__n > 0) [[__likely__]] > > { > > using _ValT = typename remove_pointer<_Src>::type; > > __builtin_memcpy(std::__niter_base(__result), > > - std::__niter_base(__first), > > + > std::__miter_base(std::__niter_base(__first)), > > __n * sizeof(_ValT)); > > __result += __n; > > } > > return __result; > > } > > diff --git > a/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_move/121789.cc > b/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_move/121789.cc > > new file mode 100644 > > index 00000000000..7ac8cf6496f > > --- /dev/null > > +++ > b/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_move/121789.cc > > @@ -0,0 +1,37 @@ > > +// Copyright (C) 2025-2026 Free Software Foundation, Inc. > > There should not be any copyright/license header here, see > https://gcc.gnu.org/onlinedocs/libstdc++/manual/test.html#test.new_tests > > I can remove it. The test was inspired by other tests in the directory, so copying was involved. I do have FSF copyright assignment, at least for glibc/binutils, not sure about gcc. > > +// > > +// This file is part of the GNU ISO C++ Library. This library is free > > +// software; you can redistribute it and/or modify it under the > > +// terms of the GNU General Public License as published by the > > +// Free Software Foundation; either version 3, or (at your option) > > +// any later version. > > + > > +// This library is distributed in the hope that it will be useful, > > +// but WITHOUT ANY WARRANTY; without even the implied warranty of > > +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > > +// GNU General Public License for more details. > > + > > +// You should have received a copy of the GNU General Public License > along > > +// with this library; see the file COPYING3. If not see > > +// <http://www.gnu.org/licenses/>. > > + > > +// { dg-options "-O1 -fdump-tree-optimized" } > > +// { dg-do compile { target c++17 } } > > +// { dg-final { scan-tree-dump "memcpy" "optimized" } } > > + > > +// PR libstdc++/121789 > > +// std::uninitialized_move_n() and friends don't optimize to memcpy > > + > > +#include <memory> > > + > > +struct T { int x; }; > > + > > +void f(T* src, T* dst, unsigned n) > > +{ > > + std::uninitialized_move(src, src + n, dst); > > +} > > + > > +void g(T* src, T* dst, unsigned n) > > +{ > > + std::uninitialized_move_n(src, n, dst); > > +} > > -- > > 2.53.0 > > > >
