diff --git a/stl/inc/expected b/stl/inc/expected index 465a1616e9..12b06882c2 100644 --- a/stl/inc/expected +++ b/stl/inc/expected @@ -184,12 +184,28 @@ struct _Check_expected_argument : true_type { _EXPORT_STD template class expected { +private: static_assert(_Check_expected_argument<_Ty>::value); static_assert(_Check_unexpected_argument<_Err>::value); template friend class expected; + template + static constexpr bool _Allow_unwrapping = disjunction_v, bool>, + negation&>, // + is_constructible<_Ty, expected<_Uty, _UErr>>, // + is_constructible<_Ty, const expected<_Uty, _UErr>&>, // + is_constructible<_Ty, const expected<_Uty, _UErr>>, // + is_convertible&, _Ty>, // + is_convertible&&, _Ty>, // + is_convertible&, _Ty>, // + is_convertible&&, _Ty>>>> // + && !is_constructible_v, expected<_Uty, _UErr>&> // + && !is_constructible_v, expected<_Uty, _UErr>> // + && !is_constructible_v, const expected<_Uty, _UErr>&> // + && !is_constructible_v, const expected<_Uty, _UErr>>; + public: using value_type = _Ty; using error_type = _Err; @@ -238,23 +254,8 @@ public: // clang-format on template - static constexpr bool _Allow_unwrapping = disjunction_v, bool>, - negation&>, // - is_constructible<_Ty, expected<_Uty, _UErr>>, // - is_constructible<_Ty, const expected<_Uty, _UErr>&>, // - is_constructible<_Ty, const expected<_Uty, _UErr>>, // - is_convertible&, _Ty>, // - is_convertible&&, _Ty>, // - is_convertible&, _Ty>, // - is_convertible&&, _Ty>>>> // - && !is_constructible_v, expected<_Uty, _UErr>&> // - && !is_constructible_v, expected<_Uty, _UErr>> // - && !is_constructible_v, const expected<_Uty, _UErr>&> // - && !is_constructible_v, const expected<_Uty, _UErr>>; - - template - requires is_constructible_v<_Ty, const _Uty&> && is_constructible_v<_Err, const _UErr&> - && _Allow_unwrapping<_Uty, _UErr> + requires _Different_from, expected> && is_constructible_v<_Ty, const _Uty&> + && is_constructible_v<_Err, const _UErr&> && _Allow_unwrapping<_Uty, _UErr> constexpr explicit(!is_convertible_v || !is_convertible_v) expected(const expected<_Uty, _UErr>& _Other) noexcept(is_nothrow_constructible_v<_Ty, const _Uty&> // && is_nothrow_constructible_v<_Err, const _UErr&>) // strengthened @@ -267,7 +268,8 @@ public: } template - requires is_constructible_v<_Ty, _Uty> && is_constructible_v<_Err, _UErr> && _Allow_unwrapping<_Uty, _UErr> + requires _Different_from, expected> && is_constructible_v<_Ty, _Uty> + && is_constructible_v<_Err, _UErr> && _Allow_unwrapping<_Uty, _UErr> constexpr explicit(!is_convertible_v<_Uty, _Ty> || !is_convertible_v<_UErr, _Err>) expected(expected<_Uty, _UErr>&& _Other) noexcept( is_nothrow_constructible_v<_Ty, _Uty>&& is_nothrow_constructible_v<_Err, _UErr>) // strengthened @@ -1161,11 +1163,18 @@ private: template requires is_void_v<_Ty> class expected<_Ty, _Err> { +private: static_assert(_Check_unexpected_argument<_Err>::value); template friend class expected; + template + static constexpr bool _Allow_unwrapping = !is_constructible_v, expected<_Uty, _UErr>&> + && !is_constructible_v, expected<_Uty, _UErr>> + && !is_constructible_v, const expected<_Uty, _UErr>&> + && !is_constructible_v, const expected<_Uty, _UErr>>; + public: using value_type = _Ty; using error_type = _Err; @@ -1202,13 +1211,8 @@ public: // clang-format on template - static constexpr bool _Allow_unwrapping = !is_constructible_v, expected<_Uty, _UErr>&> - && !is_constructible_v, expected<_Uty, _UErr>> - && !is_constructible_v, const expected<_Uty, _UErr>&> - && !is_constructible_v, const expected<_Uty, _UErr>>; - - template - requires is_void_v<_Uty> && is_constructible_v<_Err, const _UErr&> && _Allow_unwrapping<_Uty, _UErr> + requires _Different_from, expected> && is_void_v<_Uty> + && is_constructible_v<_Err, const _UErr&> && _Allow_unwrapping<_Uty, _UErr> constexpr explicit(!is_convertible_v) expected(const expected<_Uty, _UErr>& _Other) noexcept( is_nothrow_constructible_v<_Err, const _UErr&>) // strengthened : _Has_value(_Other._Has_value) { @@ -1218,7 +1222,8 @@ public: } template - requires is_void_v<_Uty> && is_constructible_v<_Err, _UErr> && _Allow_unwrapping<_Uty, _UErr> + requires _Different_from, expected> && is_void_v<_Uty> && is_constructible_v<_Err, _UErr> + && _Allow_unwrapping<_Uty, _UErr> constexpr explicit(!is_convertible_v<_UErr, _Err>) expected(expected<_Uty, _UErr>&& _Other) noexcept(is_nothrow_constructible_v<_Err, _UErr>) // strengthened : _Has_value(_Other._Has_value) { @@ -1380,26 +1385,7 @@ public: is_nothrow_move_constructible_v<_Err>&& is_nothrow_swappable_v<_Err>) requires is_swappable_v<_Err> && is_move_constructible_v<_Err> { - using _STD swap; - if (_Left._Has_value && _Right._Has_value) { - // nothing - } else if (_Left._Has_value) { - _STD construct_at(_STD addressof(_Left._Unexpected), _STD move(_Right._Unexpected)); - if constexpr (!is_trivially_destructible_v<_Err>) { - _Right._Unexpected.~_Err(); - } - _Left._Has_value = false; - _Right._Has_value = true; - } else if (_Right._Has_value) { - _STD construct_at(_STD addressof(_Right._Unexpected), _STD move(_Left._Unexpected)); - if constexpr (!is_trivially_destructible_v<_Err>) { - _Left._Unexpected.~_Err(); - } - _Left._Has_value = true; - _Right._Has_value = false; - } else { - swap(_Left._Unexpected, _Right._Unexpected); // intentional ADL - } + _Left.swap(_Right); } // [expected.void.obs] diff --git a/tests/std/tests/P0323R12_expected/test.cpp b/tests/std/tests/P0323R12_expected/test.cpp index 91214c634f..5b822c1c57 100644 --- a/tests/std/tests/P0323R12_expected/test.cpp +++ b/tests/std/tests/P0323R12_expected/test.cpp @@ -3,6 +3,7 @@ #define _CONTAINER_DEBUG_LEVEL 1 +#include #include #include #include @@ -2135,6 +2136,10 @@ void test_lwg_3843() { } } +// Test GH-4011: these predicates triggered constraint recursion. +static_assert(copyable>); +static_assert(copyable>); + int main() { test_unexpected::test_all(); static_assert(test_unexpected::test_all());