[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