diff --git a/libcxx/docs/Status/Cxx23Issues.csv b/libcxx/docs/Status/Cxx23Issues.csv --- a/libcxx/docs/Status/Cxx23Issues.csv +++ b/libcxx/docs/Status/Cxx23Issues.csv @@ -290,7 +290,7 @@ "`3827 `__","Deprecate ```` and ```` macros","February 2023","","","" "`3828 `__","Sync ``intmax_t`` and ``uintmax_t`` with C2x","February 2023","","","" "`3833 `__","Remove specialization ``template struct formatter``","February 2023","|Complete|","17.0","|format|" -"`3836 `__","``std::expected`` conversion constructor ``expected(const expected&)`` should take precedence over ``expected(U&&)`` with operator ``bool``","February 2023","","","" +"`3836 `__","``std::expected`` conversion constructor ``expected(const expected&)`` should take precedence over ``expected(U&&)`` with operator ``bool``","February 2023","|Complete|","18.0","" "`3843 `__","``std::expected::value() &`` assumes ``E`` is copy constructible","February 2023","|Complete|","17.0","" "`3847 `__","``ranges::to`` can still return views","February 2023","|Complete|","17.0","|ranges|" "`3862 `__","``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 --- a/libcxx/include/__expected/expected.h +++ b/libcxx/include/__expected/expected.h @@ -167,14 +167,18 @@ using __can_convert = _And< is_constructible<_Tp, _UfQual>, is_constructible<_Err, _OtherErrQual>, - _Not&>>, - _Not>>, - _Not&>>, - _Not>>, - _Not&, _Tp>>, - _Not&&, _Tp>>, - _Not&, _Tp>>, - _Not&&, _Tp>>, + + _Or< is_same, bool>, + _And< _Not&>>, + _Not>>, + _Not&>>, + _Not>>, + + _Not&, _Tp>>, + _Not&&, _Tp>>, + _Not&, _Tp>>, + _Not&&, _Tp>>>>, + _Not, expected<_Up, _OtherErr>&>>, _Not, expected<_Up, _OtherErr>>>, _Not, const expected<_Up, _OtherErr>&>>, @@ -221,15 +225,15 @@ template requires(!is_same_v, in_place_t> && !is_same_v> && - !__is_std_unexpected>::value && is_constructible_v<_Tp, _Up>) + !__is_std_unexpected>::value && is_constructible_v<_Tp, _Up> && + // LWG3836 + (!is_same_v, bool> || !__is_std_expected>::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 requires is_constructible_v<_Err, const _OtherErr&> _LIBCPP_HIDE_FROM_ABI constexpr explicit(!is_convertible_v) diff --git a/libcxx/include/optional b/libcxx/include/optional --- a/libcxx/include/optional +++ b/libcxx/include/optional @@ -731,7 +731,8 @@ template 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, bool> || !__is_std_optional<__remove_cvref_t<_Up>>::value), _CheckOptionalArgsConstructor, __check_tuple_constructor_fail >; @@ -758,12 +759,12 @@ template _LIBCPP_HIDE_FROM_ABI static constexpr bool __enable_implicit() { return is_convertible<_QUp, _Tp>::value && - !__check_constructible_from_opt<_Up>::value; + (is_same_v, bool> || !__check_constructible_from_opt<_Up>::value); } template _LIBCPP_HIDE_FROM_ABI static constexpr bool __enable_explicit() { return !is_convertible<_QUp, _Tp>::value && - !__check_constructible_from_opt<_Up>::value; + (is_same_v, bool> || !__check_constructible_from_opt<_Up>::value); } template _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 --- 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 @@ -112,9 +112,7 @@ 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 { struct BaseError {}; struct DerivedError : BaseError {}; @@ -122,7 +120,7 @@ std::expected e1(false); std::expected e2(e1); assert(e2.has_value()); - assert(e2.value()); // yes, e2 holds "true" + 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 --- 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 @@ static_assert( *o2 == 4, "" ); } + // LWG3836 https://wg21.link/LWG3836 + // std::optional conversion constructor optional(const optional&) + // should take precedence over optional(U&&) with operator bool + { + std::optional o1(false); + std::optional o2(o1); + assert(!o2.value()); + } + return 0; }