diff --git a/libcxx/docs/FeatureTestMacroTable.rst b/libcxx/docs/FeatureTestMacroTable.rst --- a/libcxx/docs/FeatureTestMacroTable.rst +++ b/libcxx/docs/FeatureTestMacroTable.rst @@ -318,7 +318,7 @@ ------------------------------------------------- ----------------- ``__cpp_lib_constexpr_typeinfo`` *unimplemented* ------------------------------------------------- ----------------- - ``__cpp_lib_expected`` ``202202L`` + ``__cpp_lib_expected`` ``202211L`` ------------------------------------------------- ----------------- ``__cpp_lib_forward_like`` ``202207L`` ------------------------------------------------- ----------------- diff --git a/libcxx/docs/Status/Cxx2bPapers.csv b/libcxx/docs/Status/Cxx2bPapers.csv --- a/libcxx/docs/Status/Cxx2bPapers.csv +++ b/libcxx/docs/Status/Cxx2bPapers.csv @@ -100,7 +100,7 @@ "`P1478R8 `__","LWG", "``Byte-wise`` ``atomic`` ``memcpy``", "November 2022","","","|concurrency TS|" "`P2167R3 `__","LWG", "Improved Proposed Wording for LWG 2114", "November 2022","","","" "`P2396R1 `__","LWG", "Concurrency TS 2 fixes ", "November 2022","","","|concurrency TS|" -"`P2505R5 `__","LWG", "Monadic Functions for ``std::expected``", "November 2022","","","" +"`P2505R5 `__","LWG", "Monadic Functions for ``std::expected``", "November 2022","July 2022","|Complete|","16.0" "`P2539R4 `__","LWG", "Should the output of ``std::print`` to a terminal be synchronized with the underlying stream?", "November 2022","","","|format|" "`P2602R2 `__","LWG", "Poison Pills are Too Toxic", "November 2022","","","|ranges|" "`P2708R1 `__","LWG", "No Further Fundamentals TSes", "November 2022","|Nothing to do|","","" 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 @@ -14,10 +14,12 @@ #include <__expected/bad_expected_access.h> #include <__expected/unexpect.h> #include <__expected/unexpected.h> +#include <__functional/invoke.h> #include <__memory/addressof.h> #include <__memory/construct_at.h> #include <__type_traits/conjunction.h> #include <__type_traits/disjunction.h> +#include <__type_traits/integral_constant.h> #include <__type_traits/is_assignable.h> #include <__type_traits/is_constructible.h> #include <__type_traits/is_convertible.h> @@ -60,8 +62,20 @@ _LIBCPP_BEGIN_NAMESPACE_STD +template +class expected; + namespace __expected { +template +struct __is_std_expected : false_type {}; + +template +struct __is_std_expected> : true_type {}; + +struct __expected_construct_in_place_from_invoke_tag {}; +struct __expected_construct_unexpected_from_invoke_tag {}; + template _LIBCPP_HIDE_FROM_ABI void __throw_bad_expected_access(_Arg&& __arg) { # ifndef _LIBCPP_NO_EXCEPTIONS @@ -76,19 +90,14 @@ template class expected { - static_assert( - !is_reference_v<_Tp> && - !is_function_v<_Tp> && - !is_same_v, in_place_t> && - !is_same_v, unexpect_t> && - !__unexpected::__is_unexpected>::value && - __unexpected::__valid_unexpected<_Err>::value - , - "[expected.object.general] A program that instantiates the definition of template expected for a " - "reference type, a function type, or for possibly cv-qualified types in_place_t, unexpect_t, or a " - "specialization of unexpected for the T parameter is ill-formed. A program that instantiates the " - "definition of the template expected with a type for the E parameter that is not a valid " - "template argument for unexpected is ill-formed."); + static_assert(!is_reference_v<_Tp> && !is_function_v<_Tp> && !is_same_v, in_place_t> && + !is_same_v, unexpect_t> && + !__unexpected::__is_unexpected>::value && + __unexpected::__valid_unexpected<_Err>::value, + "[expected.object.general] A type T is a valid value type for expected, if remove_cv_t is void or a " + "complete non-array object type that is not in_place_t, unexpect_t, or a specialization of unexpected. " + "A program which instantiates class template expected with an argument T that is not a valid " + "value type for expected is ill-formed."); template friend class expected; @@ -166,6 +175,15 @@ _Not, const expected<_Up, _OtherErr>&>>, _Not, const expected<_Up, _OtherErr>>> >; + template + _LIBCPP_HIDE_FROM_ABI constexpr explicit expected( + __expected::__expected_construct_in_place_from_invoke_tag __tag, _Func&& __f, _Args&&... __args) + : __union_(__tag, std::forward<_Func>(__f), std::forward<_Args>(__args)...), __has_val_(true) {} + + template + _LIBCPP_HIDE_FROM_ABI constexpr explicit expected( + __expected::__expected_construct_unexpected_from_invoke_tag __tag, _Func&& __f, _Args&&... __args) + : __union_(__tag, std::forward<_Func>(__f), std::forward<_Args>(__args)...), __has_val_(false) {} public: template @@ -595,6 +613,245 @@ return __has_val_ ? std::move(__union_.__val_) : static_cast<_Tp>(std::forward<_Up>(__v)); } + template + _LIBCPP_HIDE_FROM_ABI constexpr _Err error_or(_Up&& __error) const& { + static_assert(is_copy_constructible_v<_Err>, "error_type has to be copy constructible"); + static_assert(is_convertible_v<_Up, _Err>, "argument has to be convertible to error_type"); + if (has_value()) + return std::forward<_Up>(__error); + return error(); + } + + template + _LIBCPP_HIDE_FROM_ABI constexpr _Err error_or(_Up&& __error) && { + static_assert(is_move_constructible_v<_Err>, "error_type has to be move constructible"); + static_assert(is_convertible_v<_Up, _Err>, "argument has to be convertible to error_type"); + if (has_value()) + return std::forward<_Up>(__error); + return std::move(error()); + } + + // [expected.void.monadic], monadic + template + requires is_copy_constructible_v<_Err> + _LIBCPP_HIDE_FROM_ABI constexpr auto and_then(_Func&& __f) & { + using _Up = remove_cvref_t>; + static_assert(__expected::__is_std_expected<_Up>::value, + "The result of f(value()) must be a specialization of std::expected"); + static_assert(is_same_v, + "The result of f(value()) must have the same error_type as this expected"); + if (has_value()) { + return std::invoke(std::forward<_Func>(__f), value()); + } + return _Up(unexpect, error()); + } + + template + requires is_copy_constructible_v<_Err> + _LIBCPP_HIDE_FROM_ABI constexpr auto and_then(_Func&& __f) const& { + using _Up = remove_cvref_t>; + static_assert(__expected::__is_std_expected<_Up>::value, + "The result of f(value()) must be a specialization of std::expected"); + static_assert(is_same_v, + "The result of f(value()) must have the same error_type as this expected"); + if (has_value()) { + return std::invoke(std::forward<_Func>(__f), value()); + } + return _Up(unexpect, error()); + } + + template + requires is_move_constructible_v<_Err> + _LIBCPP_HIDE_FROM_ABI constexpr auto and_then(_Func&& __f) && { + using _Up = remove_cvref_t>; + static_assert(__expected::__is_std_expected<_Up>::value, + "The result of f(std::move(value())) must be a specialization of std::expected"); + static_assert(is_same_v, + "The result of f(std::move(value())) must have the same error_type as this expected"); + if (has_value()) { + return std::invoke(std::forward<_Func>(__f), std::move(value())); + } + return _Up(unexpect, std::move(error())); + } + + template + requires is_move_constructible_v<_Err> + _LIBCPP_HIDE_FROM_ABI constexpr auto and_then(_Func&& __f) const&& { + using _Up = remove_cvref_t>; + static_assert(__expected::__is_std_expected<_Up>::value, + "The result of f(std::move(value())) must be a specialization of std::expected"); + static_assert(is_same_v, + "The result of f(std::move(value())) must have the same error_type as this expected"); + if (has_value()) { + return std::invoke(std::forward<_Func>(__f), std::move(value())); + } + return _Up(unexpect, std::move(error())); + } + + template + requires is_copy_constructible_v<_Tp> + _LIBCPP_HIDE_FROM_ABI constexpr auto or_else(_Func&& __f) & { + using _Gp = remove_cvref_t>; + static_assert(__expected::__is_std_expected<_Gp>::value, + "The result of f(error()) must be a specialization of std::expected"); + static_assert(is_same_v, + "The result of f(error()) must have the same value_type as this expected"); + if (has_value()) { + return _Gp(in_place, value()); + } + return std::invoke(std::forward<_Func>(__f), error()); + } + + template + requires is_copy_constructible_v<_Tp> + _LIBCPP_HIDE_FROM_ABI constexpr auto or_else(_Func&& __f) const& { + using _Gp = remove_cvref_t>; + static_assert(__expected::__is_std_expected<_Gp>::value, + "The result of f(error()) must be a specialization of std::expected"); + static_assert(is_same_v, + "The result of f(error()) must have the same value_type as this expected"); + if (has_value()) { + return _Gp(in_place, value()); + } + return std::invoke(std::forward<_Func>(__f), error()); + } + + template + requires is_move_constructible_v<_Tp> + _LIBCPP_HIDE_FROM_ABI constexpr auto or_else(_Func&& __f) && { + using _Gp = remove_cvref_t>; + static_assert(__expected::__is_std_expected<_Gp>::value, + "The result of f(std::move(error())) must be a specialization of std::expected"); + static_assert(is_same_v, + "The result of f(std::move(error())) must have the same value_type as this expected"); + if (has_value()) { + return _Gp(in_place, std::move(value())); + } + return std::invoke(std::forward<_Func>(__f), std::move(error())); + } + + template + requires is_move_constructible_v<_Tp> + _LIBCPP_HIDE_FROM_ABI constexpr auto or_else(_Func&& __f) const&& { + using _Gp = remove_cvref_t>; + static_assert(__expected::__is_std_expected<_Gp>::value, + "The result of f(std::move(error())) must be a specialization of std::expected"); + static_assert(is_same_v, + "The result of f(std::move(error())) must have the same value_type as this expected"); + if (has_value()) { + return _Gp(in_place, std::move(value())); + } + return std::invoke(std::forward<_Func>(__f), std::move(error())); + } + + template + requires is_copy_constructible_v<_Err> + _LIBCPP_HIDE_FROM_ABI constexpr auto transform(_Func&& __f) & { + using _Up = remove_cv_t>; + if (!has_value()) { + return expected<_Up, _Err>(unexpect, error()); + } + if constexpr (!is_void_v<_Up>) { + return expected<_Up, _Err>( + __expected::__expected_construct_in_place_from_invoke_tag{}, std::forward<_Func>(__f), value()); + } else { + std::invoke(std::forward<_Func>(__f), value()); + return expected<_Up, _Err>(); + } + } + + template + requires is_copy_constructible_v<_Err> + _LIBCPP_HIDE_FROM_ABI constexpr auto transform(_Func&& __f) const& { + using _Up = remove_cv_t>; + if (!has_value()) { + return expected<_Up, _Err>(unexpect, error()); + } + if constexpr (!is_void_v<_Up>) { + return expected<_Up, _Err>( + __expected::__expected_construct_in_place_from_invoke_tag{}, std::forward<_Func>(__f), value()); + } else { + std::invoke(std::forward<_Func>(__f), value()); + return expected<_Up, _Err>(); + } + } + + template + requires is_move_constructible_v<_Err> + _LIBCPP_HIDE_FROM_ABI constexpr auto transform(_Func&& __f) && { + using _Up = remove_cv_t>; + if (!has_value()) { + return expected<_Up, _Err>(unexpect, std::move(error())); + } + if constexpr (!is_void_v<_Up>) { + return expected<_Up, _Err>( + __expected::__expected_construct_in_place_from_invoke_tag{}, std::forward<_Func>(__f), std::move(value())); + } else { + std::invoke(std::forward<_Func>(__f), std::move(value())); + return expected<_Up, _Err>(); + } + } + + template + requires is_move_constructible_v<_Err> + _LIBCPP_HIDE_FROM_ABI constexpr auto transform(_Func&& __f) const&& { + using _Up = remove_cv_t>; + if (!has_value()) { + return expected<_Up, _Err>(unexpect, std::move(error())); + } + if constexpr (!is_void_v<_Up>) { + return expected<_Up, _Err>( + __expected::__expected_construct_in_place_from_invoke_tag{}, std::forward<_Func>(__f), std::move(value())); + } else { + std::invoke(std::forward<_Func>(__f), std::move(value())); + return expected<_Up, _Err>(); + } + } + + template + requires is_copy_constructible_v<_Tp> + _LIBCPP_HIDE_FROM_ABI constexpr auto transform_error(_Func&& __f) & { + using _Gp = remove_cv_t>; + if (has_value()) { + return expected<_Tp, _Gp>(in_place, value()); + } + return expected<_Tp, _Gp>( + __expected::__expected_construct_unexpected_from_invoke_tag{}, std::forward<_Func>(__f), error()); + } + + template + requires is_copy_constructible_v<_Tp> + _LIBCPP_HIDE_FROM_ABI constexpr auto transform_error(_Func&& __f) const& { + using _Gp = remove_cv_t>; + if (has_value()) { + return expected<_Tp, _Gp>(in_place, value()); + } + return expected<_Tp, _Gp>( + __expected::__expected_construct_unexpected_from_invoke_tag{}, std::forward<_Func>(__f), error()); + } + + template + requires is_move_constructible_v<_Tp> + _LIBCPP_HIDE_FROM_ABI constexpr auto transform_error(_Func&& __f) && { + using _Gp = remove_cv_t>; + if (has_value()) { + return expected<_Tp, _Gp>(in_place, std::move(value())); + } + return expected<_Tp, _Gp>( + __expected::__expected_construct_unexpected_from_invoke_tag{}, std::forward<_Func>(__f), std::move(error())); + } + + template + requires is_move_constructible_v<_Tp> + _LIBCPP_HIDE_FROM_ABI constexpr auto transform_error(_Func&& __f) const&& { + using _Gp = remove_cv_t>; + if (has_value()) { + return expected<_Tp, _Gp>(in_place, std::move(value())); + } + return expected<_Tp, _Gp>( + __expected::__expected_construct_unexpected_from_invoke_tag{}, std::forward<_Func>(__f), std::move(error())); + } + // [expected.object.eq], equality operators template requires(!is_void_v<_T2>) @@ -626,6 +883,16 @@ _LIBCPP_NO_UNIQUE_ADDRESS union __union_t { _LIBCPP_HIDE_FROM_ABI constexpr __union_t() : __empty_() {} + template + _LIBCPP_HIDE_FROM_ABI constexpr explicit __union_t( + __expected::__expected_construct_in_place_from_invoke_tag, _Func&& __f, _Args&&... __args) + : __val_(std::invoke(std::forward<_Func>(__f), std::forward<_Args>(__args)...)) {} + + template + _LIBCPP_HIDE_FROM_ABI constexpr explicit __union_t( + __expected::__expected_construct_unexpected_from_invoke_tag, _Func&& __f, _Args&&... __args) + : __unex_(std::invoke(std::forward<_Func>(__f), std::forward<_Args>(__args)...)) {} + _LIBCPP_HIDE_FROM_ABI constexpr ~__union_t() requires(is_trivially_destructible_v<_Tp> && is_trivially_destructible_v<_Err>) = default; @@ -759,6 +1026,20 @@ std::construct_at(std::addressof(__union_.__unex_), __il, std::forward<_Args>(__args)...); } +private: + template + _LIBCPP_HIDE_FROM_ABI constexpr explicit expected(__expected::__expected_construct_in_place_from_invoke_tag, + _Func&& __f) + : __has_val_(true) { + std::invoke(std::forward<_Func>(__f)); + } + + template + _LIBCPP_HIDE_FROM_ABI constexpr explicit expected( + __expected::__expected_construct_unexpected_from_invoke_tag __tag, _Func&& __f, _Args&&... __args) + : __union_(__tag, std::forward<_Func>(__f), std::forward<_Args>(__args)...), __has_val_(false) {} + +public: // [expected.void.dtor], destructor _LIBCPP_HIDE_FROM_ABI constexpr ~expected() @@ -926,6 +1207,235 @@ return std::move(__union_.__unex_); } + template + _LIBCPP_HIDE_FROM_ABI constexpr _Err error_or(_Up&& __error) const& { + static_assert(is_copy_constructible_v<_Err>, "error_type has to be copy constructible"); + static_assert(is_convertible_v<_Up, _Err>, "argument has to be convertible to error_type"); + if (has_value()) { + return std::forward<_Up>(__error); + } + return error(); + } + + template + _LIBCPP_HIDE_FROM_ABI constexpr _Err error_or(_Up&& __error) && { + static_assert(is_move_constructible_v<_Err>, "error_type has to be move constructible"); + static_assert(is_convertible_v<_Up, _Err>, "argument has to be convertible to error_type"); + if (has_value()) { + return std::forward<_Up>(__error); + } + return std::move(error()); + } + + // [expected.void.monadic], monadic + template + requires is_copy_constructible_v<_Err> + _LIBCPP_HIDE_FROM_ABI constexpr auto and_then(_Func&& __f) & { + using _Up = remove_cvref_t>; + static_assert( + __expected::__is_std_expected<_Up>::value, "The result of f() must be a specialization of std::expected"); + static_assert( + is_same_v, "The result of f() must have the same error_type as this expected"); + if (has_value()) { + return std::invoke(std::forward<_Func>(__f)); + } + return _Up(unexpect, error()); + } + + template + requires is_copy_constructible_v<_Err> + _LIBCPP_HIDE_FROM_ABI constexpr auto and_then(_Func&& __f) const& { + using _Up = remove_cvref_t>; + static_assert( + __expected::__is_std_expected<_Up>::value, "The result of f() must be a specialization of std::expected"); + static_assert( + is_same_v, "The result of f() must have the same error_type as this expected"); + if (has_value()) { + return std::invoke(std::forward<_Func>(__f)); + } + return _Up(unexpect, error()); + } + + template + requires is_move_constructible_v<_Err> + _LIBCPP_HIDE_FROM_ABI constexpr auto and_then(_Func&& __f) && { + using _Up = remove_cvref_t>; + static_assert( + __expected::__is_std_expected<_Up>::value, "The result of f() must be a specialization of std::expected"); + static_assert( + is_same_v, "The result of f() must have the same error_type as this expected"); + if (has_value()) { + return std::invoke(std::forward<_Func>(__f)); + } + return _Up(unexpect, std::move(error())); + } + + template + requires is_move_constructible_v<_Err> + _LIBCPP_HIDE_FROM_ABI constexpr auto and_then(_Func&& __f) const&& { + using _Up = remove_cvref_t>; + static_assert( + __expected::__is_std_expected<_Up>::value, "The result of f() must be a specialization of std::expected"); + static_assert( + is_same_v, "The result of f() must have the same error_type as this expected"); + if (has_value()) { + return std::invoke(std::forward<_Func>(__f)); + } + return _Up(unexpect, std::move(error())); + } + + template + _LIBCPP_HIDE_FROM_ABI constexpr auto or_else(_Func&& __f) & { + using _Gp = remove_cvref_t>; + static_assert(__expected::__is_std_expected<_Gp>::value, + "The result of f(error()) must be a specialization of std::expected"); + static_assert(is_same_v, + "The result of f(error()) must have the same value_type as this expected"); + if (has_value()) { + return _Gp(); + } + return std::invoke(std::forward<_Func>(__f), error()); + } + + template + _LIBCPP_HIDE_FROM_ABI constexpr auto or_else(_Func&& __f) const& { + using _Gp = remove_cvref_t>; + static_assert(__expected::__is_std_expected<_Gp>::value, + "The result of f(error()) must be a specialization of std::expected"); + static_assert(is_same_v, + "The result of f(error()) must have the same value_type as this expected"); + if (has_value()) { + return _Gp(); + } + return std::invoke(std::forward<_Func>(__f), error()); + } + + template + _LIBCPP_HIDE_FROM_ABI constexpr auto or_else(_Func&& __f) && { + using _Gp = remove_cvref_t>; + static_assert(__expected::__is_std_expected<_Gp>::value, + "The result of f(std::move(error())) must be a specialization of std::expected"); + static_assert(is_same_v, + "The result of f(std::move(error())) must have the same value_type as this expected"); + if (has_value()) { + return _Gp(); + } + return std::invoke(std::forward<_Func>(__f), std::move(error())); + } + + template + _LIBCPP_HIDE_FROM_ABI constexpr auto or_else(_Func&& __f) const&& { + using _Gp = remove_cvref_t>; + static_assert(__expected::__is_std_expected<_Gp>::value, + "The result of f(std::move(error())) must be a specialization of std::expected"); + static_assert(is_same_v, + "The result of f(std::move(error())) must have the same value_type as this expected"); + if (has_value()) { + return _Gp(); + } + return std::invoke(std::forward<_Func>(__f), std::move(error())); + } + + template + requires is_copy_constructible_v<_Err> + _LIBCPP_HIDE_FROM_ABI constexpr auto transform(_Func&& __f) & { + using _Up = remove_cv_t>; + if (!has_value()) { + return expected<_Up, _Err>(unexpect, error()); + } + if constexpr (!is_void_v<_Up>) { + return expected<_Up, _Err>(__expected::__expected_construct_in_place_from_invoke_tag{}, std::forward<_Func>(__f)); + } else { + std::invoke(std::forward<_Func>(__f)); + return expected<_Up, _Err>(); + } + } + + template + requires is_copy_constructible_v<_Err> + _LIBCPP_HIDE_FROM_ABI constexpr auto transform(_Func&& __f) const& { + using _Up = remove_cv_t>; + if (!has_value()) { + return expected<_Up, _Err>(unexpect, error()); + } + if constexpr (!is_void_v<_Up>) { + return expected<_Up, _Err>(__expected::__expected_construct_in_place_from_invoke_tag{}, std::forward<_Func>(__f)); + } else { + std::invoke(std::forward<_Func>(__f)); + return expected<_Up, _Err>(); + } + } + + template + requires is_move_constructible_v<_Err> + _LIBCPP_HIDE_FROM_ABI constexpr auto transform(_Func&& __f) && { + using _Up = remove_cv_t>; + if (!has_value()) { + return expected<_Up, _Err>(unexpect, std::move(error())); + } + if constexpr (!is_void_v<_Up>) { + return expected<_Up, _Err>(__expected::__expected_construct_in_place_from_invoke_tag{}, std::forward<_Func>(__f)); + } else { + std::invoke(std::forward<_Func>(__f)); + return expected<_Up, _Err>(); + } + } + + template + requires is_move_constructible_v<_Err> + _LIBCPP_HIDE_FROM_ABI constexpr auto transform(_Func&& __f) const&& { + using _Up = remove_cv_t>; + if (!has_value()) { + return expected<_Up, _Err>(unexpect, std::move(error())); + } + if constexpr (!is_void_v<_Up>) { + return expected<_Up, _Err>(__expected::__expected_construct_in_place_from_invoke_tag{}, std::forward<_Func>(__f)); + } else { + std::invoke(std::forward<_Func>(__f)); + return expected<_Up, _Err>(); + } + } + + template + _LIBCPP_HIDE_FROM_ABI constexpr auto transform_error(_Func&& __f) & { + using _Gp = remove_cv_t>; + if (has_value()) { + return expected<_Tp, _Gp>(); + } + return expected<_Tp, _Gp>( + __expected::__expected_construct_unexpected_from_invoke_tag{}, std::forward<_Func>(__f), error()); + } + + template + _LIBCPP_HIDE_FROM_ABI constexpr auto transform_error(_Func&& __f) const& { + using _Gp = remove_cv_t>; + if (has_value()) { + return expected<_Tp, _Gp>(); + } + return expected<_Tp, _Gp>( + __expected::__expected_construct_unexpected_from_invoke_tag{}, std::forward<_Func>(__f), error()); + } + + template + _LIBCPP_HIDE_FROM_ABI constexpr auto transform_error(_Func&& __f) && { + using _Gp = remove_cv_t>; + if (has_value()) { + return expected<_Tp, _Gp>(); + } + return expected<_Tp, _Gp>( + __expected::__expected_construct_unexpected_from_invoke_tag{}, std::forward<_Func>(__f), std::move(error())); + } + + template + _LIBCPP_HIDE_FROM_ABI constexpr auto transform_error(_Func&& __f) const&& { + using _Gp = remove_cv_t>; + if (has_value()) { + return expected<_Tp, _Gp>(); + } + return expected<_Tp, _Gp>( + __expected::__expected_construct_unexpected_from_invoke_tag{}, std::forward<_Func>(__f), std::move(error())); + } + // [expected.void.eq], equality operators template requires is_void_v<_T2> @@ -948,6 +1458,11 @@ _LIBCPP_NO_UNIQUE_ADDRESS union __union_t { _LIBCPP_HIDE_FROM_ABI constexpr __union_t() : __empty_() {} + template + _LIBCPP_HIDE_FROM_ABI constexpr explicit __union_t( + __expected::__expected_construct_unexpected_from_invoke_tag, _Func&& __f, _Args&&... __args) + : __unex_(std::invoke(std::forward<_Func>(__f), std::forward<_Args>(__args)...)) {} + _LIBCPP_HIDE_FROM_ABI constexpr ~__union_t() requires(is_trivially_destructible_v<_Err>) = default; diff --git a/libcxx/include/version b/libcxx/include/version --- a/libcxx/include/version +++ b/libcxx/include/version @@ -82,7 +82,7 @@ __cpp_lib_exchange_function 201304L __cpp_lib_execution 201902L 201603L // C++17 -__cpp_lib_expected 202202L +__cpp_lib_expected 202211L __cpp_lib_filesystem 201703L __cpp_lib_format 202106L __cpp_lib_forward_like 202207L @@ -391,7 +391,7 @@ # undef __cpp_lib_constexpr_memory # define __cpp_lib_constexpr_memory 202202L // # define __cpp_lib_constexpr_typeinfo 202106L -# define __cpp_lib_expected 202202L +# define __cpp_lib_expected 202211L # define __cpp_lib_forward_like 202207L // # define __cpp_lib_invoke_r 202106L # define __cpp_lib_is_scoped_enum 202011L diff --git a/libcxx/test/libcxx/utilities/expected/expected.expected/and_then.mandates.verify.cpp b/libcxx/test/libcxx/utilities/expected/expected.expected/and_then.mandates.verify.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/libcxx/utilities/expected/expected.expected/and_then.mandates.verify.cpp @@ -0,0 +1,118 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 +// ADDITIONAL_COMPILE_FLAGS: -Xclang -verify-ignore-unexpected=error + +// Test the mandates +// template constexpr auto and_then(F&& f) &; +// Mandates: +// Let U be std::remove_cvref_t> +// U is a specialization of std::expected and std::is_same_v is true + +// template constexpr auto and_then(F&& f) const &; +// Mandates: +// Let U be std::remove_cvref_t> +// U is a specialization of std::expected and std::is_same_v is true + +// template constexpr auto and_then(F&& f) &&; +// Mandates: +// Let U be std::remove_cvref_t> +// U is a specialization of std::expected and std::is_same_v is true + +// template constexpr auto and_then(F&& f) const &&; +// Mandates: +// Let U be std::remove_cvref_t> +// U is a specialization of std::expected and std::is_same_v is true + +#include +#include + +struct NotSameAsInt {}; + +int lval_return_not_std_expected(int&) { return 0; } +int clval_return_not_std_expected(const int&) { return 0; } +int rval_return_not_std_expected(int&&) { return 0; } +int crval_return_not_std_expected(const int&&) { return 0; } + +std::expected lval_error_type_not_same_as_int(int&) { return {}; } +std::expected clval_error_type_not_same_as_int(const int&) { return {}; } +std::expected rval_error_type_not_same_as_int(int&&) { return {}; } +std::expected crval_error_type_not_same_as_int(const int&&) { return {}; } + +// clang-format off +void test() { + // Test & overload + { + // U is not a specialization of std::expected + { + std::expected f1(1); + f1.and_then(lval_return_not_std_expected); // expected-note{{in instantiation of function template specialization 'std::expected::and_then' requested here}} + // expected-error-re@*:* {{{{(static_assert|static assertion)}} failed {{.*}}The result of f(value()) must be a specialization of std::expected}} + } + + // !std::is_same_v + { + std::expected f1(1); + f1.and_then(lval_error_type_not_same_as_int); // expected-note{{in instantiation of function template specialization 'std::expected::and_then (&)(int &)>' requested here}} + // expected-error-re@*:* {{{{(static_assert|static assertion)}} failed {{.*}}The result of f(value()) must have the same error_type as this expected}} + } + } + + // Test const& overload + { + // U is not a specialization of std::expected + { + const std::expected f1(1); + f1.and_then(clval_return_not_std_expected); // expected-note{{in instantiation of function template specialization 'std::expected::and_then' requested here}} + // expected-error-re@*:* {{{{(static_assert|static assertion)}} failed {{.*}}The result of f(value()) must be a specialization of std::expected}} + } + + // !std::is_same_v + { + const std::expected f1(1); + f1.and_then(clval_error_type_not_same_as_int); // expected-note{{in instantiation of function template specialization 'std::expected::and_then (&)(const int &)>' requested here}} + // expected-error-re@*:* {{{{(static_assert|static assertion)}} failed {{.*}}The result of f(value()) must have the same error_type as this expected}} + } + } + + // Test && overload + { + // U is not a specialization of std::expected + { + std::expected f1(1); + std::move(f1).and_then(rval_return_not_std_expected); // expected-note{{in instantiation of function template specialization 'std::expected::and_then' requested here}} + // expected-error-re@*:* {{{{(static_assert|static assertion)}} failed {{.*}}The result of f(std::move(value())) must be a specialization of std::expected}} + } + + // !std::is_same_v + { + std::expected f1(1); + std::move(f1).and_then(rval_error_type_not_same_as_int); // expected-note{{in instantiation of function template specialization 'std::expected::and_then (&)(int &&)>' requested here}} + // expected-error-re@*:* {{{{(static_assert|static assertion)}} failed {{.*}}The result of f(std::move(value())) must have the same error_type as this expected}} + } + } + + // Test const&& overload + { + // U is not a specialization of std::expected + { + const std::expected f1(1); + std::move(f1).and_then(crval_return_not_std_expected); // expected-note{{in instantiation of function template specialization 'std::expected::and_then' requested here}} + // expected-error-re@*:* {{{{(static_assert|static assertion)}} failed {{.*}}The result of f(std::move(value())) must be a specialization of std::expected}} + } + + // !std::is_same_v + { + const std::expected f1(1); + std::move(f1).and_then(crval_error_type_not_same_as_int); // expected-note{{in instantiation of function template specialization 'std::expected::and_then (&)(const int &&)>' requested here}} + // expected-error-re@*:* {{{{(static_assert|static assertion)}} failed {{.*}}The result of f(std::move(value())) must have the same error_type as this expected}} + } + } +} +// clang-format on diff --git a/libcxx/test/libcxx/utilities/expected/expected.expected/error_or.mandates.verify.cpp b/libcxx/test/libcxx/utilities/expected/expected.expected/error_or.mandates.verify.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/libcxx/utilities/expected/expected.expected/error_or.mandates.verify.cpp @@ -0,0 +1,68 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 +// ADDITIONAL_COMPILE_FLAGS: -Xclang -verify-ignore-unexpected=error + +// Test the mandates +// template constexpr E error_or(G&&) const &; +// Mandates: is_copy_constructible_v is true and is_convertible_v is true. + +// template constexpr E error_or(G&&) &&; +// Mandates: is_move_constructible_v is true and is_convertible_v is true. + +#include +#include + +struct NonCopyable { + NonCopyable(int) {} + NonCopyable(const NonCopyable&) = delete; +}; + +struct NonMovable { + NonMovable(int) {} + NonMovable(NonMovable&&) = delete; +}; + +struct NotConvertibleFromInt {}; + +// clang-format off +void test() { + // const & overload + // !is_copy_constructible_v, + { + const std::expected f1(std::unexpect, 0); + f1.error_or(5); // expected-note{{in instantiation of function template specialization 'std::expected::error_or' requested here}} + // expected-error-re@*:* {{{{(static_assert|static assertion)}} failed {{.*}}error_type has to be copy constructible}} + } + + // const & overload + // !is_convertible_v + { + const std::expected f1(std::unexpect, NotConvertibleFromInt{}); + f1.error_or(5); // expected-note{{in instantiation of function template specialization 'std::expected::error_or' requested here}} + //expected-error-re@*:* {{{{(static_assert|static assertion)}} failed {{.*}}argument has to be convertible to error_type}} + } + + // && overload + // !is_move_constructible_v, + { + std::expected f1(std::unexpect, 0); + std::move(f1).error_or(5); // expected-note{{in instantiation of function template specialization 'std::expected::error_or' requested here}} + //expected-error-re@*:* {{{{(static_assert|static assertion)}} failed {{.*}}error_type has to be move constructible}} + } + + // && overload + // !is_convertible_v + { + std::expected f1(std::unexpect, NotConvertibleFromInt{}); + std::move(f1).error_or(5); // expected-note{{in instantiation of function template specialization 'std::expected::error_or' requested here}} + //expected-error-re@*:* {{{{(static_assert|static assertion)}} failed {{.*}}argument has to be convertible to error_type}} + } +} +// clang-format on diff --git a/libcxx/test/libcxx/utilities/expected/expected.expected/or_else.mandates.verify.cpp b/libcxx/test/libcxx/utilities/expected/expected.expected/or_else.mandates.verify.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/libcxx/utilities/expected/expected.expected/or_else.mandates.verify.cpp @@ -0,0 +1,118 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 +// ADDITIONAL_COMPILE_FLAGS: -Xclang -verify-ignore-unexpected=error + +// Test the mandates +// template constexpr auto or_else(F&& f) &; +// Mandates: +// Let G be std::remove_cvref_t> +// G is a specialization of std::expected and std::is_same_v is true + +// template constexpr auto or_else(F&& f) const &; +// Mandates: +// Let G be std::remove_cvref_t> +// G is a specialization of std::expected and std::is_same_v is true + +// template constexpr auto or_else(F&& f) &&; +// Mandates: +// Let G be std::remove_cvref_t> +// G is a specialization of std::expected and std::is_same_v is true + +// template constexpr auto or_else(F&& f) const &&; +// Mandates: +// Let G be std::remove_cvref_t> +// G is a specialization of std::expected and std::is_same_v is true + +#include +#include + +struct NotSameAsInt {}; + +int lval_return_not_std_expected(int&) { return 0; } +int clval_return_not_std_expected(const int&) { return 0; } +int rval_return_not_std_expected(int&&) { return 0; } +int crval_return_not_std_expected(const int&&) { return 0; } + +std::expected lval_error_type_not_same_as_int(int&) { return {}; } +std::expected clval_error_type_not_same_as_int(const int&) { return {}; } +std::expected rval_error_type_not_same_as_int(int&&) { return {}; } +std::expected crval_error_type_not_same_as_int(const int&&) { return {}; } + +// clang-format off +void test() { + // Test & overload + { + // G is not a specialization of std::expected + { + std::expected f1(std::unexpected(1)); + f1.or_else(lval_return_not_std_expected); // expected-note{{in instantiation of function template specialization 'std::expected::or_else' requested here}} + // expected-error-re@*:* {{{{(static_assert|static assertion)}} failed {{.*}}The result of f(error()) must be a specialization of std::expected}} + } + + // !std::is_same_v + { + std::expected f1(std::unexpected(1)); + f1.or_else(lval_error_type_not_same_as_int); // expected-note{{in instantiation of function template specialization 'std::expected::or_else (&)(int &)>' requested here}} + // expected-error-re@*:* {{{{(static_assert|static assertion)}} failed {{.*}}The result of f(error()) must have the same value_type as this expected}} + } + } + + // Test const& overload + { + // G is not a specialization of std::expected + { + const std::expected f1(std::unexpected(1)); + f1.or_else(clval_return_not_std_expected); // expected-note{{in instantiation of function template specialization 'std::expected::or_else' requested here}} + // expected-error-re@*:* {{{{(static_assert|static assertion)}} failed {{.*}}The result of f(error()) must be a specialization of std::expected}} + } + + // !std::is_same_v + { + const std::expected f1(std::unexpected(1)); + f1.or_else(clval_error_type_not_same_as_int); // expected-note{{in instantiation of function template specialization 'std::expected::or_else (&)(const int &)>' requested here}} + // expected-error-re@*:* {{{{(static_assert|static assertion)}} failed {{.*}}The result of f(error()) must have the same value_type as this expected}} + } + } + + // Test && overload + { + // G is not a specialization of std::expected + { + std::expected f1(std::unexpected(1)); + std::move(f1).or_else(rval_return_not_std_expected); // expected-note{{in instantiation of function template specialization 'std::expected::or_else' requested here}} + // expected-error-re@*:* {{{{(static_assert|static assertion)}} failed {{.*}}The result of f(std::move(error())) must be a specialization of std::expected}} + } + + // !std::is_same_v + { + std::expected f1(std::unexpected(1)); + std::move(f1).or_else(rval_error_type_not_same_as_int); // expected-note{{in instantiation of function template specialization 'std::expected::or_else (&)(int &&)>' requested here}} + // expected-error-re@*:* {{{{(static_assert|static assertion)}} failed {{.*}}The result of f(std::move(error())) must have the same value_type as this expected}} + } + } + + // Test const&& overload + { + // G is not a specialization of std::expected + { + const std::expected f1(std::unexpected(1)); + std::move(f1).or_else(crval_return_not_std_expected); // expected-note{{in instantiation of function template specialization 'std::expected::or_else' requested here}} + // expected-error-re@*:* {{{{(static_assert|static assertion)}} failed {{.*}}The result of f(std::move(error())) must be a specialization of std::expected}} + } + + // !std::is_same_v + { + const std::expected f1(std::unexpected(1)); + std::move(f1).or_else(crval_error_type_not_same_as_int); // expected-note{{in instantiation of function template specialization 'std::expected::or_else (&)(const int &&)>' requested here}} + // expected-error-re@*:* {{{{(static_assert|static assertion)}} failed {{.*}}The result of f(std::move(error())) must have the same value_type as this expected}} + } + } +} +// clang-format on diff --git a/libcxx/test/libcxx/utilities/expected/expected.void/and_then.mandates.verify.cpp b/libcxx/test/libcxx/utilities/expected/expected.void/and_then.mandates.verify.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/libcxx/utilities/expected/expected.void/and_then.mandates.verify.cpp @@ -0,0 +1,118 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 +// ADDITIONAL_COMPILE_FLAGS: -Xclang -verify-ignore-unexpected=error + +// Test the mandates +// template constexpr auto and_then(F&& f) &; +// Mandates: +// Let U be std::remove_cvref_t> +// U is a specialization of std::expected and std::is_same_v is true + +// template constexpr auto and_then(F&& f) const &; +// Mandates: +// Let U be std::remove_cvref_t> +// U is a specialization of std::expected and std::is_same_v is true + +// template constexpr auto and_then(F&& f) &&; +// Mandates: +// Let U be std::remove_cvref_t> +// U is a specialization of std::expected and std::is_same_v is true + +// template constexpr auto and_then(F&& f) const &&; +// Mandates: +// Let U be std::remove_cvref_t> +// U is a specialization of std::expected and std::is_same_v is true + +#include +#include + +struct NotSameAsInt {}; + +int lval_return_not_std_expected(void) { return 0; } +int clval_return_not_std_expected(void) { return 0; } +int rval_return_not_std_expected(void) { return 0; } +int crval_return_not_std_expected(void) { return 0; } + +std::expected lval_error_type_not_same_as_int(void) { return {}; } +std::expected clval_error_type_not_same_as_int(void) { return {}; } +std::expected rval_error_type_not_same_as_int(void) { return {}; } +std::expected crval_error_type_not_same_as_int(void) { return {}; } + +// clang-format off +void test() { + // Test & overload + { + // U is not a specialization of std::expected + { + std::expected f1; + f1.and_then(lval_return_not_std_expected); // expected-note{{in instantiation of function template specialization 'std::expected::and_then' requested here}} + // expected-error-re@*:* {{{{(static_assert|static assertion)}} failed {{.*}}The result of f() must be a specialization of std::expected}} + } + + // !std::is_same_v + { + std::expected f1; + f1.and_then(lval_error_type_not_same_as_int); // expected-note{{in instantiation of function template specialization 'std::expected::and_then (&)()>' requested here}} + // expected-error-re@*:* {{{{(static_assert|static assertion)}} failed {{.*}}The result of f() must have the same error_type as this expected}} + } + } + + // Test const& overload + { + // U is not a specialization of std::expected + { + const std::expected f1; + f1.and_then(clval_return_not_std_expected); // expected-note{{in instantiation of function template specialization 'std::expected::and_then' requested here}} + // expected-error-re@*:* {{{{(static_assert|static assertion)}} failed {{.*}}The result of f() must be a specialization of std::expected}} + } + + // !std::is_same_v + { + const std::expected f1; + f1.and_then(clval_error_type_not_same_as_int); // expected-note{{in instantiation of function template specialization 'std::expected::and_then (&)()>' requested here}} + // expected-error-re@*:* {{{{(static_assert|static assertion)}} failed {{.*}}The result of f() must have the same error_type as this expected}} + } + } + + // Test && overload + { + // U is not a specialization of std::expected + { + std::expected f1; + std::move(f1).and_then(rval_return_not_std_expected); // expected-note{{in instantiation of function template specialization 'std::expected::and_then' requested here}} + // expected-error-re@*:* {{{{(static_assert|static assertion)}} failed {{.*}}The result of f() must be a specialization of std::expected}} + } + + // !std::is_same_v + { + std::expected f1; + std::move(f1).and_then(rval_error_type_not_same_as_int); // expected-note{{in instantiation of function template specialization 'std::expected::and_then (&)()>' requested here}} + // expected-error-re@*:* {{{{(static_assert|static assertion)}} failed {{.*}}The result of f() must have the same error_type as this expected}} + } + } + + // Test const&& overload + { + // U is not a specialization of std::expected + { + const std::expected f1; + std::move(f1).and_then(crval_return_not_std_expected); // expected-note{{in instantiation of function template specialization 'std::expected::and_then' requested here}} + // expected-error-re@*:* {{{{(static_assert|static assertion)}} failed {{.*}}The result of f() must be a specialization of std::expected}} + } + + // !std::is_same_v + { + const std::expected f1; + std::move(f1).and_then(crval_error_type_not_same_as_int); // expected-note{{in instantiation of function template specialization 'std::expected::and_then (&)()>' requested here}} + // expected-error-re@*:* {{{{(static_assert|static assertion)}} failed {{.*}}The result of f() must have the same error_type as this expected}} + } + } +} +// clang-format on diff --git a/libcxx/test/libcxx/utilities/expected/expected.void/error_or.mandates.verify.cpp b/libcxx/test/libcxx/utilities/expected/expected.void/error_or.mandates.verify.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/libcxx/utilities/expected/expected.void/error_or.mandates.verify.cpp @@ -0,0 +1,68 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 +// ADDITIONAL_COMPILE_FLAGS: -Xclang -verify-ignore-unexpected=error + +// Test the mandates +// template constexpr E error_or(G&&) const &; +// Mandates: is_copy_constructible_v is true and is_convertible_v is true. + +// template constexpr E error_or(G&&) &&; +// Mandates: is_move_constructible_v is true and is_convertible_v is true. + +#include +#include + +struct NonCopyable { + NonCopyable(int) {} + NonCopyable(const NonCopyable&) = delete; +}; + +struct NonMovable { + NonMovable(int) {} + NonMovable(NonMovable&&) = delete; +}; + +struct NotConvertibleFromInt {}; + +// clang-format off +void test() { + // const & overload + // !is_copy_constructible_v, + { + const std::expected f1(std::unexpect, 0); + f1.error_or(5); // expected-note{{in instantiation of function template specialization 'std::expected::error_or' requested here}} + // expected-error-re@*:* {{{{(static_assert|static assertion)}} failed {{.*}}error_type has to be copy constructible}} + } + + // const & overload + // !is_convertible_v + { + const std::expected f1(std::unexpect, NotConvertibleFromInt{}); + f1.error_or(5); // expected-note{{in instantiation of function template specialization 'std::expected::error_or' requested here}} + //expected-error-re@*:* {{{{(static_assert|static assertion)}} failed {{.*}}argument has to be convertible to error_type}} + } + + // && overload + // !is_move_constructible_v, + { + std::expected f1(std::unexpect, 0); + std::move(f1).error_or(5); // expected-note{{in instantiation of function template specialization 'std::expected::error_or' requested here}} + //expected-error-re@*:* {{{{(static_assert|static assertion)}} failed {{.*}}error_type has to be move constructible}} + } + + // && overload + // !is_convertible_v + { + std::expected f1(std::unexpect, NotConvertibleFromInt{}); + std::move(f1).error_or(5); // expected-note{{in instantiation of function template specialization 'std::expected::error_or' requested here}} + //expected-error-re@*:* {{{{(static_assert|static assertion)}} failed {{.*}}argument has to be convertible to error_type}} + } +} +// clang-format on diff --git a/libcxx/test/libcxx/utilities/expected/expected.void/or_else.mandates.verify.cpp b/libcxx/test/libcxx/utilities/expected/expected.void/or_else.mandates.verify.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/libcxx/utilities/expected/expected.void/or_else.mandates.verify.cpp @@ -0,0 +1,118 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 +// ADDITIONAL_COMPILE_FLAGS: -Xclang -verify-ignore-unexpected=error + +// Test the mandates +// template constexpr auto or_else(F&& f) &; +// Mandates: +// Let G be std::remove_cvref_t> +// G is a specialization of std::expected and std::is_same_v is true + +// template constexpr auto or_else(F&& f) const &; +// Mandates: +// Let G be std::remove_cvref_t> +// G is a specialization of std::expected and std::is_same_v is true + +// template constexpr auto or_else(F&& f) &&; +// Mandates: +// Let G be std::remove_cvref_t> +// G is a specialization of std::expected and std::is_same_v is true + +// template constexpr auto or_else(F&& f) const &&; +// Mandates: +// Let G be std::remove_cvref_t> +// G is a specialization of std::expected and std::is_same_v is true + +#include +#include + +struct NotSameAsInt {}; + +int lval_return_not_std_expected(int&) { return 0; } +int clval_return_not_std_expected(const int&) { return 0; } +int rval_return_not_std_expected(int&&) { return 0; } +int crval_return_not_std_expected(const int&&) { return 0; } + +std::expected lval_error_type_not_same_as_int(int&) { return {}; } +std::expected clval_error_type_not_same_as_int(const int&) { return {}; } +std::expected rval_error_type_not_same_as_int(int&&) { return {}; } +std::expected crval_error_type_not_same_as_int(const int&&) { return {}; } + +// clang-format off +void test() { + // Test & overload + { + // G is not a specialization of std::expected + { + std::expected f1(std::unexpected(1)); + f1.or_else(lval_return_not_std_expected); // expected-note{{in instantiation of function template specialization 'std::expected::or_else' requested here}} + // expected-error-re@*:* {{{{(static_assert|static assertion)}} failed {{.*}}The result of f(error()) must be a specialization of std::expected}} + } + + // !std::is_same_v + { + std::expected f1(std::unexpected(1)); + f1.or_else(lval_error_type_not_same_as_int); // expected-note{{in instantiation of function template specialization 'std::expected::or_else (&)(int &)>' requested here}} + // expected-error-re@*:* {{{{(static_assert|static assertion)}} failed {{.*}}The result of f(error()) must have the same value_type as this expected}} + } + } + + // Test const& overload + { + // G is not a specialization of std::expected + { + const std::expected f1(std::unexpected(1)); + f1.or_else(clval_return_not_std_expected); // expected-note{{in instantiation of function template specialization 'std::expected::or_else' requested here}} + // expected-error-re@*:* {{{{(static_assert|static assertion)}} failed {{.*}}The result of f(error()) must be a specialization of std::expected}} + } + + // !std::is_same_v + { + const std::expected f1(std::unexpected(1)); + f1.or_else(clval_error_type_not_same_as_int); // expected-note{{in instantiation of function template specialization 'std::expected::or_else (&)(const int &)>' requested here}} + // expected-error-re@*:* {{{{(static_assert|static assertion)}} failed {{.*}}The result of f(error()) must have the same value_type as this expected}} + } + } + + // Test && overload + { + // G is not a specialization of std::expected + { + std::expected f1(std::unexpected(1)); + std::move(f1).or_else(rval_return_not_std_expected); // expected-note{{in instantiation of function template specialization 'std::expected::or_else' requested here}} + // expected-error-re@*:* {{{{(static_assert|static assertion)}} failed {{.*}}The result of f(std::move(error())) must be a specialization of std::expected}} + } + + // !std::is_same_v + { + std::expected f1(std::unexpected(1)); + std::move(f1).or_else(rval_error_type_not_same_as_int); // expected-note{{in instantiation of function template specialization 'std::expected::or_else (&)(int &&)>' requested here}} + // expected-error-re@*:* {{{{(static_assert|static assertion)}} failed {{.*}}The result of f(std::move(error())) must have the same value_type as this expected}} + } + } + + // Test const&& overload + { + // G is not a specialization of std::expected + { + const std::expected f1(std::unexpected(1)); + std::move(f1).or_else(crval_return_not_std_expected); // expected-note{{in instantiation of function template specialization 'std::expected::or_else' requested here}} + // expected-error-re@*:* {{{{(static_assert|static assertion)}} failed {{.*}}The result of f(std::move(error())) must be a specialization of std::expected}} + } + + // !std::is_same_v + { + const std::expected f1(std::unexpected(1)); + std::move(f1).or_else(crval_error_type_not_same_as_int); // expected-note{{in instantiation of function template specialization 'std::expected::or_else (&)(const int &&)>' requested here}} + // expected-error-re@*:* {{{{(static_assert|static assertion)}} failed {{.*}}The result of f(std::move(error())) must have the same value_type as this expected}} + } + } +} +// clang-format on diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/expected.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/expected.version.compile.pass.cpp --- a/libcxx/test/std/language.support/support.limits/support.limits.general/expected.version.compile.pass.cpp +++ b/libcxx/test/std/language.support/support.limits/support.limits.general/expected.version.compile.pass.cpp @@ -16,7 +16,7 @@ // Test the feature test macros defined by /* Constant Value - __cpp_lib_expected 202202L [C++2b] + __cpp_lib_expected 202211L [C++2b] */ #include @@ -51,8 +51,8 @@ # ifndef __cpp_lib_expected # error "__cpp_lib_expected should be defined in c++2b" # endif -# if __cpp_lib_expected != 202202L -# error "__cpp_lib_expected should have the value 202202L in c++2b" +# if __cpp_lib_expected != 202211L +# error "__cpp_lib_expected should have the value 202211L in c++2b" # endif #endif // TEST_STD_VER > 20 diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp --- a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp +++ b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp @@ -76,7 +76,7 @@ __cpp_lib_exchange_function 201304L [C++14] __cpp_lib_execution 201603L [C++17] 201902L [C++20] - __cpp_lib_expected 202202L [C++2b] + __cpp_lib_expected 202211L [C++2b] __cpp_lib_filesystem 201703L [C++17] __cpp_lib_format 202106L [C++20] __cpp_lib_forward_like 202207L [C++2b] @@ -4079,8 +4079,8 @@ # ifndef __cpp_lib_expected # error "__cpp_lib_expected should be defined in c++2b" # endif -# if __cpp_lib_expected != 202202L -# error "__cpp_lib_expected should have the value 202202L in c++2b" +# if __cpp_lib_expected != 202211L +# error "__cpp_lib_expected should have the value 202211L in c++2b" # endif # if !defined(_LIBCPP_AVAILABILITY_DISABLE_FTM___cpp_lib_filesystem) diff --git a/libcxx/test/std/utilities/expected/expected.expected/monadic/and_then.pass.cpp b/libcxx/test/std/utilities/expected/expected.expected/monadic/and_then.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/expected/expected.expected/monadic/and_then.pass.cpp @@ -0,0 +1,282 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template constexpr auto and_then(F&& f) &; +// template constexpr auto and_then(F&& f) const &; +// template constexpr auto and_then(F&& f) &&; +// template constexpr auto and_then(F&& f) const &&; + +#include +#include +#include +#include + +struct LVal { + constexpr std::expected operator()(int&) { return 1; } + std::expected operator()(const int&) = delete; + std::expected operator()(int&&) = delete; + std::expected operator()(const int&&) = delete; +}; + +struct CLVal { + std::expected operator()(int&) = delete; + constexpr std::expected operator()(const int&) { return 1; } + std::expected operator()(int&&) = delete; + std::expected operator()(const int&&) = delete; +}; + +struct RVal { + std::expected operator()(int&) = delete; + std::expected operator()(const int&) = delete; + constexpr std::expected operator()(int&&) { return 1; } + std::expected operator()(const int&&) = delete; +}; + +struct CRVal { + std::expected operator()(int&) = delete; + std::expected operator()(const int&) = delete; + std::expected operator()(int&&) = delete; + constexpr std::expected operator()(const int&&) { return 1; } +}; + +struct RefQual { + constexpr std::expected operator()(int) & { return 1; } + std::expected operator()(int) const& = delete; + std::expected operator()(int) && = delete; + std::expected operator()(int) const&& = delete; +}; + +struct CRefQual { + std::expected operator()(int) & = delete; + constexpr std::expected operator()(int) const& { return 1; } + std::expected operator()(int) && = delete; + std::expected operator()(int) const&& = delete; +}; + +struct RVRefQual { + std::expected operator()(int) & = delete; + std::expected operator()(int) const& = delete; + constexpr std::expected operator()(int) && { return 1; } + std::expected operator()(int) const&& = delete; +}; + +struct RVCRefQual { + std::expected operator()(int) & = delete; + std::expected operator()(int) const& = delete; + std::expected operator()(int) && = delete; + constexpr std::expected operator()(int) const&& { return 1; } +}; + +struct NOLVal { + constexpr std::expected operator()(int&) { return std::expected(std::unexpected(5)); } + std::expected operator()(const int&) = delete; + std::expected operator()(int&&) = delete; + std::expected operator()(const int&&) = delete; +}; + +struct NOCLVal { + std::expected operator()(int&) = delete; + constexpr std::expected operator()(const int&) { return std::expected(std::unexpected(5)); } + std::expected operator()(int&&) = delete; + std::expected operator()(const int&&) = delete; +}; + +struct NORVal { + std::expected operator()(int&) = delete; + std::expected operator()(const int&) = delete; + constexpr std::expected operator()(int&&) { return std::expected(std::unexpected(5)); } + std::expected operator()(const int&&) = delete; +}; + +struct NOCRVal { + std::expected operator()(int&) = delete; + std::expected operator()(const int&) = delete; + std::expected operator()(int&&) = delete; + constexpr std::expected operator()(const int&&) { return std::expected(std::unexpected(5)); } +}; + +struct NORefQual { + constexpr std::expected operator()(int) & { return std::expected(std::unexpected(5)); } + std::expected operator()(int) const& = delete; + std::expected operator()(int) && = delete; + std::expected operator()(int) const&& = delete; +}; + +struct NOCRefQual { + std::expected operator()(int) & = delete; + constexpr std::expected operator()(int) const& { return std::expected(std::unexpected(5)); } + std::expected operator()(int) && = delete; + std::expected operator()(int) const&& = delete; +}; + +struct NORVRefQual { + std::expected operator()(int) & = delete; + std::expected operator()(int) const& = delete; + constexpr std::expected operator()(int) && { return std::expected(std::unexpected(5)); } + std::expected operator()(int) const&& = delete; +}; + +struct NORVCRefQual { + std::expected operator()(int) & = delete; + std::expected operator()(int) const& = delete; + std::expected operator()(int) && = delete; + constexpr std::expected operator()(int) const&& { return std::expected(std::unexpected(5)); } +}; + +struct NonCopyable { + constexpr NonCopyable(int) {} + NonCopyable(const NonCopyable&) = delete; +}; + +struct NonMovable { + constexpr NonMovable(int) {} + NonMovable(NonMovable&&) = delete; +}; + +struct NonConst { + std::expected non_const() { return 1; } +}; + +template +concept has_and_then = requires(E&& e, F&& f) { + {std::forward(e).and_then(std::forward(f))}; +}; + +static_assert( has_and_then&, decltype([](int&)->std::expected { return 0; })>); +static_assert(!has_and_then&, decltype([](int&)->std::expected { return 0; })>); +static_assert( has_and_then&, decltype([](const int&)->std::expected { return 0; })>); +static_assert(!has_and_then&, decltype([](const int&)->std::expected { return 0; })>); +static_assert( has_and_then&&, decltype([](int)->std::expected { return 0; })>); +static_assert(!has_and_then&&, decltype([](int)->std::expected { return 0; })>); +static_assert( has_and_then&&, decltype([](const int)->std::expected { return 0; })>); +static_assert(!has_and_then&&, decltype([](const int)->std::expected { return 0; })>); + +// clang-format off +constexpr void test_val_types() { + // Test & overload + { + // Without &qualifier on F'soperator() + { + std::expected e{0}; + assert(e.and_then(LVal{}).value() == 1); + assert(e.and_then(NOLVal{}).error() == 5); + static_assert(std::is_same_v>); + } + + // With & qualifier on F's operator() + { + std::expected e{0}; + RefQual l{}; + assert(e.and_then(l) == 1); + NORefQual nl{}; + assert(e.and_then(nl).error() == 5); + static_assert(std::is_same_v>); + } + } + + // Test const& overload + { + // Without & qualifier on F's operator() + { + const std::expected e{0}; + assert(e.and_then(CLVal{}).value() == 1); + assert(e.and_then(NOCLVal{}).error() == 5); + static_assert(std::is_same_v>); + } + + // With & qualifier on F's operator() + { + const std::expected e{0}; + const CRefQual l{}; + assert(e.and_then(l) == 1); + const NOCRefQual nl{}; + assert(e.and_then(nl).error() == 5); + static_assert(std::is_same_v>); + } + } + + // Test && overload + { + // Without & qualifier on F's operator() + { + std::expected e{0}; + assert(std::move(e).and_then(RVal{}) == 1); + assert(std::move(e).and_then(NORVal{}).error() == 5); + static_assert(std::is_same_v>); + } + + // With & qualifier on F's operator() + { + std::expected e{0}; + assert(e.and_then(RVRefQual{}) == 1); + assert(e.and_then(NORVRefQual{}).error() == 5); + static_assert(std::is_same_v>); + } + } + + // Test const&& overload + { + // Without & qualifier on F's operator() + { + const std::expected e{0}; + assert(std::move(e).and_then(CRVal{}) == 1); + assert(std::move(e).and_then(NOCRVal{}).error() == 5); + static_assert(std::is_same_v>); + } + + // With & qualifier on F's operator() + { + const std::expected e{0}; + const RVCRefQual l{}; + assert(std::move(e).and_then(std::move(l)) == 1); + const NORVCRefQual nl{}; + assert(std::move(e).and_then(std::move(nl)).error() == 5); + static_assert(std::is_same_v>); + } + } +} +// clang-format on + +// check that the lambda body is not instantiated during overload resolution +constexpr void test_sfinae() { + std::expected e(std::unexpected(2)); + auto l = [](auto&& x) { return x.non_const(); }; + e.and_then(l); + std::move(e).and_then(l); +} + +constexpr bool test() { + test_sfinae(); + test_val_types(); + + std::expected e(std::unexpected(1)); + const auto& ce = e; + + const auto never_called = [](int) { + assert(false); + return std::expected(); + }; + + e.and_then(never_called); + std::move(e).and_then(never_called); + ce.and_then(never_called); + std::move(ce).and_then(never_called); + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/utilities/expected/expected.expected/monadic/or_else.pass.cpp b/libcxx/test/std/utilities/expected/expected.expected/monadic/or_else.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/expected/expected.expected/monadic/or_else.pass.cpp @@ -0,0 +1,190 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template constexpr auto or_else(F&& f) &; +// template constexpr auto or_else(F&& f) const &; +// template constexpr auto or_else(F&& f) &&; +// template constexpr auto or_else(F&& f) const &&; + +#include +#include +#include +#include + +struct LVal { + constexpr std::expected operator()(int&) { return 1; } + std::expected operator()(const int&) = delete; + std::expected operator()(int&&) = delete; + std::expected operator()(const int&&) = delete; +}; + +struct CLVal { + std::expected operator()(int&) = delete; + constexpr std::expected operator()(const int&) { return 1; } + std::expected operator()(int&&) = delete; + std::expected operator()(const int&&) = delete; +}; + +struct RVal { + std::expected operator()(int&) = delete; + std::expected operator()(const int&) = delete; + constexpr std::expected operator()(int&&) { return 1; } + std::expected operator()(const int&&) = delete; +}; + +struct CRVal { + std::expected operator()(int&) = delete; + std::expected operator()(const int&) = delete; + std::expected operator()(int&&) = delete; + constexpr std::expected operator()(const int&&) { return 1; } +}; + +struct RefQual { + constexpr std::expected operator()(int) & { return 1; } + std::expected operator()(int) const& = delete; + std::expected operator()(int) && = delete; + std::expected operator()(int) const&& = delete; +}; + +struct CRefQual { + std::expected operator()(int) & = delete; + constexpr std::expected operator()(int) const& { return 1; } + std::expected operator()(int) && = delete; + std::expected operator()(int) const&& = delete; +}; + +struct RVRefQual { + std::expected operator()(int) & = delete; + std::expected operator()(int) const& = delete; + constexpr std::expected operator()(int) && { return 1; } + std::expected operator()(int) const&& = delete; +}; + +struct RVCRefQual { + std::expected operator()(int) & = delete; + std::expected operator()(int) const& = delete; + std::expected operator()(int) && = delete; + constexpr std::expected operator()(int) const&& { return 1; } +}; + +// clang-format off +constexpr void test_val_types() { + // Test & overload + { + // Without & qualifier on F's operator() + { + std::expected e(std::unexpected(0)); + assert(e.or_else(LVal{}) == 1); + static_assert(std::is_same_v>); + } + + // With & qualifier on F's operator + { + std::expected e(std::unexpected(0)); + RefQual l{}; + assert(e.or_else(l) == 1); + static_assert(std::is_same_v>); + } + } + + // Test const& overload + { + // Without const& qualifier on F's operator() + { + const std::expected e(std::unexpected(0)); + assert(e.or_else(CLVal{}) == 1); + static_assert(std::is_same_v>); + } + + // With const& qualifier on F's operator() + { + const std::expected e(std::unexpected(0)); + const CRefQual l{}; + assert(e.or_else(l) == 1); + static_assert(std::is_same_v>); + } + } + + // Test && overload + { + // Without && qualifier on F's operator() + { + std::expected e(std::unexpected(0)); + assert(std::move(e).or_else(RVal{}) == 1); + static_assert(std::is_same_v>); + } + + // With && qualifier on F's operator() + { + std::expected e(std::unexpected(0)); + assert(std::move(e).or_else(RVRefQual{}) == 1); + static_assert(std::is_same_v>); + } + } + + // Test const&& overload + { + // Without const&& qualifier on F's operator() + { + const std::expected e(std::unexpected(0)); + assert(std::move(e).or_else(CRVal{}) == 1); + static_assert(std::is_same_v>); + } + + // With const&& qualifier on F's operator() + { + const std::expected e(std::unexpected(0)); + const RVCRefQual l{}; + assert(std::move(e).or_else(std::move(l)) == 1); + static_assert(std::is_same_v>); + } + } +} +// clang-format on + +struct NonConst { + std::expected non_const() { return std::expected(std::unexpect, 1); } +}; + +// check that the lambda body is not instantiated during overload resolution +constexpr void test_sfinae() { + std::expected e{1}; + auto l = [](auto&& x) { return x.non_const(); }; + e.or_else(l); + std::move(e).or_else(l); +} + +constexpr bool test() { + test_sfinae(); + test_val_types(); + + std::expected e(1); + const auto& ce = e; + + const auto never_called = [](int) { + assert(false); + return std::expected(); + }; + + e.or_else(never_called); + std::move(e).or_else(never_called); + ce.or_else(never_called); + std::move(ce).or_else(never_called); + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/utilities/expected/expected.expected/monadic/transform.pass.cpp b/libcxx/test/std/utilities/expected/expected.expected/monadic/transform.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/expected/expected.expected/monadic/transform.pass.cpp @@ -0,0 +1,238 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// GCC has a bug, please refer to: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108333 +// XFAIL: gcc + +// + +// template constexpr auto transform(F&& f) &; +// template constexpr auto transform(F&& f) const &; +// template constexpr auto transform(F&& f) &&; +// template constexpr auto transform(F&& f) const &&; + +#include +#include +#include +#include + +struct LVal { + constexpr int operator()(int&) { return 1; } + int operator()(const int&) = delete; + int operator()(int&&) = delete; + int operator()(const int&&) = delete; +}; + +struct CLVal { + int operator()(int&) = delete; + constexpr int operator()(const int&) { return 1; } + int operator()(int&&) = delete; + int operator()(const int&&) = delete; +}; + +struct RVal { + int operator()(int&) = delete; + int operator()(const int&) = delete; + constexpr int operator()(int&&) { return 1; } + int operator()(const int&&) = delete; +}; + +struct CRVal { + int operator()(int&) = delete; + int operator()(const int&) = delete; + int operator()(int&&) = delete; + constexpr int operator()(const int&&) { return 1; } +}; + +struct RefQual { + constexpr int operator()(int) & { return 1; } + int operator()(int) const& = delete; + int operator()(int) && = delete; + int operator()(int) const&& = delete; +}; + +struct CRefQual { + int operator()(int) & = delete; + constexpr int operator()(int) const& { return 1; } + int operator()(int) && = delete; + int operator()(int) const&& = delete; +}; + +struct RVRefQual { + int operator()(int) & = delete; + int operator()(int) const& = delete; + constexpr int operator()(int) && { return 1; } + int operator()(int) const&& = delete; +}; + +struct RVCRefQual { + int operator()(int) & = delete; + int operator()(int) const& = delete; + int operator()(int) && = delete; + constexpr int operator()(int) const&& { return 1; } +}; + +struct NonCopy { + int value; + constexpr explicit NonCopy(int val) : value(val) {} + NonCopy(const NonCopy&) = delete; +}; + +struct NonConst { + int non_const() { return 1; } +}; + +// clang-format off +constexpr void test_val_types() { + // Test & overload + { + // Without &qualifier on F'soperator() + { + std::expected e(0); + assert(e.transform(LVal{}).value() == 1); + static_assert(std::is_same_v>); + } + + // With & qualifier on F's operator() + { + std::expected e(0); + RefQual l{}; + assert(e.transform(l) == 1); + static_assert(std::is_same_v>); + } + } + + // Test const& overload + { + // Without & qualifier on F's operator() + { + const std::expected e(0); + assert(e.transform(CLVal{}).value() == 1); + static_assert(std::is_same_v>); + } + + // With & qualifier on F's operator() + { + const std::expected e(0); + const CRefQual l{}; + assert(e.transform(l).value() == 1); + static_assert(std::is_same_v>); + } + } + + // Test && overload + { + // Without & qualifier on F's operator() + { + std::expected e(0); + assert(std::move(e).transform(RVal{}).value() == 1); + static_assert(std::is_same_v>); + } + + // With & qualifier on F's operator() + { + std::expected e(0); + assert(e.transform(RVRefQual{}).value() == 1); + static_assert(std::is_same_v>); + } + } + + // Test const&& overload + { + // Without & qualifier on F's operator() + { + const std::expected e(0); + assert(std::move(e).transform(CRVal{}) == 1); + static_assert(std::is_same_v>); + } + + // With & qualifier on F's operator() + { + const std::expected e(0); + const RVCRefQual l{}; + assert(e.transform(std::move(l)) == 1); + static_assert(std::is_same_v>); + } + } +} +// clang-format on + +constexpr void test_take_val_return_void() { + std::expected e(1); + int val = 0; + e.transform([&val](T&&) -> void { + static_assert(std::is_same_v); + assert(val == 0); + val = 1; + }); + assert(val == 1); + std::move(e).transform([&val](T&&) -> void { + static_assert(std::is_same_v); + assert(val == 1); + val = 2; + }); + + const auto& ce = e; + assert(val == 2); + ce.transform([&val](T&&) -> void { + static_assert(std::is_same_v); + assert(val == 2); + val = 3; + }); + assert(val == 3); + std::move(ce).transform([&val](T&&) -> void { + static_assert(std::is_same_v); + assert(val == 3); + val = 4; + }); + assert(val == 4); +} + +// check val member is direct-non-list-initialized with invoke(std::forward(f), value()) +constexpr void test_direct_non_list_init() { + auto xform = [](int i) { return NonCopy(i); }; + std::expected e(2); + std::expected n = e.transform(xform); + assert(n.value().value == 2); +} + +// check that the lambda body is not instantiated during overload resolution +constexpr void test_sfinae() { + std::expected e(std::unexpected(2)); + auto l = [](auto&& x) { return x.non_const(); }; + e.transform(l); + std::move(e).transform(l); + + std::expected e1(std::unexpected(1)); + const auto& ce1 = e1; + const auto never_called = [](int) { + assert(false); + return std::expected(); + }; + + e1.transform(never_called); + std::move(e1).transform(never_called); + ce1.and_then(never_called); + std::move(ce1).transform(never_called); +} + +constexpr bool test() { + test_sfinae(); + test_val_types(); + test_direct_non_list_init(); + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/utilities/expected/expected.expected/monadic/transform_error.pass.cpp b/libcxx/test/std/utilities/expected/expected.expected/monadic/transform_error.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/expected/expected.expected/monadic/transform_error.pass.cpp @@ -0,0 +1,208 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// GCC has a bug, please refer to: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108333 +// XFAIL: gcc + +// + +// template constexpr auto transform_error(F&& f) &; +// template constexpr auto transform_error(F&& f) const &; +// template constexpr auto transform_error(F&& f) &&; +// template constexpr auto transform_error(F&& f) const &&; + +#include +#include +#include +#include + +struct LVal { + constexpr int operator()(int&) { return 1; } + int operator()(const int&) = delete; + int operator()(int&&) = delete; + int operator()(const int&&) = delete; +}; + +struct CLVal { + int operator()(int&) = delete; + constexpr int operator()(const int&) { return 1; } + int operator()(int&&) = delete; + int operator()(const int&&) = delete; +}; + +struct RVal { + int operator()(int&) = delete; + int operator()(const int&) = delete; + constexpr int operator()(int&&) { return 1; } + int operator()(const int&&) = delete; +}; + +struct CRVal { + int operator()(int&) = delete; + int operator()(const int&) = delete; + int operator()(int&&) = delete; + constexpr int operator()(const int&&) { return 1; } +}; + +struct RefQual { + constexpr int operator()(int) & { return 1; } + int operator()(int) const& = delete; + int operator()(int) && = delete; + int operator()(int) const&& = delete; +}; + +struct CRefQual { + int operator()(int) & = delete; + constexpr int operator()(int) const& { return 1; } + int operator()(int) && = delete; + int operator()(int) const&& = delete; +}; + +struct RVRefQual { + int operator()(int) & = delete; + int operator()(int) const& = delete; + constexpr int operator()(int) && { return 1; } + int operator()(int) const&& = delete; +}; + +struct RVCRefQual { + int operator()(int) & = delete; + int operator()(int) const& = delete; + int operator()(int) && = delete; + constexpr int operator()(int) const&& { return 1; } +}; + +struct NonCopy { + int value; + constexpr explicit NonCopy(int val) : value(val) {} + NonCopy(const NonCopy&) = delete; +}; + +struct NonConst { + int non_const() { return 1; } +}; + +// clang-format off +constexpr void test_val_types() { + // Test & overload + { + // Without & qualifier on F's operator() + { + std::expected e(std::unexpected(0)); + assert(e.transform_error(LVal{}).error() == 1); + static_assert(std::is_same_v>); + } + + // With & qualifier on F's operator() + { + std::expected e(std::unexpected(0)); + RefQual l{}; + assert(e.transform_error(l).error() == 1); + static_assert(std::is_same_v>); + } + } + + // Test const& overload + { + // Without const& qualifier on F's operator() + { + const std::expected e(std::unexpected(0)); + assert(e.transform_error(CLVal{}).error() == 1); + static_assert(std::is_same_v>); + } + + // With const& qualifier on F's operator() + { + const std::expected e(std::unexpected(0)); + const CRefQual l{}; + assert(e.transform_error(l).error() == 1); + static_assert(std::is_same_v>); + } + } + + // Test && overload + { + // Without && qualifier on F's operator() + { + std::expected e(std::unexpected(0)); + assert(std::move(e).transform_error(RVal{}).error() == 1); + static_assert(std::is_same_v>); + } + + // With && qualifier on F's operator() + { + std::expected e(std::unexpected(0)); + assert(std::move(e).transform_error(RVRefQual{}).error() == 1); + static_assert(std::is_same_v>); + } + } + + // Test const&& overload + { + // Without const&& qualifier on F's operator() + { + const std::expected e(std::unexpected(0)); + assert(std::move(e).transform_error(CRVal{}).error() == 1); + static_assert(std::is_same_v>); + } + + // With const&& qualifier on F's operator() + { + const std::expected e(std::unexpected(0)); + const RVCRefQual l{}; + assert(std::move(e).transform_error(std::move(l)).error() == 1); + static_assert(std::is_same_v>); + } + } +} +// clang-format on + +// check unex member is direct-non-list-initialized with invoke(std::forward(f), error()) +constexpr void test_direct_non_list_init() { + auto xform = [](int i) { return NonCopy(i); }; + std::expected e(std::unexpected(2)); + std::expected n = e.transform_error(xform); + assert(n.error().value == 2); +} + +// check that the lambda body is not instantiated during overload resolution +constexpr void test_sfinae() { + std::expected e(2); + auto l = [](auto&& x) { return x.non_const(); }; + e.transform_error(l); + std::move(e).transform_error(l); + + std::expected e1; + const auto& ce1 = e1; + + const auto never_called = [](int) { + assert(false); + return 0; + }; + + e1.transform_error(never_called); + std::move(e1).transform_error(never_called); + ce1.transform_error(never_called); + std::move(ce1).transform_error(never_called); +} + +constexpr bool test() { + test_sfinae(); + test_val_types(); + test_direct_non_list_init(); + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/utilities/expected/expected.expected/observers/error_or.pass.cpp b/libcxx/test/std/utilities/expected/expected.expected/observers/error_or.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/expected/expected.expected/observers/error_or.pass.cpp @@ -0,0 +1,96 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// template constexpr E error_or(G&& e) const &; +// template constexpr E error_or(G&& e) &&; + +#include +#include +#include +#include +#include + +struct ConstructFromInt { + int value; + constexpr ConstructFromInt(int v) : value(v) {} +}; + +constexpr bool test_default_template_arg() { + // const &, has_value() + { + const std::expected e(5); + std::same_as decltype(auto) x = e.error_or(10); + assert(x.value == 10); + } + + // const &, !has_value() + { + const std::expected e(std::unexpect, 5); + std::same_as decltype(auto) x = e.error_or(10); + assert(x.value == 5); + } + + // &&, has_value() + { + const std::expected e(5); + std::same_as decltype(auto) x = std::move(e).error_or(10); + assert(x.value == 10); + } + + // &&, !has_value() + { + const std::expected e(std::unexpect, 5); + std::same_as decltype(auto) x = std::move(e).error_or(10); + assert(x.value == 5); + } + + return true; +} + +constexpr bool test() { + // const &, has_value() + { + const std::expected e(5); + std::same_as decltype(auto) x = e.error_or(10); + assert(x == 10); + } + + // const &, !has_value() + { + const std::expected e(std::unexpect, 5); + std::same_as decltype(auto) x = e.error_or(10); + assert(x == 5); + } + + // &&, has_value() + { + std::expected e(5); + std::same_as decltype(auto) x = std::move(e).error_or(10); + assert(x == 10); + } + + // &&, !has_value() + { + std::expected e(std::unexpect, 5); + std::same_as decltype(auto) x = std::move(e).error_or(10); + assert(x == 5); + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + test_default_template_arg(); + static_assert(test_default_template_arg()); + + return 0; +} diff --git a/libcxx/test/std/utilities/expected/expected.void/monadic/and_then.pass.cpp b/libcxx/test/std/utilities/expected/expected.void/monadic/and_then.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/expected/expected.void/monadic/and_then.pass.cpp @@ -0,0 +1,131 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template constexpr auto and_then(F&& f) &; +// template constexpr auto and_then(F&& f) const &; +// template constexpr auto and_then(F&& f) &&; +// template constexpr auto and_then(F&& f) const &&; + +#include +#include +#include +#include + +struct NonCopyable { + constexpr NonCopyable(int) {} + NonCopyable(const NonCopyable&) = delete; +}; + +struct NonMovable { + constexpr NonMovable(int) {} + NonMovable(NonMovable&&) = delete; +}; + +template +concept has_and_then = + requires(E&& e, F&& f) { + { std::forward(e).and_then(std::forward(f)) }; + }; + +std::expected return_int() { return {}; } +std::expected return_noncopyable() { return {}; } +std::expected return_nonmovable() { return {}; } + +static_assert(has_and_then&, decltype(return_int)>); +static_assert(!has_and_then&, decltype(return_noncopyable)>); +static_assert(has_and_then&, decltype(return_int)>); +static_assert(!has_and_then&, decltype(return_noncopyable)>); +static_assert(has_and_then&&, decltype(return_int)>); +static_assert(!has_and_then&&, decltype(return_nonmovable)>); +static_assert(has_and_then&&, decltype(return_int)>); +static_assert(!has_and_then&&, decltype(return_nonmovable)>); + +constexpr void test_val_types() { + // Test & overload + { + auto l = [] -> std::expected { return 2; }; + std::expected v; + assert(v.and_then(l).value() == 2); + static_assert(std::is_same_v< decltype(v.and_then(l)), std::expected>); + } + + // Test const& overload + { + auto l = [] -> std::expected { return 2; }; + const std::expected v; + assert(v.and_then(l).value() == 2); + static_assert(std::is_same_v< decltype(v.and_then(l)), std::expected>); + } + + // Test && overload + { + auto l = [] -> std::expected { return 2; }; + std::expected v; + assert(std::move(v).and_then(l).value() == 2); + static_assert(std::is_same_v< decltype(std::move(v).and_then(l)), std::expected>); + } + + // Test const&& overload + { + auto l = [] -> std::expected { return 2; }; + const std::expected v; + assert(std::move(v).and_then(l).value() == 2); + static_assert(std::is_same_v< decltype(std::move(v).and_then(l)), std::expected>); + } +} + +constexpr void test_fail() { + // Test & overload + { + auto f = [] -> std::expected { assert(false); }; + std::expected v(std::unexpected(2)); + assert(v.and_then(f).error() == 2); + static_assert(std::is_same_v< decltype(v.and_then(f)), std::expected>); + } + + // Test const& overload + { + auto f = [] -> std::expected { assert(false); }; + const std::expected v(std::unexpected(2)); + assert(v.and_then(f).error() == 2); + static_assert(std::is_same_v< decltype(v.and_then(f)), std::expected>); + } + + // Test && overload + { + auto f = [] -> std::expected { assert(false); }; + std::expected v(std::unexpected(2)); + assert(std::move(v).and_then(f).error() == 2); + static_assert(std::is_same_v< decltype(std::move(v).and_then(f)), std::expected>); + } + + // Test const&& overload + { + auto f = [] -> std::expected { assert(false); }; + const std::expected v(std::unexpected(2)); + assert(std::move(v).and_then(f).error() == 2); + static_assert(std::is_same_v< decltype(std::move(v).and_then(f)), std::expected>); + } +} + +constexpr bool test() { + test_fail(); + test_val_types(); + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/utilities/expected/expected.void/monadic/or_else.pass.cpp b/libcxx/test/std/utilities/expected/expected.void/monadic/or_else.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/expected/expected.void/monadic/or_else.pass.cpp @@ -0,0 +1,102 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template constexpr auto or_else(F&& f) &; +// template constexpr auto or_else(F&& f) const &; +// template constexpr auto or_else(F&& f) &&; +// template constexpr auto or_else(F&& f) const &&; + +#include +#include +#include +#include + +constexpr void test_val_types() { + // Test & overload + { + auto l = [](auto) -> std::expected { return {}; }; + std::expected v(std::unexpected(1)); + assert(v.or_else(l).has_value()); + static_assert(std::is_same_v>); + } + + // Test const& overload + { + auto l = [](auto) -> std::expected { return {}; }; + const std::expected v(std::unexpected(1)); + assert(v.or_else(l).has_value()); + static_assert(std::is_same_v>); + } + + // Test && overload + { + auto l = [](auto) -> std::expected { return {}; }; + std::expected v(std::unexpected(1)); + assert(std::move(v).or_else(l).has_value()); + static_assert(std::is_same_v>); + } + + // Test const&& overload + { + auto l = [](auto) -> std::expected { return {}; }; + const std::expected v(std::unexpected(1)); + assert(std::move(v).or_else(l).has_value()); + static_assert(std::is_same_v>); + } +} + +constexpr void test_fail() { + // Test & overload + { + auto l = [](auto) -> std::expected { assert(false); }; + std::expected v; + assert(v.or_else(l).has_value()); + static_assert(std::is_same_v>); + } + + // Test const& overload + { + auto l = [](auto) -> std::expected { assert(false); }; + const std::expected v; + assert(v.or_else(l).has_value()); + static_assert(std::is_same_v>); + } + + // Test && overload + { + auto l = [](auto) -> std::expected { assert(false); }; + std::expected v; + assert(std::move(v).or_else(l).has_value()); + static_assert(std::is_same_v>); + } + + // Test const&& overload + { + auto l = [](auto) -> std::expected { assert(false); }; + const std::expected v; + assert(std::move(v).or_else(l).has_value()); + static_assert(std::is_same_v>); + } +} + +constexpr bool test() { + test_fail(); + test_val_types(); + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/utilities/expected/expected.void/monadic/transform.pass.cpp b/libcxx/test/std/utilities/expected/expected.void/monadic/transform.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/expected/expected.void/monadic/transform.pass.cpp @@ -0,0 +1,102 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// template constexpr auto transform_error(F&& f) &; +// template constexpr auto transform_error(F&& f) const &; +// template constexpr auto transform_error(F&& f) &&; +// template constexpr auto transform_error(F&& f) const &&; + +#include +#include +#include +#include + +constexpr void test_val_types() { + // Test & overload + { + auto l = [] -> int { return 1; }; + std::expected v; + assert(v.transform(l).value() == 1); + static_assert(std::is_same_v>); + } + + // Test const& overload + { + auto l = [] -> int { return 1; }; + const std::expected v; + assert(v.transform(l).value() == 1); + static_assert(std::is_same_v>); + } + + // Test && overload + { + auto l = [] -> int { return 1; }; + std::expected v; + assert(std::move(v).transform(l).value() == 1); + static_assert(std::is_same_v>); + } + + // Test const&& overload + { + auto l = [] -> int { return 1; }; + const std::expected v; + assert(std::move(v).transform(l).value() == 1); + static_assert(std::is_same_v>); + } +} + +constexpr void test_fail() { + // Test & overload + { + auto l = [] -> int { assert(false); }; + std::expected v(std::unexpected(5)); + assert(v.transform(l).error() == 5); + static_assert(std::is_same_v>); + } + + // Test const& overload + { + auto l = [] -> int { assert(false); }; + const std::expected v(std::unexpected(5)); + assert(v.transform(l).error() == 5); + static_assert(std::is_same_v>); + } + + // Test && overload + { + auto l = [] -> int { assert(false); }; + std::expected v(std::unexpected(5)); + assert(std::move(v).transform(l).error() == 5); + static_assert(std::is_same_v>); + } + + // Test const&& overload + { + auto l = [] -> int { assert(false); }; + const std::expected v(std::unexpected(5)); + assert(std::move(v).transform(l).error() == 5); + static_assert(std::is_same_v>); + } +} + +constexpr bool test() { + test_fail(); + test_val_types(); + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/utilities/expected/expected.void/monadic/transform_error.pass.cpp b/libcxx/test/std/utilities/expected/expected.void/monadic/transform_error.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/expected/expected.void/monadic/transform_error.pass.cpp @@ -0,0 +1,120 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// GCC has a bug, please refer to: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108333 +// XFAIL: gcc + +// + +// template constexpr auto transform_error(F&& f) &; +// template constexpr auto transform_error(F&& f) const &; +// template constexpr auto transform_error(F&& f) &&; +// template constexpr auto transform_error(F&& f) const &&; + +#include +#include +#include +#include + +struct NonCopy { + int value; + constexpr explicit NonCopy(int val) : value(val) {} + NonCopy(const NonCopy&) = delete; +}; + +constexpr void test_val_types() { + // Test & overload + { + auto l = [](auto) -> int { return 1; }; + std::expected v(std::unexpected(2)); + assert(v.transform_error(l).error() == 1); + static_assert(std::is_same_v>); + } + + // Test const& overload + { + auto l = [](auto) -> int { return 1; }; + const std::expected v(std::unexpected(2)); + assert(v.transform_error(l).error() == 1); + static_assert(std::is_same_v>); + } + + // Test && overload + { + auto l = [](auto) -> int { return 1; }; + std::expected v(std::unexpected(2)); + assert(std::move(v).transform_error(l).error() == 1); + static_assert(std::is_same_v>); + } + + // Test const&& overload + { + auto l = [](auto) -> int { return 1; }; + const std::expected v(std::unexpected(2)); + assert(std::move(v).transform_error(l).error() == 1); + static_assert(std::is_same_v>); + } +} + +constexpr void test_fail() { + // Test & overload + { + auto l = [](auto) -> int { assert(false); }; + std::expected v; + assert(v.transform_error(l).has_value()); + static_assert(std::is_same_v>); + } + + // Test const& overload + { + auto l = [](auto) -> int { assert(false); }; + const std::expected v; + assert(v.transform_error(l).has_value()); + static_assert(std::is_same_v>); + } + + // Test && overload + { + auto l = [](auto) -> int { assert(false); }; + std::expected v; + assert(std::move(v).transform_error(l).has_value()); + static_assert(std::is_same_v>); + } + + // Test const&& overload + { + auto l = [](auto) -> int { assert(false); }; + const std::expected v; + assert(std::move(v).transform_error(l).has_value()); + static_assert(std::is_same_v>); + } +} + +// check unex member is direct-non-list-initialized with invoke(std::forward(f)) +constexpr void test_direct_non_list_init() { + auto x = [](int i) { return NonCopy(i); }; + std::expected v(std::unexpected(2)); + std::expected nv = v.transform_error(x); + assert(nv.error().value == 2); +} + +constexpr bool test() { + test_fail(); + test_val_types(); + test_direct_non_list_init(); + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/utilities/expected/expected.void/observers/error_or.pass.cpp b/libcxx/test/std/utilities/expected/expected.void/observers/error_or.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/expected/expected.void/observers/error_or.pass.cpp @@ -0,0 +1,96 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// template constexpr E error_or(G&& e) const &; +// template constexpr E error_or(G&& e) &&; + +#include +#include +#include +#include +#include + +struct ConstructFromInt { + int value; + constexpr ConstructFromInt(int v) : value(v) {} +}; + +constexpr bool test_default_template_arg() { + // const &, has_value() + { + const std::expected e; + std::same_as decltype(auto) x = e.error_or(10); + assert(x.value == 10); + } + + // const &, !has_value() + { + const std::expected e(std::unexpect, 5); + std::same_as decltype(auto) x = e.error_or(10); + assert(x.value == 5); + } + + // &&, has_value() + { + const std::expected e; + std::same_as decltype(auto) x = std::move(e).error_or(10); + assert(x.value == 10); + } + + // &&, !has_value() + { + const std::expected e(std::unexpect, 5); + std::same_as decltype(auto) x = std::move(e).error_or(10); + assert(x.value == 5); + } + + return true; +} + +constexpr bool test() { + // const &, has_value() + { + const std::expected e; + std::same_as decltype(auto) x = e.error_or(10); + assert(x == 10); + } + + // const &, !has_value() + { + const std::expected e(std::unexpect, 5); + std::same_as decltype(auto) x = e.error_or(10); + assert(x == 5); + } + + // &&, has_value() + { + std::expected e; + std::same_as decltype(auto) x = std::move(e).error_or(10); + assert(x == 10); + } + + // &&, !has_value() + { + std::expected e(std::unexpect, 5); + std::same_as decltype(auto) x = std::move(e).error_or(10); + assert(x == 5); + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + test_default_template_arg(); + static_assert(test_default_template_arg()); + + return 0; +} diff --git a/libcxx/utils/generate_feature_test_macro_components.py b/libcxx/utils/generate_feature_test_macro_components.py --- a/libcxx/utils/generate_feature_test_macro_components.py +++ b/libcxx/utils/generate_feature_test_macro_components.py @@ -309,7 +309,7 @@ "unimplemented": True, }, { "name": "__cpp_lib_expected", - "values": { "c++2b": 202202 }, + "values": { "c++2b": 202211 }, "headers": ["expected"], }, { "name": "__cpp_lib_filesystem",