[libcxx-commits] [libcxx] [libcxx] makes `pair` conditionally trivially copyable for C++20 (PR #84811)

Christopher Di Bella via libcxx-commits libcxx-commits at lists.llvm.org
Mon Mar 11 14:23:24 PDT 2024


https://github.com/cjdb updated https://github.com/llvm/llvm-project/pull/84811

>From dd4566d652c0b4b9c6145a2b54592fbb45b0378f Mon Sep 17 00:00:00 2001
From: Christopher Di Bella <cjdb.ns at gmail.com>
Date: Mon, 11 Mar 2024 18:01:24 +0000
Subject: [PATCH 1/2] [libcxx] makes `pair` conditionally trivially copyable
 for C++20

`pair` can have trivial copy and move assignment operators
when both its members have trivial copy and move operators,
which opens `pair` up to being trivially copyable. This is
the first of three possible commits to bring users a more
robust implementation.

It's currently unclear how to implement this without using a
_requires-clause_, so the feature is restricted to C++20 for
now. There has also been some interest in moving this out of
the unstable ABI mode. Both of these changes are intended to
arrive in future pull requests, should their feasibility pan
out.
---
 libcxx/include/__config                       |  3 +++
 libcxx/include/__utility/pair.h               | 19 +++++++++++++++++++
 .../pairs/pairs.pair/assign_pair.pass.cpp     | 10 ++++++++++
 .../pairs.pair/assign_pair_cxx03.pass.cpp     |  2 ++
 .../pairs/pairs.pair/assign_rv_pair.pass.cpp  | 11 +++++++++++
 5 files changed, 45 insertions(+)

diff --git a/libcxx/include/__config b/libcxx/include/__config
index 11e13e0c24986a..a8720cd76ca03d 100644
--- a/libcxx/include/__config
+++ b/libcxx/include/__config
@@ -180,6 +180,9 @@
 // requires code not to make these assumptions.
 #    define _LIBCPP_ABI_USE_WRAP_ITER_IN_STD_ARRAY
 #    define _LIBCPP_ABI_USE_WRAP_ITER_IN_STD_STRING_VIEW
+// Allows std::pair's copy assignment and move assignment operators to be trivial
+// when both its element types' respective assignment operators are trivial.
+#    define _LIBCPP_ABI_PAIR_TRIVIALLY_COPYABLE
 #  elif _LIBCPP_ABI_VERSION == 1
 #    if !(defined(_LIBCPP_OBJECT_FORMAT_COFF) || defined(_LIBCPP_OBJECT_FORMAT_XCOFF))
 // Enable compiling copies of now inline methods into the dylib to support
diff --git a/libcxx/include/__utility/pair.h b/libcxx/include/__utility/pair.h
index b488a9829c3849..7cded19bcf694a 100644
--- a/libcxx/include/__utility/pair.h
+++ b/libcxx/include/__utility/pair.h
@@ -26,20 +26,24 @@
 #include <__type_traits/common_type.h>
 #include <__type_traits/conditional.h>
 #include <__type_traits/decay.h>
+#include <__type_traits/enable_if.h>
 #include <__type_traits/integral_constant.h>
 #include <__type_traits/is_assignable.h>
 #include <__type_traits/is_constructible.h>
 #include <__type_traits/is_convertible.h>
 #include <__type_traits/is_copy_assignable.h>
+#include <__type_traits/is_trivially_copy_assignable.h>
 #include <__type_traits/is_default_constructible.h>
 #include <__type_traits/is_implicitly_default_constructible.h>
 #include <__type_traits/is_move_assignable.h>
+#include <__type_traits/is_trivially_move_assignable.h>
 #include <__type_traits/is_nothrow_assignable.h>
 #include <__type_traits/is_nothrow_constructible.h>
 #include <__type_traits/is_nothrow_copy_assignable.h>
 #include <__type_traits/is_nothrow_copy_constructible.h>
 #include <__type_traits/is_nothrow_default_constructible.h>
 #include <__type_traits/is_nothrow_move_assignable.h>
+#include <__type_traits/is_object.h>
 #include <__type_traits/is_same.h>
 #include <__type_traits/is_swappable.h>
 #include <__type_traits/nat.h>
@@ -67,6 +71,14 @@ struct __non_trivially_copyable_base {
   __non_trivially_copyable_base(__non_trivially_copyable_base const&) _NOEXCEPT {}
 };
 
+#if _LIBCPP_STD_VER >= 20
+template<class _Tp>
+concept __trivially_copy_assignable_object = is_trivially_copy_assignable_v<_Tp> && is_object_v<_Tp>;
+
+template<class _Tp>
+concept __trivially_move_assignable_object = is_trivially_move_assignable_v<_Tp> && is_object_v<_Tp>;
+#endif
+
 #if _LIBCPP_STD_VER >= 23
 template <class _Tp>
 struct __is_specialization_of_subrange : false_type {};
@@ -236,6 +248,13 @@ struct _LIBCPP_TEMPLATE_VIS pair
              typename __make_tuple_indices<sizeof...(_Args1)>::type(),
              typename __make_tuple_indices<sizeof...(_Args2) >::type()) {}
 
+#  if _LIBCPP_STD_VER >= 20 && defined(_LIBCPP_ABI_PAIR_TRIVIALLY_COPYABLE)
+  _LIBCPP_HIDE_FROM_ABI pair& operator=(pair const& __p)
+      requires __trivially_copy_assignable_object<first_type> && __trivially_copy_assignable_object<second_type> = default;
+  _LIBCPP_HIDE_FROM_ABI pair& operator=(pair&& __p)
+      requires __trivially_move_assignable_object<first_type> && __trivially_move_assignable_object<second_type> = default;
+#endif
+
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 pair&
   operator=(__conditional_t< is_copy_assignable<first_type>::value && is_copy_assignable<second_type>::value,
                              pair,
diff --git a/libcxx/test/std/utilities/utility/pairs/pairs.pair/assign_pair.pass.cpp b/libcxx/test/std/utilities/utility/pairs/pairs.pair/assign_pair.pass.cpp
index 253bd1b85d03ec..f45903f2a263a7 100644
--- a/libcxx/test/std/utilities/utility/pairs/pairs.pair/assign_pair.pass.cpp
+++ b/libcxx/test/std/utilities/utility/pairs/pairs.pair/assign_pair.pass.cpp
@@ -88,6 +88,16 @@ TEST_CONSTEXPR_CXX20 bool test() {
     assert(&p.second == &inc_obj);
   }
 
+#if TEST_STD_VER >= 20 && defined(_LIBCPP_ABI_PAIR_TRIVIALLY_COPYABLE)
+  static_assert(std::is_trivially_copy_assignable<std::pair<int, int>>::value, "");
+#else
+  static_assert(!std::is_trivially_copy_assignable<std::pair<int, int>>::value, "");
+#endif
+
+  static_assert(!std::is_trivially_copy_assignable<std::pair<CountAssign, int>>::value, "");
+  static_assert(!std::is_trivially_copy_assignable<std::pair<int, CountAssign>>::value, "");
+  static_assert(!std::is_trivially_copy_assignable<std::pair<CountAssign, CountAssign>>::value, "");
+
   return true;
 }
 
diff --git a/libcxx/test/std/utilities/utility/pairs/pairs.pair/assign_pair_cxx03.pass.cpp b/libcxx/test/std/utilities/utility/pairs/pairs.pair/assign_pair_cxx03.pass.cpp
index 2444131b02a0cf..baa472e1cf4525 100644
--- a/libcxx/test/std/utilities/utility/pairs/pairs.pair/assign_pair_cxx03.pass.cpp
+++ b/libcxx/test/std/utilities/utility/pairs/pairs.pair/assign_pair_cxx03.pass.cpp
@@ -62,6 +62,8 @@ int main(int, char**)
       assert(p.second == 'x');
     }
 
+    static_assert(!std::is_trivially_copy_assignable<std::pair<int, int>>::value);
+
   return 0;
 }
 
diff --git a/libcxx/test/std/utilities/utility/pairs/pairs.pair/assign_rv_pair.pass.cpp b/libcxx/test/std/utilities/utility/pairs/pairs.pair/assign_rv_pair.pass.cpp
index 8e5d9c39ae8868..a4c178db25492a 100644
--- a/libcxx/test/std/utilities/utility/pairs/pairs.pair/assign_rv_pair.pass.cpp
+++ b/libcxx/test/std/utilities/utility/pairs/pairs.pair/assign_rv_pair.pass.cpp
@@ -130,6 +130,17 @@ TEST_CONSTEXPR_CXX20 bool test() {
     static_assert(!std::is_move_assignable<P5>::value, "");
     static_assert(!std::is_move_assignable<P6>::value, "");
   }
+
+#if TEST_STD_VER >= 20 && defined(_LIBCPP_ABI_PAIR_TRIVIALLY_COPYABLE)
+  static_assert(std::is_trivially_move_assignable<std::pair<int, int>>::value, "");
+#else
+  static_assert(!std::is_trivially_move_assignable<std::pair<int, int>>::value, "");
+#endif
+
+  static_assert(!std::is_trivially_move_assignable<std::pair<CountAssign, int>>::value, "");
+  static_assert(!std::is_trivially_move_assignable<std::pair<int, CountAssign>>::value, "");
+  static_assert(!std::is_trivially_move_assignable<std::pair<CountAssign, CountAssign>>::value, "");
+
   return true;
 }
 

>From 9916c2e48315d0817b45d25eeef1f2ba2fa7fd5b Mon Sep 17 00:00:00 2001
From: Christopher Di Bella <cjdb at google.com>
Date: Mon, 11 Mar 2024 21:23:00 +0000
Subject: [PATCH 2/2] sorts includes

---
 libcxx/include/__utility/pair.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/libcxx/include/__utility/pair.h b/libcxx/include/__utility/pair.h
index 7cded19bcf694a..a46ab6b7bce672 100644
--- a/libcxx/include/__utility/pair.h
+++ b/libcxx/include/__utility/pair.h
@@ -32,11 +32,9 @@
 #include <__type_traits/is_constructible.h>
 #include <__type_traits/is_convertible.h>
 #include <__type_traits/is_copy_assignable.h>
-#include <__type_traits/is_trivially_copy_assignable.h>
 #include <__type_traits/is_default_constructible.h>
 #include <__type_traits/is_implicitly_default_constructible.h>
 #include <__type_traits/is_move_assignable.h>
-#include <__type_traits/is_trivially_move_assignable.h>
 #include <__type_traits/is_nothrow_assignable.h>
 #include <__type_traits/is_nothrow_constructible.h>
 #include <__type_traits/is_nothrow_copy_assignable.h>
@@ -46,6 +44,8 @@
 #include <__type_traits/is_object.h>
 #include <__type_traits/is_same.h>
 #include <__type_traits/is_swappable.h>
+#include <__type_traits/is_trivially_copy_assignable.h>
+#include <__type_traits/is_trivially_move_assignable.h>
 #include <__type_traits/nat.h>
 #include <__type_traits/remove_cvref.h>
 #include <__type_traits/unwrap_ref.h>



More information about the libcxx-commits mailing list