[libcxx-commits] [libcxx] [libc++][ABI BREAK] Make std::pair trivially copyable if its members are (PR #89652)

Nikolas Klauser via libcxx-commits libcxx-commits at lists.llvm.org
Tue Apr 23 00:05:06 PDT 2024


https://github.com/philnik777 updated https://github.com/llvm/llvm-project/pull/89652

>From 3c390aae043e9332c07e2e9a2b575e39ebc57225 Mon Sep 17 00:00:00 2001
From: Nikolas Klauser <nikolasklauser at berlin.de>
Date: Mon, 22 Apr 2024 20:58:34 +0200
Subject: [PATCH] [libc++][ABI BREAK] Make std::pair trivially copyable if its
 members are

---
 libcxx/include/__type_traits/datasizeof.h     |  1 +
 libcxx/include/__utility/pair.h               | 41 ++++++++++++++++---
 .../trivially_copyable.compile.pass.cpp       | 32 +++++++++++++++
 3 files changed, 68 insertions(+), 6 deletions(-)
 create mode 100644 libcxx/test/libcxx/utilities/utility/pairs/pairs.pair/trivially_copyable.compile.pass.cpp

diff --git a/libcxx/include/__type_traits/datasizeof.h b/libcxx/include/__type_traits/datasizeof.h
index 3a8b1516010731..197403ea0429dd 100644
--- a/libcxx/include/__type_traits/datasizeof.h
+++ b/libcxx/include/__type_traits/datasizeof.h
@@ -55,6 +55,7 @@ struct __libcpp_datasizeof {
   // the use as an extension.
   _LIBCPP_DIAGNOSTIC_PUSH
   _LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Winvalid-offsetof")
+  _LIBCPP_GCC_DIAGNOSTIC_IGNORED("-Winvalid-offsetof")
   static const size_t value = offsetof(_FirstPaddingByte<>, __first_padding_byte_);
   _LIBCPP_DIAGNOSTIC_POP
 #endif   // __has_extension(datasizeof)
diff --git a/libcxx/include/__utility/pair.h b/libcxx/include/__utility/pair.h
index e05250ba05717f..2a26dd3b3851b1 100644
--- a/libcxx/include/__utility/pair.h
+++ b/libcxx/include/__utility/pair.h
@@ -32,6 +32,7 @@
 #include <__type_traits/is_implicitly_default_constructible.h>
 #include <__type_traits/is_nothrow_assignable.h>
 #include <__type_traits/is_nothrow_constructible.h>
+#include <__type_traits/is_reference.h>
 #include <__type_traits/is_same.h>
 #include <__type_traits/is_swappable.h>
 #include <__type_traits/nat.h>
@@ -141,6 +142,31 @@ struct _LIBCPP_TEMPLATE_VIS pair
       _NOEXCEPT_(is_nothrow_copy_constructible<first_type>::value&& is_nothrow_copy_constructible<second_type>::value)
       : first(__t1), second(__t2) {}
 
+  // Make pair trivially copyable if we have a way to do it
+  static const bool __enable_defaulted_assignment_operators =
+      !is_reference<first_type>::value && !is_reference<second_type>::value;
+#  if _LIBCPP_STD_VER >= 20
+  static const bool __has_defaulted_members = __enable_defaulted_assignment_operators;
+
+  _LIBCPP_HIDE_FROM_ABI constexpr pair& operator=(const pair&)
+    requires __enable_defaulted_assignment_operators
+  = default;
+
+  _LIBCPP_HIDE_FROM_ABI constexpr pair& operator=(pair&&)
+    requires __enable_defaulted_assignment_operators
+  = default;
+#  elif __has_attribute(__enable_if__)
+  static const bool __has_defaulted_members = __enable_defaulted_assignment_operators;
+
+  _LIBCPP_HIDE_FROM_ABI pair& operator=(const pair&)
+      __attribute__((__enable_if__(__enable_defaulted_assignment_operators, ""))) = default;
+
+  _LIBCPP_HIDE_FROM_ABI pair& operator=(pair&&)
+      __attribute__((__enable_if__(__enable_defaulted_assignment_operators, ""))) = default;
+#  else
+  static const bool __has_defaulted_members = false;
+#  endif                    // __has_attribute(__enable_if__)
+
   template <
 #  if _LIBCPP_STD_VER >= 23 // http://wg21.link/P1951
       class _U1 = _T1,
@@ -221,18 +247,21 @@ struct _LIBCPP_TEMPLATE_VIS pair
              typename __make_tuple_indices<sizeof...(_Args2) >::type()) {}
 
   _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,
-                             __nat> const& __p)
+  operator=(__conditional_t<
+            !__has_defaulted_members && is_copy_assignable<first_type>::value && is_copy_assignable<second_type>::value,
+            pair,
+            __nat> const& __p)
       _NOEXCEPT_(is_nothrow_copy_assignable<first_type>::value&& is_nothrow_copy_assignable<second_type>::value) {
     first  = __p.first;
     second = __p.second;
     return *this;
   }
 
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 pair& operator=(
-      __conditional_t< is_move_assignable<first_type>::value && is_move_assignable<second_type>::value, pair, __nat>&&
-          __p)
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 pair&
+  operator=(__conditional_t<
+            !__has_defaulted_members && is_move_assignable<first_type>::value && is_move_assignable<second_type>::value,
+            pair,
+            __nat>&& __p)
       _NOEXCEPT_(is_nothrow_move_assignable<first_type>::value&& is_nothrow_move_assignable<second_type>::value) {
     first  = std::forward<first_type>(__p.first);
     second = std::forward<second_type>(__p.second);
diff --git a/libcxx/test/libcxx/utilities/utility/pairs/pairs.pair/trivially_copyable.compile.pass.cpp b/libcxx/test/libcxx/utilities/utility/pairs/pairs.pair/trivially_copyable.compile.pass.cpp
new file mode 100644
index 00000000000000..fb77d19a4a71da
--- /dev/null
+++ b/libcxx/test/libcxx/utilities/utility/pairs/pairs.pair/trivially_copyable.compile.pass.cpp
@@ -0,0 +1,32 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: c++20 || clang
+
+#include <type_traits>
+#include <utility>
+
+struct trivially_copyable {
+  int arr[4];
+};
+
+static_assert(std::is_trivially_copyable<std::pair<int, int> >::value, "");
+static_assert(std::is_trivially_copyable<std::pair<int, char> >::value, "");
+static_assert(std::is_trivially_copyable<std::pair<char, int> >::value, "");
+static_assert(std::is_trivially_copyable<std::pair<std::pair<char, char>, int> >::value, "");
+static_assert(std::is_trivially_copyable<std::pair<trivially_copyable, int> >::value, "");
+
+static_assert(!std::is_trivially_copyable<std::pair<int&, int> >::value, "");
+static_assert(!std::is_trivially_copyable<std::pair<int, int&> >::value, "");
+static_assert(!std::is_trivially_copyable<std::pair<int&, int&> >::value, "");
+
+static_assert(std::is_trivially_copy_constructible<std::pair<int, int> >::value, "");
+static_assert(std::is_trivially_move_constructible<std::pair<int, int> >::value, "");
+static_assert(std::is_trivially_copy_assignable<std::pair<int, int> >::value, "");
+static_assert(std::is_trivially_move_assignable<std::pair<int, int> >::value, "");
+static_assert(std::is_trivially_destructible<std::pair<int, int> >::value, "");



More information about the libcxx-commits mailing list