diff options
author | Jonathan Wakely <jwakely@redhat.com> | 2024-06-18 13:27:02 +0100 |
---|---|---|
committer | Jonathan Wakely <jwakely@redhat.com> | 2024-07-12 11:21:58 +0100 |
commit | 08463348c5cce84dc3c64ac4fbb20e2795ee104f (patch) | |
tree | 19ae3fc59ee138394e68395c0e9d42f0eebfe689 | |
parent | 1b22831d3c74a1b3e72dab840e2818e495ecd567 (diff) | |
download | gcc-08463348c5cce84dc3c64ac4fbb20e2795ee104f.zip gcc-08463348c5cce84dc3c64ac4fbb20e2795ee104f.tar.gz gcc-08463348c5cce84dc3c64ac4fbb20e2795ee104f.tar.bz2 |
libstdc++: Fix std::to_array for trivial-ish types [PR115522]
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.
(cherry picked from commit 510ce5eed69ee1bea9c2c696fe3b2301e16d1486)
-rw-r--r-- | libstdc++-v3/include/std/array | 8 | ||||
-rw-r--r-- | libstdc++-v3/testsuite/23_containers/array/creation/115522.cc | 33 |
2 files changed, 39 insertions, 2 deletions
diff --git a/libstdc++-v3/include/std/array b/libstdc++-v3/include/std/array index edcac89..dd9b4a0 100644 --- a/libstdc++-v3/include/std/array +++ b/libstdc++-v3/include/std/array @@ -426,7 +426,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) @@ -455,7 +457,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 0000000..37073e0 --- /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)); +} |