[libcxx-commits] [libcxx] 96377e5 - [libc++][expected] Implement LWG3836

via libcxx-commits libcxx-commits at lists.llvm.org
Sun Aug 20 05:18:54 PDT 2023


Author: yrong
Date: 2023-08-20T20:18:09+08:00
New Revision: 96377e5cc1e39cccbc0b4911c0c2170e9135d105

URL: https://github.com/llvm/llvm-project/commit/96377e5cc1e39cccbc0b4911c0c2170e9135d105
DIFF: https://github.com/llvm/llvm-project/commit/96377e5cc1e39cccbc0b4911c0c2170e9135d105.diff

LOG: [libc++][expected] Implement LWG3836

Implement LWG3836 (https://wg21.link/LWG3836)
`std::expected<bool, E1>` conversion constructor `expected(const expected<U, G>&)` should take precedence over `expected(U&&)` with operator `bool`

Reviewed By: #libc, Mordante

Differential Revision: https://reviews.llvm.org/D155701

Added: 
    

Modified: 
    libcxx/docs/Status/Cxx23Issues.csv
    libcxx/include/__expected/expected.h
    libcxx/include/optional
    libcxx/test/std/utilities/expected/expected.expected/ctor/ctor.u.pass.cpp
    libcxx/test/std/utilities/optional/optional.object/optional.object.ctor/copy.pass.cpp

Removed: 
    


################################################################################
diff  --git a/libcxx/docs/Status/Cxx23Issues.csv b/libcxx/docs/Status/Cxx23Issues.csv
index 0cc06674bda390..a27158e6040943 100644
--- a/libcxx/docs/Status/Cxx23Issues.csv
+++ b/libcxx/docs/Status/Cxx23Issues.csv
@@ -290,7 +290,7 @@
 "`3827 <https://wg21.link/LWG3827>`__","Deprecate ``<stdalign.h>`` and ``<stdbool.h>`` macros","February 2023","","",""
 "`3828 <https://wg21.link/LWG3828>`__","Sync ``intmax_t`` and ``uintmax_t`` with C2x","February 2023","","",""
 "`3833 <https://wg21.link/LWG3833>`__","Remove specialization ``template<size_t N> struct formatter<const charT[N], charT>``","February 2023","|Complete|","17.0","|format|"
-"`3836 <https://wg21.link/LWG3836>`__","``std::expected<bool, E1>`` conversion constructor ``expected(const expected<U, G>&)`` should take precedence over ``expected(U&&)`` with operator ``bool``","February 2023","","",""
+"`3836 <https://wg21.link/LWG3836>`__","``std::expected<bool, E1>`` conversion constructor ``expected(const expected<U, G>&)`` should take precedence over ``expected(U&&)`` with operator ``bool``","February 2023","|Complete|","18.0",""
 "`3843 <https://wg21.link/LWG3843>`__","``std::expected<T,E>::value() &`` assumes ``E`` is copy constructible","February 2023","|Complete|","17.0",""
 "`3847 <https://wg21.link/LWG3847>`__","``ranges::to`` can still return views","February 2023","|Complete|","17.0","|ranges|"
 "`3862 <https://wg21.link/LWG3862>`__","``basic_const_iterator``'s ``common_type`` specialization is underconstrained","February 2023","","",""

diff  --git a/libcxx/include/__expected/expected.h b/libcxx/include/__expected/expected.h
index 7d57aa4db5f952..dd383ff8596370 100644
--- a/libcxx/include/__expected/expected.h
+++ b/libcxx/include/__expected/expected.h
@@ -167,14 +167,16 @@ class expected {
   using __can_convert =
       _And< is_constructible<_Tp, _UfQual>,
             is_constructible<_Err, _OtherErrQual>,
-            _Not<is_constructible<_Tp, expected<_Up, _OtherErr>&>>,
-            _Not<is_constructible<_Tp, expected<_Up, _OtherErr>>>,
-            _Not<is_constructible<_Tp, const expected<_Up, _OtherErr>&>>,
-            _Not<is_constructible<_Tp, const expected<_Up, _OtherErr>>>,
-            _Not<is_convertible<expected<_Up, _OtherErr>&, _Tp>>,
-            _Not<is_convertible<expected<_Up, _OtherErr>&&, _Tp>>,
-            _Not<is_convertible<const expected<_Up, _OtherErr>&, _Tp>>,
-            _Not<is_convertible<const expected<_Up, _OtherErr>&&, _Tp>>,
+            _If<_Not<is_same<remove_cv_t<_Tp>, bool>>::value,
+                _And< _Not<is_constructible<_Tp, expected<_Up, _OtherErr>&>>,
+                      _Not<is_constructible<_Tp, expected<_Up, _OtherErr>>>,
+                      _Not<is_constructible<_Tp, const expected<_Up, _OtherErr>&>>,
+                      _Not<is_constructible<_Tp, const expected<_Up, _OtherErr>>>,
+                      _Not<is_convertible<expected<_Up, _OtherErr>&, _Tp>>,
+                      _Not<is_convertible<expected<_Up, _OtherErr>&&, _Tp>>,
+                      _Not<is_convertible<const expected<_Up, _OtherErr>&, _Tp>>,
+                      _Not<is_convertible<const expected<_Up, _OtherErr>&&, _Tp>>>,
+                true_type>,
             _Not<is_constructible<unexpected<_Err>, expected<_Up, _OtherErr>&>>,
             _Not<is_constructible<unexpected<_Err>, expected<_Up, _OtherErr>>>,
             _Not<is_constructible<unexpected<_Err>, const expected<_Up, _OtherErr>&>>,
@@ -221,15 +223,14 @@ class expected {
 
   template <class _Up = _Tp>
     requires(!is_same_v<remove_cvref_t<_Up>, in_place_t> && !is_same_v<expected, remove_cvref_t<_Up>> &&
-             !__is_std_unexpected<remove_cvref_t<_Up>>::value && is_constructible_v<_Tp, _Up>)
+             is_constructible_v<_Tp, _Up> && !__is_std_unexpected<remove_cvref_t<_Up>>::value &&
+             (!is_same_v<remove_cv_t<_Tp>, bool> || !__is_std_expected<remove_cvref_t<_Up>>::value))
   _LIBCPP_HIDE_FROM_ABI constexpr explicit(!is_convertible_v<_Up, _Tp>)
-  expected(_Up&& __u)
-    noexcept(is_nothrow_constructible_v<_Tp, _Up>) // strengthened
+      expected(_Up&& __u) noexcept(is_nothrow_constructible_v<_Tp, _Up>) // strengthened
       : __has_val_(true) {
     std::construct_at(std::addressof(__union_.__val_), std::forward<_Up>(__u));
   }
 
-
   template <class _OtherErr>
     requires is_constructible_v<_Err, const _OtherErr&>
   _LIBCPP_HIDE_FROM_ABI constexpr explicit(!is_convertible_v<const _OtherErr&, _Err>)

diff  --git a/libcxx/include/optional b/libcxx/include/optional
index e7e5193a0bb626..80146234fc9bff 100644
--- a/libcxx/include/optional
+++ b/libcxx/include/optional
@@ -731,7 +731,8 @@ private:
     template <class _Up>
     using _CheckOptionalArgsCtor = _If<
         _IsNotSame<__remove_cvref_t<_Up>, in_place_t>::value &&
-        _IsNotSame<__remove_cvref_t<_Up>, optional>::value,
+        _IsNotSame<__remove_cvref_t<_Up>, optional>::value &&
+        (!is_same_v<remove_cv_t<_Tp>, bool> || !__is_std_optional<__remove_cvref_t<_Up>>::value),
         _CheckOptionalArgsConstructor,
         __check_tuple_constructor_fail
     >;
@@ -758,12 +759,12 @@ private:
       template <class _Up, class _QUp = _QualUp>
       _LIBCPP_HIDE_FROM_ABI static constexpr bool __enable_implicit() {
           return is_convertible<_QUp, _Tp>::value &&
-              !__check_constructible_from_opt<_Up>::value;
+                 (is_same_v<remove_cv_t<_Tp>, bool> || !__check_constructible_from_opt<_Up>::value);
       }
       template <class _Up, class _QUp = _QualUp>
       _LIBCPP_HIDE_FROM_ABI static constexpr bool __enable_explicit() {
           return !is_convertible<_QUp, _Tp>::value &&
-              !__check_constructible_from_opt<_Up>::value;
+                 (is_same_v<remove_cv_t<_Tp>, bool> || !__check_constructible_from_opt<_Up>::value);
       }
       template <class _Up, class _QUp = _QualUp>
       _LIBCPP_HIDE_FROM_ABI static constexpr bool __enable_assign() {

diff  --git a/libcxx/test/std/utilities/expected/expected.expected/ctor/ctor.u.pass.cpp b/libcxx/test/std/utilities/expected/expected.expected/ctor/ctor.u.pass.cpp
index f05c2d15f3bbe5..9e82943f9f314d 100644
--- a/libcxx/test/std/utilities/expected/expected.expected/ctor/ctor.u.pass.cpp
+++ b/libcxx/test/std/utilities/expected/expected.expected/ctor/ctor.u.pass.cpp
@@ -67,6 +67,9 @@ struct CopyOnly {
   friend constexpr bool operator==(const CopyOnly& mi, int ii) { return mi.i == ii; }
 };
 
+struct BaseError {};
+struct DerivedError : BaseError {};
+
 template <class T>
 constexpr void testInt() {
   std::expected<T, int> e(5);
@@ -112,17 +115,38 @@ constexpr bool test() {
     assert(e.value().j == 6);
   }
 
-  // this is a confusing example, but the behaviour
-  // is exactly what is specified in the spec
-  // see https://cplusplus.github.io/LWG/issue3836
+  // https://cplusplus.github.io/LWG/issue3836
+
+  // Test &
   {
-    struct BaseError {};
-    struct DerivedError : BaseError {};
+    std::expected<bool, DerivedError> e1(false);
+    std::expected<bool, BaseError> e2(e1);
+    assert(e2.has_value());
+    assert(!e2.value()); // yes, e2 holds "false" since LWG3836
+  }
 
+  // Test &&
+  {
     std::expected<bool, DerivedError> e1(false);
+    std::expected<bool, BaseError> e2(std::move(e1));
+    assert(e2.has_value());
+    assert(!e2.value()); // yes, e2 holds "false" since LWG3836
+  }
+
+  // Test const&
+  {
+    const std::expected<bool, DerivedError> e1(false);
     std::expected<bool, BaseError> e2(e1);
     assert(e2.has_value());
-    assert(e2.value()); // yes, e2 holds "true"
+    assert(!e2.value()); // yes, e2 holds "false" since LWG3836
+  }
+
+  // Test const&&
+  {
+    const std::expected<bool, DerivedError> e1(false);
+    std::expected<bool, BaseError> e2(std::move(e1));
+    assert(e2.has_value());
+    assert(!e2.value()); // yes, e2 holds "false" since LWG3836
   }
   return true;
 }

diff  --git a/libcxx/test/std/utilities/optional/optional.object/optional.object.ctor/copy.pass.cpp b/libcxx/test/std/utilities/optional/optional.object/optional.object.ctor/copy.pass.cpp
index 265b4bf9682c63..54a424c4c347de 100644
--- a/libcxx/test/std/utilities/optional/optional.object/optional.object.ctor/copy.pass.cpp
+++ b/libcxx/test/std/utilities/optional/optional.object/optional.object.ctor/copy.pass.cpp
@@ -170,5 +170,14 @@ int main(int, char**)
         static_assert( *o2 == 4, "" );
     }
 
+    // LWG3836 https://wg21.link/LWG3836
+    // std::optional<bool> conversion constructor optional(const optional<U>&)
+    // should take precedence over optional(U&&) with operator bool
+    {
+        std::optional<bool> o1(false);
+        std::optional<bool> o2(o1);
+        assert(!o2.value());
+    }
+
   return 0;
 }


        


More information about the libcxx-commits mailing list