https://gcc.gnu.org/g:510ce5eed69ee1bea9c2c696fe3b2301e16d1486

commit r15-1533-g510ce5eed69ee1bea9c2c696fe3b2301e16d1486
Author: Jonathan Wakely <jwak...@redhat.com>
Date:   Tue Jun 18 13:27:02 2024 +0100

    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.

Diff:
---
 libstdc++-v3/include/std/array                     |  8 ++++--
 .../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 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));
+}

Reply via email to