aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJonathan Wakely <jwakely@redhat.com>2024-06-18 13:27:02 +0100
committerJonathan Wakely <jwakely@redhat.com>2024-07-12 11:21:58 +0100
commit08463348c5cce84dc3c64ac4fbb20e2795ee104f (patch)
tree19ae3fc59ee138394e68395c0e9d42f0eebfe689
parent1b22831d3c74a1b3e72dab840e2818e495ecd567 (diff)
downloadgcc-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/array8
-rw-r--r--libstdc++-v3/testsuite/23_containers/array/creation/115522.cc33
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));
+}