[libcxx-commits] [libcxx] [libcxx] makes `expected` trivially assignable when both members are … (PR #74768)
Christopher Di Bella via libcxx-commits
libcxx-commits at lists.llvm.org
Thu Dec 7 13:48:29 PST 2023
https://github.com/cjdb created https://github.com/llvm/llvm-project/pull/74768
…trivially assignable
>From d9ffc415f43e2a05b6d55483709b882adb34ccc6 Mon Sep 17 00:00:00 2001
From: Christopher Di Bella <cjdb at google.com>
Date: Thu, 7 Dec 2023 21:46:14 +0000
Subject: [PATCH] [libcxx] makes `expected` trivially assignable when both
members are trivially assignable
---
libcxx/include/__expected/expected.h | 25 +++++++++++++
.../assign/assign.copy.pass.cpp | 37 ++++++++++++++++++-
.../assign/assign.move.pass.cpp | 33 ++++++++++++++++-
3 files changed, 93 insertions(+), 2 deletions(-)
diff --git a/libcxx/include/__expected/expected.h b/libcxx/include/__expected/expected.h
index bf16c8f720d268..128369fc1b0a1e 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 03fe888b0a5e7f..12ca07a3c1f9af 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 8c419afd10729f..b08023b9c95efe 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).
{
More information about the libcxx-commits
mailing list