[flang] [clang-tools-extra] [libc] [llvm] [clang] [libcxx] [compiler-rt] [libc++] Implement LWG3940: std::expected<void, E>::value() also needs E to be copy constructible (PR #71819)

via cfe-commits cfe-commits at lists.llvm.org
Tue Jan 9 05:58:14 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/9] [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/9] [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/9] 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/9] 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/9] 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/9] 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'}}
 }

>From 4ef228b7eeda58ab04dafdc2736f1f4a6a6ff850 Mon Sep 17 00:00:00 2001
From: PragmaTwice <twice at apache.org>
Date: Sat, 6 Jan 2024 11:20:03 +0800
Subject: [PATCH 8/9] exclude no-rtti and no-exceptions

---
 .../utilities/expected/expected.void/value.lwg3940.verify.cpp   | 2 ++
 1 file changed, 2 insertions(+)

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 04e5a5d68f2c25..69dd022bfc523e 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
@@ -6,6 +6,8 @@
 //===----------------------------------------------------------------------===//
 
 // UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+// UNSUPPORTED: no-rtti
+// UNSUPPORTED: no-exceptions
 
 // constexpr void value() const &;
 // Mandates: is_copy_constructible_v<E> is true.

>From 2614080a0e5260021a80140e5096bb86b46ebf23 Mon Sep 17 00:00:00 2001
From: PragmaTwice <twice at apache.org>
Date: Tue, 9 Jan 2024 22:57:46 +0900
Subject: [PATCH 9/9] remove static_assert message & move expected-error
 position

---
 libcxx/include/__expected/expected.h                     | 3 +--
 .../expected/expected.void/value.lwg3940.verify.cpp      | 9 ++++-----
 2 files changed, 5 insertions(+), 7 deletions(-)

diff --git a/libcxx/include/__expected/expected.h b/libcxx/include/__expected/expected.h
index 0cc82ed6c9db23..9f36c41b78edfd 100644
--- a/libcxx/include/__expected/expected.h
+++ b/libcxx/include/__expected/expected.h
@@ -1157,8 +1157,7 @@ class expected<_Tp, _Err> {
   }
 
   _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");
+    static_assert(is_copy_constructible_v<_Err> && is_move_constructible_v<_Err>);
     if (!__has_val_) {
       std::__throw_bad_expected_access<_Err>(std::move(__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 69dd022bfc523e..9c1c1d2e648d6a 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
@@ -31,21 +31,20 @@ void test() {
 
   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>'}}
+  // expected-error@*:* {{call to deleted constructor of '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}}
+  // expected-error@*:* {{static assertion failed due to requirement 'is_copy_constructible_v<MoveOnly>'}}
 
   // CopyOnly type as error_type
   std::expected<void, CopyOnly> e2(std::unexpect);
+  // expected-error@*:* {{call to deleted constructor of 'CopyOnly'}}
 
   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@*:* {{static assertion failed due to requirement 'is_move_constructible_v<CopyOnly>'}}
   // expected-error@*:* {{call to deleted constructor of 'CopyOnly'}}
 }



More information about the cfe-commits mailing list