On Tue, 16 Dec 2025, Jonathan Wakely wrote:
> ping
>
> On Mon, 8 Dec 2025 at 11:08, Jonathan Wakely <[email protected]> wrote:
> >
> > Copying narrow characters to a range of bool using std::copy cannot be
> > optimized to use std::memcpy. Assignment of an arbitrary integer to a
> > bool needs to convert all non-zero values to true, so is not a simple
> > memcpy-like or bit_cast-like operation. We currently get this wrong and
> > optimize it to memcpy, producing invalid bool values.
> >
> > By making __memcpyable_integer<bool> false we disable memcpy
> > optimizations for heterogeneous std::copy and std::move calls where
> > either the source or destination type is bool. Copies where both types
> > are bool can still optimize to memcpy, because we don't check
> > __memcpyable_integer in that case.
> >
> > This disables the memcpy optimization for bool as the source type,
> > which isn't actually necessary (the representation of bool in GCC is
> > 0x00 or 0x01 and so copying bool to char is just a bit_cast). We don't
> > currently have a straightforward way to allow memcpy for bool to char
> > but disallow the inverse. This seems acceptable as using std::copy with
> > bool inputs and narrow character outputs is probably not common enough
> > for this to be an important optimization to do in the library code.
> >
> > libstdc++-v3/ChangeLog:
> >
> > PR libstdc++/122907
> > * include/bits/cpp_type_traits.h (__memcpyable_integer<bool>):
> > Define as false.
> > * testsuite/25_algorithms/copy/122907.cc: New test.
LGTM, seems like an obviously safe restriction of 93059 optimization.
> > ---
> >
> > Tested x86_64-linux.
> >
> > libstdc++-v3/include/bits/cpp_type_traits.h | 7 +++
> > .../testsuite/25_algorithms/copy/122907.cc | 43 +++++++++++++++++++
> > 2 files changed, 50 insertions(+)
> > create mode 100644 libstdc++-v3/testsuite/25_algorithms/copy/122907.cc
> >
> > diff --git a/libstdc++-v3/include/bits/cpp_type_traits.h
> > b/libstdc++-v3/include/bits/cpp_type_traits.h
> > index 38cea4c67b76..0a42b7b8d997 100644
> > --- a/libstdc++-v3/include/bits/cpp_type_traits.h
> > +++ b/libstdc++-v3/include/bits/cpp_type_traits.h
> > @@ -518,6 +518,13 @@ __INT_N(__int128)
> > struct __memcpyable_integer<volatile _Tp>
> > { enum { __width = 0 }; };
> >
> > + // Assigning an integer to bool needs to convert all non-zero values to
> > true
> > + // so it is not a memcpyable integer.
> > + // __memcpyable<bool*, bool*> is still true though.
> > + template<>
> > + struct __memcpyable_integer<bool>
> > + { enum { __width = 0 }; };
> > +
> > // Specializations for __intNN types with padding bits.
> > #if defined __GLIBCXX_TYPE_INT_N_0 && __GLIBCXX_BITSIZE_INT_N_0 %
> > __CHAR_BIT__
> > __extension__
> > diff --git a/libstdc++-v3/testsuite/25_algorithms/copy/122907.cc
> > b/libstdc++-v3/testsuite/25_algorithms/copy/122907.cc
> > new file mode 100644
> > index 000000000000..02276cea7b9b
> > --- /dev/null
> > +++ b/libstdc++-v3/testsuite/25_algorithms/copy/122907.cc
> > @@ -0,0 +1,43 @@
> > +// { dg-do run }
> > +
> > +// Bug libstdc++/122907
> > +// std::copy incorrectly uses memcpy when copying from signed or unsigned
> > char
> > +// buffer to bool buffer
> > +
> > +#include <algorithm>
> > +#include <testsuite_hooks.h>
> > +
> > +template<typename T>
> > +__attribute__((noinline,noipa))
> > +void
> > +test_pr122907(T (&buf)[4])
> > +{
> > + unsigned char uc[4];
> > + bool bool_buf[4];
> > + std::copy(buf, buf+1, bool_buf);
> > + std::copy(bool_buf, bool_buf+1, uc);
> > + VERIFY(uc[0] == bool(buf[0]));
> > + std::copy(buf, buf+4, bool_buf);
> > + std::copy(bool_buf, bool_buf+4, uc);
> > + VERIFY(uc[0] == bool(buf[0]));
> > + VERIFY(uc[1] == bool(buf[1]));
> > + VERIFY(uc[2] == bool(buf[2]));
> > + VERIFY(uc[3] == bool(buf[3]));
> > +}
> > +
> > +template<typename T>
> > +void
> > +test_pr122907()
> > +{
> > + T buf[4] = { (T)3, (T)2, (T)1, (T)0 };
> > + test_pr122907(buf);
> > +}
> > +
> > +int main()
> > +{
> > + test_pr122907<char>();
> > + test_pr122907<signed char>();
> > + test_pr122907<unsigned char>();
> > + test_pr122907<bool>();
> > + test_pr122907<int>();
> > +}
> > --
> > 2.52.0
> >
>
>