[libcxx-commits] [libcxx] [libcxx] makes `expected` trivially assignable when both members are … (PR #74768)

via libcxx-commits libcxx-commits at lists.llvm.org
Thu Dec 7 13:48:47 PST 2023


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-libcxx

Author: Christopher Di Bella (cjdb)

<details>
<summary>Changes</summary>

…trivially assignable

---
Full diff: https://github.com/llvm/llvm-project/pull/74768.diff


3 Files Affected:

- (modified) libcxx/include/__expected/expected.h (+25) 
- (modified) libcxx/test/std/utilities/expected/expected.expected/assign/assign.copy.pass.cpp (+36-1) 
- (modified) libcxx/test/std/utilities/expected/expected.expected/assign/assign.move.pass.cpp (+32-1) 


``````````diff
diff --git a/libcxx/include/__expected/expected.h b/libcxx/include/__expected/expected.h
index bf16c8f720d26..128369fc1b0a1 100644
--- a/libcxx/include/__expected/expected.h
+++ b/libcxx/include/__expected/expected.h
@@ -38,8 +38,10 @@
 #include <__type_traits/is_reference.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_copy_constructible.h>
 #include <__type_traits/is_trivially_destructible.h>
+#include <__type_traits/is_trivially_move_assignable.h>
 #include <__type_traits/is_trivially_move_constructible.h>
 #include <__type_traits/is_void.h>
 #include <__type_traits/lazy.h>
@@ -282,10 +284,27 @@ class expected {
     }
   }
 
+  static constexpr bool __is_trivially_move_assignable =
+      is_trivially_move_constructible_v<_Tp> &&
+      is_trivially_move_assignable_v<_Tp> &&
+      is_trivially_move_constructible_v<_Err> &&
+      is_trivially_move_assignable_v<_Err>;
+
+  static constexpr bool __is_trivially_copy_assignable =
+      __is_trivially_move_assignable &&
+      is_trivially_copy_constructible_v<_Tp> &&
+      is_trivially_copy_assignable_v<_Tp> &&
+      is_trivially_copy_constructible_v<_Err> &&
+      is_trivially_copy_assignable_v<_Err>;
+
 public:
   // [expected.object.assign], assignment
   _LIBCPP_HIDE_FROM_ABI constexpr expected& operator=(const expected&) = delete;
 
+  _LIBCPP_HIDE_FROM_ABI constexpr expected& operator=(const expected& __rhs)
+    requires __is_trivially_copy_assignable
+  = default;
+
   _LIBCPP_HIDE_FROM_ABI constexpr expected& operator=(const expected& __rhs)
     noexcept(is_nothrow_copy_assignable_v<_Tp> &&
              is_nothrow_copy_constructible_v<_Tp> &&
@@ -295,6 +314,7 @@ class expected {
              is_copy_constructible_v<_Tp> &&
              is_copy_assignable_v<_Err> &&
              is_copy_constructible_v<_Err> &&
+             !__is_trivially_copy_assignable &&
              (is_nothrow_move_constructible_v<_Tp> ||
               is_nothrow_move_constructible_v<_Err>))
   {
@@ -312,6 +332,10 @@ class expected {
     return *this;
   }
 
+  _LIBCPP_HIDE_FROM_ABI constexpr expected& operator=(expected&& __rhs)
+    requires __is_trivially_move_assignable
+  = default;
+
   _LIBCPP_HIDE_FROM_ABI constexpr expected& operator=(expected&& __rhs)
     noexcept(is_nothrow_move_assignable_v<_Tp> &&
              is_nothrow_move_constructible_v<_Tp> &&
@@ -321,6 +345,7 @@ class expected {
              is_move_assignable_v<_Tp> &&
              is_move_constructible_v<_Err> &&
              is_move_assignable_v<_Err> &&
+             !__is_trivially_move_assignable &&
              (is_nothrow_move_constructible_v<_Tp> ||
               is_nothrow_move_constructible_v<_Err>))
   {
diff --git a/libcxx/test/std/utilities/expected/expected.expected/assign/assign.copy.pass.cpp b/libcxx/test/std/utilities/expected/expected.expected/assign/assign.copy.pass.cpp
index 03fe888b0a5e7..12ca07a3c1f9a 100644
--- a/libcxx/test/std/utilities/expected/expected.expected/assign/assign.copy.pass.cpp
+++ b/libcxx/test/std/utilities/expected/expected.expected/assign/assign.copy.pass.cpp
@@ -47,6 +47,22 @@ struct NotCopyAssignable {
   NotCopyAssignable& operator=(const NotCopyAssignable&) = delete;
 };
 
+struct NotTriviallyCopyConstructible {
+  NotTriviallyCopyConstructible(const NotTriviallyCopyConstructible&);
+  NotTriviallyCopyConstructible(NotTriviallyCopyConstructible&&) = default;
+
+  NotTriviallyCopyConstructible& operator=(const NotTriviallyCopyConstructible&) = default;
+  NotTriviallyCopyConstructible& operator=(NotTriviallyCopyConstructible&&)      = default;
+};
+
+struct NotTriviallyCopyAssignable {
+  NotTriviallyCopyAssignable(const NotTriviallyCopyAssignable&) = default;
+  NotTriviallyCopyAssignable(NotTriviallyCopyAssignable&&)      = default;
+
+  NotTriviallyCopyAssignable& operator=(const NotTriviallyCopyAssignable&);
+  NotTriviallyCopyAssignable& operator=(NotTriviallyCopyAssignable&&) = default;
+};
+
 struct MoveMayThrow {
   MoveMayThrow(MoveMayThrow const&)            = default;
   MoveMayThrow& operator=(const MoveMayThrow&) = default;
@@ -55,7 +71,7 @@ struct MoveMayThrow {
 };
 
 // Test constraints
-static_assert(std::is_copy_assignable_v<std::expected<int, int>>);
+static_assert(std::is_trivially_copy_assignable_v<std::expected<int, int>>);
 
 // !is_copy_assignable_v<T>
 static_assert(!std::is_copy_assignable_v<std::expected<NotCopyAssignable, int>>);
@@ -78,6 +94,25 @@ static_assert(std::is_copy_assignable_v<std::expected<int, MoveMayThrow>>);
 // !is_nothrow_move_constructible_v<T> && !is_nothrow_move_constructible_v<E>
 static_assert(!std::is_copy_assignable_v<std::expected<MoveMayThrow, MoveMayThrow>>);
 
+// !is_trivially_copy_constructible
+static_assert(std::is_copy_assignable_v<std::expected<NotTriviallyCopyConstructible, int>>);
+static_assert(!std::is_trivially_copy_assignable_v<std::expected<NotTriviallyCopyConstructible, int>>);
+static_assert(!std::is_trivially_copy_assignable_v<std::expected<int, NotTriviallyCopyConstructible>>);
+static_assert(
+    !std::is_trivially_copy_assignable_v<std::expected<NotTriviallyCopyConstructible, NotTriviallyCopyConstructible>>);
+
+// !is_trivially_copy_assignable
+static_assert(std::is_copy_assignable_v<std::expected<NotTriviallyCopyAssignable, int>>);
+static_assert(!std::is_trivially_copy_assignable_v<std::expected<NotTriviallyCopyAssignable, int>>);
+static_assert(!std::is_trivially_copy_assignable_v<std::expected<int, NotTriviallyCopyAssignable>>);
+static_assert(
+    !std::is_trivially_copy_assignable_v<std::expected<NotTriviallyCopyAssignable, NotTriviallyCopyAssignable>>);
+
+static_assert(
+    !std::is_trivially_copy_assignable_v<std::expected<NotTriviallyCopyConstructible, NotTriviallyCopyAssignable>>);
+static_assert(
+    !std::is_trivially_copy_assignable_v<std::expected<NotTriviallyCopyAssignable, NotTriviallyCopyConstructible>>);
+
 constexpr bool test() {
   // If this->has_value() && rhs.has_value() is true, equivalent to val = *rhs.
   {
diff --git a/libcxx/test/std/utilities/expected/expected.expected/assign/assign.move.pass.cpp b/libcxx/test/std/utilities/expected/expected.expected/assign/assign.move.pass.cpp
index 8c419afd10729..b08023b9c95ef 100644
--- a/libcxx/test/std/utilities/expected/expected.expected/assign/assign.move.pass.cpp
+++ b/libcxx/test/std/utilities/expected/expected.expected/assign/assign.move.pass.cpp
@@ -50,13 +50,29 @@ struct NotMoveAssignable {
   NotMoveAssignable& operator=(NotMoveAssignable&&) = delete;
 };
 
+struct NotTriviallyMoveConstructible {
+  NotTriviallyMoveConstructible(const NotTriviallyMoveConstructible&) = default;
+  NotTriviallyMoveConstructible(NotTriviallyMoveConstructible&&);
+
+  NotTriviallyMoveConstructible& operator=(const NotTriviallyMoveConstructible&) = default;
+  NotTriviallyMoveConstructible& operator=(NotTriviallyMoveConstructible&&)      = default;
+};
+
+struct NotTriviallyMoveAssignable {
+  NotTriviallyMoveAssignable(const NotTriviallyMoveAssignable&) = default;
+  NotTriviallyMoveAssignable(NotTriviallyMoveAssignable&&)      = default;
+
+  NotTriviallyMoveAssignable& operator=(const NotTriviallyMoveAssignable&) = default;
+  NotTriviallyMoveAssignable& operator=(NotTriviallyMoveAssignable&&);
+};
+
 struct MoveCtorMayThrow {
   MoveCtorMayThrow(MoveCtorMayThrow&&) noexcept(false) {}
   MoveCtorMayThrow& operator=(MoveCtorMayThrow&&) noexcept = default;
 };
 
 // Test constraints
-static_assert(std::is_move_assignable_v<std::expected<int, int>>);
+static_assert(std::is_trivially_move_assignable_v<std::expected<int, int>>);
 
 // !is_move_assignable_v<T>
 static_assert(!std::is_move_assignable_v<std::expected<NotMoveAssignable, int>>);
@@ -99,6 +115,21 @@ static_assert(!std::is_nothrow_move_assignable_v<std::expected<int, MoveAssignMa
 // !is_nothrow_move_constructible_v<E>
 static_assert(!std::is_nothrow_move_assignable_v<std::expected<int, MoveCtorMayThrow>>);
 
+// !is_trivially_move_constructible
+static_assert(std::is_move_assignable_v<std::expected<NotTriviallyMoveConstructible, int>>);
+static_assert(!std::is_trivially_move_assignable_v<std::expected<NotTriviallyMoveConstructible, int>>);
+static_assert(!std::is_trivially_move_assignable_v<std::expected<int, NotTriviallyMoveConstructible>>);
+
+// !is_trivially_move_assignable
+static_assert(std::is_move_assignable_v<std::expected<NotTriviallyMoveAssignable, int>>);
+static_assert(!std::is_trivially_move_assignable_v<std::expected<NotTriviallyMoveAssignable, int>>);
+static_assert(!std::is_trivially_move_assignable_v<std::expected<int, NotTriviallyMoveAssignable>>);
+
+static_assert(
+    !std::is_trivially_move_assignable_v<std::expected<NotTriviallyMoveConstructible, NotTriviallyMoveAssignable>>);
+static_assert(
+    !std::is_trivially_move_assignable_v<std::expected<NotTriviallyMoveAssignable, NotTriviallyMoveConstructible>>);
+
 constexpr bool test() {
   // If this->has_value() && rhs.has_value() is true, equivalent to val = std::move(*rhs).
   {

``````````

</details>


https://github.com/llvm/llvm-project/pull/74768


More information about the libcxx-commits mailing list