[libcxx-commits] [libcxx] [clang-tools-extra] [llvm] [libc++] Implement LWG3940: std::expected<void, E>::value() also needs E to be copy constructible (PR #71819)
via libcxx-commits
libcxx-commits at lists.llvm.org
Wed Jan 3 18:03:50 PST 2024
https://github.com/PragmaTwice updated https://github.com/llvm/llvm-project/pull/71819
>From 3e4b73d2aeac411a83dda5cd63eb0572499db467 Mon Sep 17 00:00:00 2001
From: PragmaTwice <twice at apache.org>
Date: Fri, 10 Nov 2023 00:50:24 +0900
Subject: [PATCH 1/7] [libc++] Implement LWG3940 (std::expected<void,
E>::value() also needs E to be copy constructible)
---
libcxx/docs/Status/Cxx2cIssues.csv | 2 +-
libcxx/include/__expected/expected.h | 3 +++
.../observers/value.lwg3940.compile.fail.cpp | 27 +++++++++++++++++++
.../expected.void/observers/value.pass.cpp | 11 --------
4 files changed, 31 insertions(+), 12 deletions(-)
create mode 100644 libcxx/test/std/utilities/expected/expected.void/observers/value.lwg3940.compile.fail.cpp
diff --git a/libcxx/docs/Status/Cxx2cIssues.csv b/libcxx/docs/Status/Cxx2cIssues.csv
index a928b69ea10c48..099a19d02888f4 100644
--- a/libcxx/docs/Status/Cxx2cIssues.csv
+++ b/libcxx/docs/Status/Cxx2cIssues.csv
@@ -15,7 +15,7 @@
"`3927 <https://wg21.link/LWG3927>`__","Unclear preconditions for ``operator[]`` for sequence containers","Varna June 2023","|Nothing To Do|","",""
"`3935 <https://wg21.link/LWG3935>`__","``template<class X> constexpr complex& operator=(const complex<X>&)`` has no specification","Varna June 2023","|Complete|","3.4",""
"`3938 <https://wg21.link/LWG3938>`__","Cannot use ``std::expected`` monadic ops with move-only ``error_type``","Varna June 2023","|Complete|","18.0",""
-"`3940 <https://wg21.link/LWG3940>`__","``std::expected<void, E>::value()`` also needs ``E`` to be copy constructible","Varna June 2023","","",""
+"`3940 <https://wg21.link/LWG3940>`__","``std::expected<void, E>::value()`` also needs ``E`` to be copy constructible","Varna June 2023","|Complete|","18.0",""
"","","","","",""
"`3343 <https://wg21.link/LWG3343>`__","Ordering of calls to ``unlock()`` and ``notify_all()`` in Effects element of ``notify_all_at_thread_exit()`` should be reversed","Not Yet Adopted","|Complete|","16.0",""
"`3892 <https://wg21.link/LWG3892>`__","Incorrect formatting of nested ranges and tuples","Not Yet Adopted","|Complete|","17.0","|format|"
diff --git a/libcxx/include/__expected/expected.h b/libcxx/include/__expected/expected.h
index bf16c8f720d268..c6441f1651b085 100644
--- a/libcxx/include/__expected/expected.h
+++ b/libcxx/include/__expected/expected.h
@@ -1187,12 +1187,15 @@ class expected<_Tp, _Err> {
}
_LIBCPP_HIDE_FROM_ABI constexpr void value() const& {
+ static_assert(is_copy_constructible_v<_Err>, "error_type has to be copy constructible");
if (!__has_val_) {
std::__throw_bad_expected_access<_Err>(__union_.__unex_);
}
}
_LIBCPP_HIDE_FROM_ABI constexpr void value() && {
+ static_assert(is_copy_constructible_v<_Err> && is_move_constructible_v<_Err>,
+ "error_type has to be both copy constructible and move constructible");
if (!__has_val_) {
std::__throw_bad_expected_access<_Err>(std::move(__union_.__unex_));
}
diff --git a/libcxx/test/std/utilities/expected/expected.void/observers/value.lwg3940.compile.fail.cpp b/libcxx/test/std/utilities/expected/expected.void/observers/value.lwg3940.compile.fail.cpp
new file mode 100644
index 00000000000000..37c06e629e9443
--- /dev/null
+++ b/libcxx/test/std/utilities/expected/expected.void/observers/value.lwg3940.compile.fail.cpp
@@ -0,0 +1,27 @@
+//===----------------------------------------------------------------------===//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// constexpr void value() &&;
+// Mandates: is_copy_constructible_v<E> is true and is_move_constructible_v<E> is true.
+
+#include <expected>
+
+#include "MoveOnly.h"
+
+void test() {
+ // MoveOnly
+ std::expected<void, MoveOnly> e(std::unexpect, 5);
+
+ // COMPILE FAIL: MoveOnly is not copy constructible
+ std::move(e).value();
+}
+
+int main(int, char**) {
+ test();
+}
diff --git a/libcxx/test/std/utilities/expected/expected.void/observers/value.pass.cpp b/libcxx/test/std/utilities/expected/expected.void/observers/value.pass.cpp
index 0f02db19c7b75e..a24d67c57e19b5 100644
--- a/libcxx/test/std/utilities/expected/expected.void/observers/value.pass.cpp
+++ b/libcxx/test/std/utilities/expected/expected.void/observers/value.pass.cpp
@@ -65,17 +65,6 @@ void testException() {
}
}
- // MoveOnly
- {
- std::expected<void, MoveOnly> e(std::unexpect, 5);
- try {
- std::move(e).value();
- assert(false);
- } catch (const std::bad_expected_access<MoveOnly>& ex) {
- assert(ex.error() == 5);
- }
- }
-
#endif // TEST_HAS_NO_EXCEPTIONS
}
>From 2d1c43fa98b3a97f31509e98c3abdd7fe8f62626 Mon Sep 17 00:00:00 2001
From: PragmaTwice <twice at apache.org>
Date: Fri, 10 Nov 2023 19:29:30 +0900
Subject: [PATCH 2/7] [libcxx] format test
---
.../expected.void/observers/value.lwg3940.compile.fail.cpp | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/libcxx/test/std/utilities/expected/expected.void/observers/value.lwg3940.compile.fail.cpp b/libcxx/test/std/utilities/expected/expected.void/observers/value.lwg3940.compile.fail.cpp
index 37c06e629e9443..0f43a45b4eaaa1 100644
--- a/libcxx/test/std/utilities/expected/expected.void/observers/value.lwg3940.compile.fail.cpp
+++ b/libcxx/test/std/utilities/expected/expected.void/observers/value.lwg3940.compile.fail.cpp
@@ -22,6 +22,4 @@ void test() {
std::move(e).value();
}
-int main(int, char**) {
- test();
-}
+int main(int, char**) { test(); }
>From 0767b57320aa3433a65761132d57414fe6ffd1ea Mon Sep 17 00:00:00 2001
From: PragmaTwice <twice at apache.org>
Date: Wed, 15 Nov 2023 23:49:52 +0900
Subject: [PATCH 3/7] use .verify.cpp instead of .compile.fail.cpp
---
...e.lwg3940.compile.fail.cpp => value.lwg3940.verify.cpp} | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
rename libcxx/test/std/utilities/expected/expected.void/observers/{value.lwg3940.compile.fail.cpp => value.lwg3940.verify.cpp} (62%)
diff --git a/libcxx/test/std/utilities/expected/expected.void/observers/value.lwg3940.compile.fail.cpp b/libcxx/test/std/utilities/expected/expected.void/observers/value.lwg3940.verify.cpp
similarity index 62%
rename from libcxx/test/std/utilities/expected/expected.void/observers/value.lwg3940.compile.fail.cpp
rename to libcxx/test/std/utilities/expected/expected.void/observers/value.lwg3940.verify.cpp
index 0f43a45b4eaaa1..da6aeb10a3e40d 100644
--- a/libcxx/test/std/utilities/expected/expected.void/observers/value.lwg3940.compile.fail.cpp
+++ b/libcxx/test/std/utilities/expected/expected.void/observers/value.lwg3940.verify.cpp
@@ -6,6 +6,7 @@
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+// ADDITIONAL_COMPILE_FLAGS: -Xclang -verify-ignore-unexpected=error
// constexpr void value() &&;
// Mandates: is_copy_constructible_v<E> is true and is_move_constructible_v<E> is true.
@@ -15,11 +16,11 @@
#include "MoveOnly.h"
void test() {
- // MoveOnly
+ // MoveOnly type as error_type
std::expected<void, MoveOnly> e(std::unexpect, 5);
- // COMPILE FAIL: MoveOnly is not copy constructible
- std::move(e).value();
+ std::move(e).value(); // expected-note{{in instantiation of member function 'std::expected<void, MoveOnly>::value' requested here}}
+ // expected-error-re@*:* {{static assertion failed due to requirement 'is_copy_constructible_v<MoveOnly>': error_type has to be both copy constructible and move constructible}}
}
int main(int, char**) { test(); }
>From a5ea3056ec348ca0b576cda84fa99796c0b2b60b Mon Sep 17 00:00:00 2001
From: PragmaTwice <twice at apache.org>
Date: Wed, 15 Nov 2023 23:54:51 +0900
Subject: [PATCH 4/7] format code
---
.../expected/expected.void/observers/value.lwg3940.verify.cpp | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/libcxx/test/std/utilities/expected/expected.void/observers/value.lwg3940.verify.cpp b/libcxx/test/std/utilities/expected/expected.void/observers/value.lwg3940.verify.cpp
index da6aeb10a3e40d..c2516119089f9e 100644
--- a/libcxx/test/std/utilities/expected/expected.void/observers/value.lwg3940.verify.cpp
+++ b/libcxx/test/std/utilities/expected/expected.void/observers/value.lwg3940.verify.cpp
@@ -19,7 +19,8 @@ void test() {
// MoveOnly type as error_type
std::expected<void, MoveOnly> e(std::unexpect, 5);
- std::move(e).value(); // expected-note{{in instantiation of member function 'std::expected<void, MoveOnly>::value' requested here}}
+ std::move(e)
+ .value(); // expected-note{{in instantiation of member function 'std::expected<void, MoveOnly>::value' requested here}}
// expected-error-re@*:* {{static assertion failed due to requirement 'is_copy_constructible_v<MoveOnly>': error_type has to be both copy constructible and move constructible}}
}
>From cc857072825b73c34f7cc7c01ff860a7b1dd7cd0 Mon Sep 17 00:00:00 2001
From: PragmaTwice <twice at apache.org>
Date: Thu, 16 Nov 2023 21:52:55 +0900
Subject: [PATCH 5/7] rename & clean up
---
.../expected/expected.void}/value.lwg3940.verify.cpp | 7 ++-----
1 file changed, 2 insertions(+), 5 deletions(-)
rename libcxx/test/{std/utilities/expected/expected.void/observers => libcxx/utilities/expected/expected.void}/value.lwg3940.verify.cpp (63%)
diff --git a/libcxx/test/std/utilities/expected/expected.void/observers/value.lwg3940.verify.cpp b/libcxx/test/libcxx/utilities/expected/expected.void/value.lwg3940.verify.cpp
similarity index 63%
rename from libcxx/test/std/utilities/expected/expected.void/observers/value.lwg3940.verify.cpp
rename to libcxx/test/libcxx/utilities/expected/expected.void/value.lwg3940.verify.cpp
index c2516119089f9e..33bac465a5eda2 100644
--- a/libcxx/test/std/utilities/expected/expected.void/observers/value.lwg3940.verify.cpp
+++ b/libcxx/test/libcxx/utilities/expected/expected.void/value.lwg3940.verify.cpp
@@ -6,7 +6,6 @@
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
-// ADDITIONAL_COMPILE_FLAGS: -Xclang -verify-ignore-unexpected=error
// constexpr void value() &&;
// Mandates: is_copy_constructible_v<E> is true and is_move_constructible_v<E> is true.
@@ -20,8 +19,6 @@ void test() {
std::expected<void, MoveOnly> e(std::unexpect, 5);
std::move(e)
- .value(); // expected-note{{in instantiation of member function 'std::expected<void, MoveOnly>::value' requested here}}
- // expected-error-re@*:* {{static assertion failed due to requirement 'is_copy_constructible_v<MoveOnly>': error_type has to be both copy constructible and move constructible}}
+ .value(); // expected-note {{in instantiation of member function 'std::expected<void, MoveOnly>::value' requested here}}
+ // expected-error@*:* {{static assertion failed due to requirement 'is_copy_constructible_v<MoveOnly>': error_type has to be both copy constructible and move constructible}}
}
-
-int main(int, char**) { test(); }
>From 5cf3dc623e5051d402ce4c6d135052c8ef511844 Mon Sep 17 00:00:00 2001
From: PragmaTwice <twice at apache.org>
Date: Wed, 3 Jan 2024 16:16:56 +0800
Subject: [PATCH 7/7] add more tests
---
libcxx/include/__expected/expected.h | 2 +-
.../expected.void/value.lwg3940.verify.cpp | 25 +++++++++++++++++++
2 files changed, 26 insertions(+), 1 deletion(-)
diff --git a/libcxx/include/__expected/expected.h b/libcxx/include/__expected/expected.h
index c6441f1651b085..d91f307ecda1c7 100644
--- a/libcxx/include/__expected/expected.h
+++ b/libcxx/include/__expected/expected.h
@@ -1187,7 +1187,7 @@ class expected<_Tp, _Err> {
}
_LIBCPP_HIDE_FROM_ABI constexpr void value() const& {
- static_assert(is_copy_constructible_v<_Err>, "error_type has to be copy constructible");
+ static_assert(is_copy_constructible_v<_Err>);
if (!__has_val_) {
std::__throw_bad_expected_access<_Err>(__union_.__unex_);
}
diff --git a/libcxx/test/libcxx/utilities/expected/expected.void/value.lwg3940.verify.cpp b/libcxx/test/libcxx/utilities/expected/expected.void/value.lwg3940.verify.cpp
index 33bac465a5eda2..04e5a5d68f2c25 100644
--- a/libcxx/test/libcxx/utilities/expected/expected.void/value.lwg3940.verify.cpp
+++ b/libcxx/test/libcxx/utilities/expected/expected.void/value.lwg3940.verify.cpp
@@ -7,6 +7,9 @@
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+// constexpr void value() const &;
+// Mandates: is_copy_constructible_v<E> is true.
+
// constexpr void value() &&;
// Mandates: is_copy_constructible_v<E> is true and is_move_constructible_v<E> is true.
@@ -14,11 +17,33 @@
#include "MoveOnly.h"
+struct CopyOnly {
+ CopyOnly() = default;
+ CopyOnly(const CopyOnly&) = default;
+ CopyOnly(CopyOnly&&) = delete;
+};
+
void test() {
// MoveOnly type as error_type
std::expected<void, MoveOnly> e(std::unexpect, 5);
+ e.value(); // expected-note {{in instantiation of member function 'std::expected<void, MoveOnly>::value' requested here}}
+ // expected-error@*:* {{static assertion failed due to requirement 'is_copy_constructible_v<MoveOnly>'}}
+
std::move(e)
.value(); // expected-note {{in instantiation of member function 'std::expected<void, MoveOnly>::value' requested here}}
// expected-error@*:* {{static assertion failed due to requirement 'is_copy_constructible_v<MoveOnly>': error_type has to be both copy constructible and move constructible}}
+
+ // CopyOnly type as error_type
+ std::expected<void, CopyOnly> e2(std::unexpect);
+
+ e2.value();
+
+ std::move(e2)
+ .value(); // expected-note {{in instantiation of member function 'std::expected<void, CopyOnly>::value' requested here}}
+ // expected-error@*:* {{static assertion failed due to requirement 'is_move_constructible_v<CopyOnly>': error_type has to be both copy constructible and move constructible}}
+
+ // expected-error@*:* {{call to deleted constructor of 'MoveOnly'}}
+ // expected-error@*:* {{call to deleted constructor of 'CopyOnly'}}
+ // expected-error@*:* {{call to deleted constructor of 'CopyOnly'}}
}
More information about the libcxx-commits
mailing list