diff --git a/stl/inc/expected b/stl/inc/expected index 92f5590c529..2f093ce3a86 100644 --- a/stl/inc/expected +++ b/stl/inc/expected @@ -1159,9 +1159,9 @@ public: template _NODISCARD friend constexpr bool operator==(const expected& _Left, const _Uty& _Right) - noexcept(noexcept(static_cast(_Left._Value == _Right))) /* strengthened */ { + noexcept(noexcept(_STD _Fake_copy_init(_Left._Value == _Right))) /* strengthened */ { if (_Left._Has_value) { - return static_cast(_Left._Value == _Right); + return _Left._Value == _Right; } else { return false; } @@ -1169,11 +1169,11 @@ public: template _NODISCARD friend constexpr bool operator==(const expected& _Left, const unexpected<_UErr>& _Right) - noexcept(noexcept(static_cast(_Left._Unexpected == _Right.error()))) /* strengthened */ { + noexcept(noexcept(_STD _Fake_copy_init(_Left._Unexpected == _Right.error()))) /* strengthened */ { if (_Left._Has_value) { return false; } else { - return static_cast(_Left._Unexpected == _Right.error()); + return _Left._Unexpected == _Right.error(); } } @@ -1890,21 +1890,25 @@ public: template requires is_void_v<_Uty> _NODISCARD friend constexpr bool operator==(const expected& _Left, const expected<_Uty, _UErr>& _Right) - noexcept(noexcept(static_cast(_Left._Unexpected == _Right.error()))) /* strengthened */ { + noexcept(noexcept(_STD _Fake_copy_init(_Left._Unexpected == _Right.error()))) /* strengthened */ { if (_Left._Has_value != _Right.has_value()) { return false; } else { - return _Left._Has_value || static_cast(_Left._Unexpected == _Right.error()); + if (_Left._Has_value) { + return true; + } else { + return _Left._Unexpected == _Right.error(); + } } } template _NODISCARD friend constexpr bool operator==(const expected& _Left, const unexpected<_UErr>& _Right) - noexcept(noexcept(static_cast(_Left._Unexpected == _Right.error()))) /* strengthened */ { + noexcept(noexcept(_STD _Fake_copy_init(_Left._Unexpected == _Right.error()))) /* strengthened */ { if (_Left._Has_value) { return false; } else { - return static_cast(_Left._Unexpected == _Right.error()); + return _Left._Unexpected == _Right.error(); } } diff --git a/tests/std/tests/P0323R12_expected/test.cpp b/tests/std/tests/P0323R12_expected/test.cpp index f9cdbdaa04f..a67913c784c 100644 --- a/tests/std/tests/P0323R12_expected/test.cpp +++ b/tests/std/tests/P0323R12_expected/test.cpp @@ -2524,6 +2524,72 @@ static_assert(!is_constructible_v, unexpect_t>); static_assert(!is_constructible_v, const unexpect_t>); +// Test LWG-4366 "Heterogeneous comparison of expected may be ill-formed" +// Test taken from an example in the issue text +namespace test_lwg_4366 { + struct E1 {}; + struct E2 {}; + + struct Bool { + constexpr operator bool() const { + return false; + } + constexpr explicit operator bool() = delete; + }; + + constexpr Bool operator==(E1, E2) { + return {}; + } + + constexpr void test() { + unexpected e1{E1{}}; + unexpected e2{E2{}}; + (void) (expected{e1} == e2); + (void) (expected{e1} == e2); + (void) (e1 == e2); + (void) (expected{e1} == expected{e2}); + (void) (expected{e1} == expected{e2}); + } + + template + struct bool_with_noexcept { + constexpr operator bool() const noexcept(has_noexcept_operator_bool) { + return false; + } + }; + + // Test that operator== has correct noexcept specification (based on noexcept specs of underlying expressions) + + struct E3 {}; + template + struct E4 {}; + + template + constexpr bool_with_noexcept operator==(E3, E4) noexcept { + return {}; + } + + template + constexpr void test2() { + unexpected e3{E3{}}; + unexpected e4{E4{}}; + + (void) (expected{e3} == e4); + (void) (expected{e3} == e4); + (void) (e3 == e4); + (void) (expected{e3} == expected>{e4}); + (void) (expected{e3} == expected>{e4}); + + static_assert(has_noexcept_operator_bool == noexcept(expected{e3} == e4)); + static_assert(has_noexcept_operator_bool == noexcept(expected{e3} == e4)); + static_assert(has_noexcept_operator_bool == noexcept(e3 == e4)); + static_assert(has_noexcept_operator_bool + == noexcept(expected{e3} == expected>{e4})); + static_assert(has_noexcept_operator_bool + == noexcept(expected{e3} == expected>{e4})); + } +} // namespace test_lwg_4366 + int main() { test_unexpected::test_all(); static_assert(test_unexpected::test_all()); @@ -2543,4 +2609,8 @@ int main() { test_lwg_3886(); test_lwg_3886_volatile(); test_inherited_constructors(); + + test_lwg_4366::test(); + test_lwg_4366::test2(); + test_lwg_4366::test2(); }