A gentle ping

On Thu, Feb 26, 2026 at 8:00 PM 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().
>
> We remove operator-() in testsuite_greedy_ops.h; otherwise it breaks
> the range size computation.
>
> 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.
>         * libstdc++-v3/testsuite/util/testsuite_greedy_ops.h (greedy_ops):
>         Comment out operator-(T, T).
> ---
>  libstdc++-v3/include/bits/stl_uninitialized.h |  4 +-
>  .../uninitialized_move/121789.cc              | 37 +++++++++++++++++++
>  .../testsuite/util/testsuite_greedy_ops.h     |  3 +-
>  3 files changed, 41 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..672ab717741 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);
> @@ -290,11 +290,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>           ptrdiff_t __n = __last - __first;
>           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..5a2a164421f
> --- /dev/null
> +++
> b/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_move/121789.cc
> @@ -0,0 +1,37 @@
> +// Copyright (C) 2026 Free Software Foundation, Inc.
> +//
> +// 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);
> +}
> diff --git a/libstdc++-v3/testsuite/util/testsuite_greedy_ops.h
> b/libstdc++-v3/testsuite/util/testsuite_greedy_ops.h
> index 053e36956b2..88d502663d8 100644
> --- a/libstdc++-v3/testsuite/util/testsuite_greedy_ops.h
> +++ b/libstdc++-v3/testsuite/util/testsuite_greedy_ops.h
> @@ -44,14 +44,15 @@ namespace greedy_ops
>
>    template<typename T>
>    X operator>=(T, T)
>    { return X(); }
>
> +  /*
>    template<typename T>
>    X operator-(T, T)
>    { return X(); }
> -  /*
> +
>    template<typename T>
>    T operator+(std::size_t, T)
>    { return T(); }
>    */
>    template<typename T>
> --
> 2.53.0
>
>

Reply via email to