Message ID | 20240619163810.1792381-1-jwakely@redhat.com |
---|---|
State | New |
Headers | show |
Series | libstdc++: Fix std::to_array for trivial-ish types [PR115522] | expand |
Pushed to trunk now. On Wed, 19 Jun 2024 at 17:38, Jonathan Wakely <jwakely@redhat.com> wrote: > > Tested x86_64-linux. Not pushed yet. backports will be needed too. > > -- >8 -- > > Due to PR c++/85723 the std::is_trivial trait is true for types with a > deleted default constructor, so the use of std::is_trivial in > std::to_array is not sufficient to ensure the type can be trivially > default constructed then filled using memcpy. > > I also forgot that a type with a deleted assignment operator can still > be trivial, so we also need to check that it's assignable because the > is_constant_evaluated() path can't use memcpy. > > Replace the uses of std::is_trivial with std::is_trivially_copyable > (needed for memcpy), std::is_trivially_default_constructible (needed so > that the default construction is valid and does no work) and > std::is_copy_assignable (needed for the constant evaluation case). > > libstdc++-v3/ChangeLog: > > PR libstdc++/115522 > * include/std/array (to_array): Workaround the fact that > std::is_trivial is not sufficient to check that a type is > trivially default constructible and assignable. > * testsuite/23_containers/array/creation/115522.cc: New test. > --- > libstdc++-v3/include/std/array | 8 +++-- > .../23_containers/array/creation/115522.cc | 33 +++++++++++++++++++ > 2 files changed, 39 insertions(+), 2 deletions(-) > create mode 100644 libstdc++-v3/testsuite/23_containers/array/creation/115522.cc > > diff --git a/libstdc++-v3/include/std/array b/libstdc++-v3/include/std/array > index 39695471e24..8710bf75924 100644 > --- a/libstdc++-v3/include/std/array > +++ b/libstdc++-v3/include/std/array > @@ -431,7 +431,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > static_assert(is_constructible_v<_Tp, _Tp&>); > if constexpr (is_constructible_v<_Tp, _Tp&>) > { > - if constexpr (is_trivial_v<_Tp>) > + if constexpr (is_trivially_copyable_v<_Tp> > + && is_trivially_default_constructible_v<_Tp> > + && is_copy_assignable_v<_Tp>) > { > array<remove_cv_t<_Tp>, _Nm> __arr; > if (!__is_constant_evaluated() && _Nm != 0) > @@ -460,7 +462,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > static_assert(is_move_constructible_v<_Tp>); > if constexpr (is_move_constructible_v<_Tp>) > { > - if constexpr (is_trivial_v<_Tp>) > + if constexpr (is_trivially_copyable_v<_Tp> > + && is_trivially_default_constructible_v<_Tp> > + && is_copy_assignable_v<_Tp>) > { > array<remove_cv_t<_Tp>, _Nm> __arr; > if (!__is_constant_evaluated() && _Nm != 0) > diff --git a/libstdc++-v3/testsuite/23_containers/array/creation/115522.cc b/libstdc++-v3/testsuite/23_containers/array/creation/115522.cc > new file mode 100644 > index 00000000000..37073e002bd > --- /dev/null > +++ b/libstdc++-v3/testsuite/23_containers/array/creation/115522.cc > @@ -0,0 +1,33 @@ > +// { dg-do compile { target c++20 } } > + > +// PR libstdc++/115522 std::to_array no longer works for struct which is > +// trivial but not default constructible > + > +#include <array> > + > +void > +test_deleted_ctor() > +{ > + struct S > + { > + S() = delete; > + S(int) { } > + }; > + > + S arr[1] = {{1}}; > + auto arr1 = std::to_array(arr); > + auto arr2 = std::to_array(std::move(arr)); > +} > + > +void > +test_deleted_assignment() > +{ > + struct S > + { > + void operator=(const S&) = delete; > + }; > + > + S arr[1] = {}; > + auto a1 = std::to_array(arr); > + auto a2 = std::to_array(std::move(arr)); > +} > -- > 2.45.1 >
diff --git a/libstdc++-v3/include/std/array b/libstdc++-v3/include/std/array index 39695471e24..8710bf75924 100644 --- a/libstdc++-v3/include/std/array +++ b/libstdc++-v3/include/std/array @@ -431,7 +431,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION static_assert(is_constructible_v<_Tp, _Tp&>); if constexpr (is_constructible_v<_Tp, _Tp&>) { - if constexpr (is_trivial_v<_Tp>) + if constexpr (is_trivially_copyable_v<_Tp> + && is_trivially_default_constructible_v<_Tp> + && is_copy_assignable_v<_Tp>) { array<remove_cv_t<_Tp>, _Nm> __arr; if (!__is_constant_evaluated() && _Nm != 0) @@ -460,7 +462,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION static_assert(is_move_constructible_v<_Tp>); if constexpr (is_move_constructible_v<_Tp>) { - if constexpr (is_trivial_v<_Tp>) + if constexpr (is_trivially_copyable_v<_Tp> + && is_trivially_default_constructible_v<_Tp> + && is_copy_assignable_v<_Tp>) { array<remove_cv_t<_Tp>, _Nm> __arr; if (!__is_constant_evaluated() && _Nm != 0) diff --git a/libstdc++-v3/testsuite/23_containers/array/creation/115522.cc b/libstdc++-v3/testsuite/23_containers/array/creation/115522.cc new file mode 100644 index 00000000000..37073e002bd --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/array/creation/115522.cc @@ -0,0 +1,33 @@ +// { dg-do compile { target c++20 } } + +// PR libstdc++/115522 std::to_array no longer works for struct which is +// trivial but not default constructible + +#include <array> + +void +test_deleted_ctor() +{ + struct S + { + S() = delete; + S(int) { } + }; + + S arr[1] = {{1}}; + auto arr1 = std::to_array(arr); + auto arr2 = std::to_array(std::move(arr)); +} + +void +test_deleted_assignment() +{ + struct S + { + void operator=(const S&) = delete; + }; + + S arr[1] = {}; + auto a1 = std::to_array(arr); + auto a2 = std::to_array(std::move(arr)); +}