Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 12 additions & 9 deletions stl/inc/expected
Original file line number Diff line number Diff line change
Expand Up @@ -238,14 +238,15 @@ public:
// clang-format on

template <class _Uty, class _UErr>
static constexpr bool _Allow_unwrapping = !is_constructible_v<_Ty, expected<_Uty, _UErr>&> //
&& !is_constructible_v<_Ty, expected<_Uty, _UErr>> //
&& !is_constructible_v<_Ty, const expected<_Uty, _UErr>&> //
&& !is_constructible_v<_Ty, const expected<_Uty, _UErr>> //
&& !is_convertible_v<expected<_Uty, _UErr>&, _Ty> //
&& !is_convertible_v<expected<_Uty, _UErr>&&, _Ty> //
&& !is_convertible_v<const expected<_Uty, _UErr>&, _Ty> //
&& !is_convertible_v<const expected<_Uty, _UErr>&&, _Ty> //
static constexpr bool _Allow_unwrapping = disjunction_v<is_same<remove_cv_t<_Ty>, bool>,
negation<disjunction<is_constructible<_Ty, expected<_Uty, _UErr>&>, //
is_constructible<_Ty, expected<_Uty, _UErr>>, //
is_constructible<_Ty, const expected<_Uty, _UErr>&>, //
is_constructible<_Ty, const expected<_Uty, _UErr>>, //
is_convertible<expected<_Uty, _UErr>&, _Ty>, //
is_convertible<expected<_Uty, _UErr>&&, _Ty>, //
is_convertible<const expected<_Uty, _UErr>&, _Ty>, //
is_convertible<const expected<_Uty, _UErr>&&, _Ty>>>> //
&& !is_constructible_v<unexpected<_Err>, expected<_Uty, _UErr>&> //
&& !is_constructible_v<unexpected<_Err>, expected<_Uty, _UErr>> //
&& !is_constructible_v<unexpected<_Err>, const expected<_Uty, _UErr>&> //
Expand Down Expand Up @@ -280,7 +281,9 @@ public:

template <class _Uty = _Ty>
requires (!is_same_v<remove_cvref_t<_Uty>, in_place_t> && !is_same_v<remove_cvref_t<_Uty>, expected>
&& !_Is_specialization_v<remove_cvref_t<_Uty>, unexpected> && is_constructible_v<_Ty, _Uty>)
&& !_Is_specialization_v<remove_cvref_t<_Uty>, unexpected>
&& (!is_same_v<remove_cv_t<_Ty>, bool> || !_Is_specialization_v<remove_cvref_t<_Uty>, expected>)
&& is_constructible_v<_Ty, _Uty>)
constexpr explicit(!is_convertible_v<_Uty, _Ty>)
expected(_Uty&& _Other) noexcept(is_nothrow_constructible_v<_Ty, _Uty>) // strengthened
: _Value(_STD forward<_Uty>(_Other)), _Has_value(true) {}
Expand Down
16 changes: 10 additions & 6 deletions stl/inc/optional
Original file line number Diff line number Diff line change
Expand Up @@ -239,19 +239,23 @@ public:

template <class _Ty2>
using _AllowDirectConversion = bool_constant<conjunction_v<negation<is_same<_Remove_cvref_t<_Ty2>, optional>>,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pre-existing, but why is this doing a bool_constant<conjunction_v rather than just conjunction; no change requested.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think there's some attempt here to improve throughput by "smashing" a complicated type to either true_type or false_type but looking at this again, I am unsure whether we are actually achieving anything here. In cases below (e.g. _AllowUnwrappingAssignment) we are introducing a new struct instead of simply a using, and there appears to be no short-circuit benefit to doing so. I'll record a todo on my list, but I would prefer to avoid touching this existing code in <optional> until Casey returns as there is no urgent need.

negation<is_same<_Remove_cvref_t<_Ty2>, in_place_t>>, is_constructible<_Ty, _Ty2>>>;
negation<is_same<_Remove_cvref_t<_Ty2>, in_place_t>>,
negation<conjunction<is_same<remove_cv_t<_Ty>, bool>, _Is_specialization<_Remove_cvref_t<_Ty2>, optional>>>,
is_constructible<_Ty, _Ty2>>>;

template <class _Ty2 = _Ty, enable_if_t<_AllowDirectConversion<_Ty2>::value, int> = 0>
constexpr explicit(!is_convertible_v<_Ty2, _Ty>)
optional(_Ty2&& _Right) noexcept(is_nothrow_constructible_v<_Ty, _Ty2>) // strengthened
: _Mybase(in_place, _STD forward<_Ty2>(_Right)) {}

template <class _Ty2>
struct _AllowUnwrapping : bool_constant<!disjunction_v<is_same<_Ty, _Ty2>, is_constructible<_Ty, optional<_Ty2>&>,
is_constructible<_Ty, const optional<_Ty2>&>,
is_constructible<_Ty, const optional<_Ty2>>, is_constructible<_Ty, optional<_Ty2>>,
is_convertible<optional<_Ty2>&, _Ty>, is_convertible<const optional<_Ty2>&, _Ty>,
is_convertible<const optional<_Ty2>, _Ty>, is_convertible<optional<_Ty2>, _Ty>>> {};
struct _AllowUnwrapping
: bool_constant<disjunction_v<is_same<remove_cv_t<_Ty>, bool>,
negation<disjunction<is_same<_Ty, _Ty2>, is_constructible<_Ty, optional<_Ty2>&>,
is_constructible<_Ty, const optional<_Ty2>&>, is_constructible<_Ty, const optional<_Ty2>>,
is_constructible<_Ty, optional<_Ty2>>, is_convertible<optional<_Ty2>&, _Ty>,
is_convertible<const optional<_Ty2>&, _Ty>, is_convertible<const optional<_Ty2>, _Ty>,
is_convertible<optional<_Ty2>, _Ty>>>>> {};

template <class _Ty2,
enable_if_t<conjunction_v<_AllowUnwrapping<_Ty2>, is_constructible<_Ty, const _Ty2&>>, int> = 0>
Expand Down
3 changes: 3 additions & 0 deletions tests/libcxx/expected_results.txt
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,9 @@ std/language.support/support.limits/support.limits.general/format.version.compil
# libc++ doesn't implement LWG-3670
std/ranges/range.factories/range.iota.view/iterator/member_typedefs.compile.pass.cpp FAIL

# libc++ doesn't implement LWG-3836
std/utilities/expected/expected.expected/ctor/ctor.u.pass.cpp FAIL

# libc++ doesn't implement LWG-3857
std/strings/string.view/string.view.cons/from_range.pass.cpp FAIL
std/strings/string.view/string.view.cons/from_string1.compile.fail.cpp FAIL
Expand Down
26 changes: 26 additions & 0 deletions tests/std/tests/P0220R1_optional/test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8148,6 +8148,30 @@ namespace msvc {
STATIC_ASSERT(!is_constructible_v<O, const in_place_t&>);
} // namespace lwg2842

namespace lwg3836 {
STATIC_ASSERT(std::is_convertible_v<std::optional<int>, std::optional<bool>>);
STATIC_ASSERT(std::is_convertible_v<const std::optional<int>&, std::optional<bool>>);

#if _HAS_CXX20
#define CONSTEXPR20 constexpr
#else // ^^^ _HAS_CXX20 / !_HAS_CXX20 vvv
#define CONSTEXPR20 inline
#endif // ^^^ !_HAS_CXX20 ^^^
CONSTEXPR20 bool run_test() {
std::optional<int> oi = 0;
std::optional<bool> ob = oi;
assert(!ob.value());
assert(!std::optional<bool>{std::optional<int>{0}}.value());

return true;
}
#undef CONSTEXPR20

#if _HAS_CXX20
STATIC_ASSERT(run_test());
#endif // _HAS_CXX20
} // namespace lwg3836

namespace vso406124 {
// Defend against regression of VSO-406124
void run_test() {
Expand Down Expand Up @@ -8334,6 +8358,8 @@ int main() {
nonmembers::make_optional_explicit_init_list::run_test();
nonmembers::swap_::run_test();

msvc::lwg3836::run_test();

msvc::vso406124::run_test();
msvc::vso508126::run_test();
msvc::vso614907::run_test();
Expand Down
8 changes: 8 additions & 0 deletions tests/std/tests/P0323R12_expected/test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -662,6 +662,14 @@ namespace test_expected {
test_constructors<IsNothrowConstructible::Not, IsExplicitConstructible::Yes>();
test_constructors<IsNothrowConstructible::Yes, IsExplicitConstructible::Not>();
test_constructors<IsNothrowConstructible::Yes, IsExplicitConstructible::Yes>();

// LWG-3836
struct BaseError {};
struct DerivedError : BaseError {};

std::expected<bool, DerivedError> e1(false);
std::expected<bool, BaseError> e2(e1);
Comment on lines +670 to +671

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No change requested: This test is already using namespace std;. Not worth resetting testing as this test has already accumulated ~20 occurrences; I'll clean this up later, no reason to pollute this PR.

assert(!e2.value());
}

template <IsNothrowCopyConstructible nothrowCopyConstructible, IsNothrowMoveConstructible nothrowMoveConstructible,
Expand Down