diff --git a/libcxx/docs/FeatureTestMacroTable.rst b/libcxx/docs/FeatureTestMacroTable.rst --- a/libcxx/docs/FeatureTestMacroTable.rst +++ b/libcxx/docs/FeatureTestMacroTable.rst @@ -312,6 +312,8 @@ ------------------------------------------------- ----------------- ``__cpp_lib_constexpr_typeinfo`` *unimplemented* ------------------------------------------------- ----------------- + ``__cpp_lib_expected`` ``202202L`` + ------------------------------------------------- ----------------- ``__cpp_lib_invoke_r`` *unimplemented* ------------------------------------------------- ----------------- ``__cpp_lib_is_scoped_enum`` ``202011L`` diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt --- a/libcxx/include/CMakeLists.txt +++ b/libcxx/include/CMakeLists.txt @@ -182,6 +182,9 @@ __coroutine/noop_coroutine_handle.h __coroutine/trivial_awaitables.h __debug + __expected/bad_expected_access.h + __expected/expected.h + __expected/unexpected.h __errc __filesystem/copy_options.h __filesystem/directory_entry.h @@ -480,6 +483,7 @@ errno.h exception execution + expected experimental/__config experimental/__memory experimental/algorithm diff --git a/libcxx/include/__expected/bad_expected_access.h b/libcxx/include/__expected/bad_expected_access.h new file mode 100644 --- /dev/null +++ b/libcxx/include/__expected/bad_expected_access.h @@ -0,0 +1,56 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___EXPECTED_BAD_EXPECTED_ACCESS_H +#define _LIBCPP___EXPECTED_BAD_EXPECTED_ACCESS_H + +#include <__config> +#include <__utility/move.h> +#include + +#if _LIBCPP_STD_VER > 20 || _LIBCPP_BUILDING_LIBRARY + +namespace std { + +template +class bad_expected_access; + +template <> +class _LIBCPP_EXCEPTION_ABI bad_expected_access : public exception { +protected: + _LIBCPP_HIDE_FROM_ABI bad_expected_access() noexcept = default; + _LIBCPP_HIDE_FROM_ABI bad_expected_access(const bad_expected_access&) = default; + _LIBCPP_HIDE_FROM_ABI bad_expected_access(bad_expected_access&&) = default; + _LIBCPP_HIDE_FROM_ABI bad_expected_access& operator=(const bad_expected_access&) = default; + _LIBCPP_HIDE_FROM_ABI bad_expected_access& operator=(bad_expected_access&&) = default; + _LIBCPP_HIDE_FROM_ABI ~bad_expected_access() = default; +public: + const char* what() const noexcept override; +}; + +template +class bad_expected_access : public bad_expected_access { +public: + _LIBCPP_HIDE_FROM_ABI explicit bad_expected_access(_Ep __val) : __val_(std::move(__val)) {} + + _LIBCPP_HIDE_FROM_ABI const char* what() const noexcept override { + return "bad_expected_access"; + } + + _LIBCPP_HIDE_FROM_ABI _Ep& error() & noexcept { return __val_; } + _LIBCPP_HIDE_FROM_ABI const _Ep& error() const & noexcept { return __val_; } + _LIBCPP_HIDE_FROM_ABI _Ep&& error() && noexcept { return std::move(__val_); } + _LIBCPP_HIDE_FROM_ABI const _Ep&& error() const && noexcept { return std::move(__val_); } +private: + _Ep __val_; +}; +} // namespace std + +#endif // _LIBCPP_STD_VER > 20 + +#endif // _LIBCPP___EXPECTED_BAD_EXPECTED_ACCESS_H diff --git a/libcxx/include/__expected/expected.h b/libcxx/include/__expected/expected.h new file mode 100644 --- /dev/null +++ b/libcxx/include/__expected/expected.h @@ -0,0 +1,730 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___EXPECTED_EXPECTED_H +#define _LIBCPP___EXPECTED_EXPECTED_H + +#include <__concepts/convertible_to.h> +#include <__config> +#include <__expected/bad_expected_access.h> +#include <__expected/unexpected.h> +#include <__memory/addressof.h> +#include <__memory/construct_at.h> +#include <__utility/forward.h> +#include <__utility/in_place.h> +#include <__utility/move.h> +#include +#include +#include + +#if _LIBCPP_STD_VER > 20 + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +class expected { +public: + using value_type = _Type; + using error_type = _Error; + using unexpected_type = unexpected<_Error>; + + template + static constexpr bool __is_unexpected = false; + + template + static constexpr bool __is_unexpected> = true; + + static_assert(!is_reference_v, "The value type can't be a reference!"); + static_assert(!is_reference_v, "The error type can't be a reference!"); + static_assert(!is_function_v, "The value type can't be a function!"); + static_assert(!is_function_v, "The error type can't be a function!"); + static_assert(!is_same_v, in_place_t>, "The value type can't be in_place_t!"); + static_assert(!is_same_v, in_place_t>, "The error type can't be in_place_t!"); + static_assert(!is_same_v, unexpect_t>, "The value type can't be unexpect_t!"); + static_assert(!is_same_v, unexpect_t>, "The error type can't be unexpect_t!"); + static_assert(!__is_unexpected, "The value type can't be a specialization of unexpected!"); + static_assert(is_same_v, void> || is_destructible_v<_Type>, + "The value type has to be destructible!"); + static_assert(is_destructible_v<_Error>, "The error type has to be destructible!"); + + template + using rebind = expected<_Type2, error_type>; + + // [expected.object.ctor] + _LIBCPP_HIDE_FROM_ABI constexpr expected() requires is_default_constructible_v + : __has_value_(true), __val_(value_type()) {} + + constexpr explicit(false) expected(const expected&) = delete; + + _LIBCPP_HIDE_FROM_ABI constexpr explicit(false) + expected(const expected&) requires (is_trivially_copy_constructible_v + && is_trivially_copy_constructible_v) = default; + + _LIBCPP_HIDE_FROM_ABI constexpr explicit(false) + expected(const expected& __rhs) requires (is_copy_constructible_v + && is_copy_constructible_v + && !(is_trivially_copy_constructible_v + && is_trivially_copy_constructible_v)) + : __has_value_(__rhs.has_value()) { + if (has_value()) + std::construct_at(std::addressof(__val_), __rhs.__val_); + else + std::construct_at(std::addressof(__unexpected_), __rhs.__unexpected_); + } + + _LIBCPP_HIDE_FROM_ABI constexpr explicit(false) expected(expected&&) + noexcept(is_nothrow_move_constructible_v && is_nothrow_move_constructible_v) + requires(is_trivially_move_constructible_v && is_trivially_move_constructible_v) + = default; + + _LIBCPP_HIDE_FROM_ABI constexpr explicit(false) expected(expected&& __rhs) + noexcept(is_nothrow_move_constructible_v && is_nothrow_move_constructible_v) + requires(is_move_constructible_v && is_move_constructible_v + && !(is_trivially_move_constructible_v && is_trivially_move_constructible_v)) + : __has_value_(__rhs.has_value()) { + if (has_value()) + std::construct_at(std::addressof(__val_),std::move(__rhs.__val_)); + else + std::construct_at(std::addressof(__unexpected_), std::move(__rhs.__unexpected_)); + } + + template + static constexpr bool __enable_other_expected_ctor = + !is_constructible_v&> + && !is_constructible_v> + && !is_constructible_v&> + && !is_constructible_v> + && !is_convertible_v&, _Type> + && !is_convertible_v&&, _Type> + && !is_convertible_v&, _Type> + && !is_convertible_v&&, _Type> + && !is_constructible_v, expected<_Type2, _Error2>&> + && !is_constructible_v, expected<_Type2, _Error2>> + && !is_constructible_v, const expected<_Type2, _Error2>&> + && !is_constructible_v, const expected<_Type2, _Error2>>; + + template + requires (__enable_other_expected_ctor<_Type2, _Error2> + && is_constructible_v + && is_constructible_v) + _LIBCPP_HIDE_FROM_ABI constexpr + explicit(!is_convertible_v || !is_convertible_v) + expected(const expected<_Type2, _Error2>& __rhs) : __has_value_(__rhs.has_value()) { + if (has_value()) + std::construct_at(std::addressof(__val_), __rhs.__val_); + else + std::construct_at(std::addressof(__unexpected_), __rhs.__unexpected_); + } + + template + requires (__enable_other_expected_ctor<_Type2, _Error2> + && is_constructible_v + && is_constructible_v) + _LIBCPP_HIDE_FROM_ABI constexpr + explicit(!is_convertible_v<_Type2, value_type> || !is_convertible_v<_Error2, error_type>) + expected(expected<_Type2, _Error2>&& __rhs) + : __has_value_(__rhs.has_value()) { + if (has_value()) + std::construct_at(std::addressof(__val_), std::move(__rhs.__val_)); + else + std::construct_at(std::addressof(__unexpected_), std::move(__rhs.__unexpected_)); + } + + template + requires (!is_same_v, in_place_t> + && !is_same_v> + && !__is_unexpected<_Type2> + && is_constructible_v<_Type2, value_type>) + _LIBCPP_HIDE_FROM_ABI constexpr explicit(!is_convertible_v<_Type2, value_type>) expected(_Type2&& __val) + : __has_value_(true), __val_(std::forward<_Type2>(__val)) {} + + template requires (is_constructible_v) + _LIBCPP_HIDE_FROM_ABI constexpr explicit(!is_convertible_v) + expected(const unexpected<_Error2>& __unexpected) : __has_value_(false), __unexpected_(__unexpected) {} + + template requires (is_constructible_v) + _LIBCPP_HIDE_FROM_ABI constexpr explicit(!is_convertible_v<_Error2, error_type>) + expected(unexpected<_Error2>&& __unexpected) : __has_value_(false), __unexpected_(std::move(__unexpected)) {} + + template requires (is_constructible_v) + _LIBCPP_HIDE_FROM_ABI constexpr explicit expected(in_place_t, _Args&&... __args) + : __has_value_(true), __val_(std::forward<_Args>(__args)...) {} + + template requires (is_constructible_v, _Args...>) + _LIBCPP_HIDE_FROM_ABI constexpr expected(in_place_t, initializer_list<_Type2> __il, _Args&&... __args) + : __has_value_(true), __val_(__il, std::forward<_Args>(__args)...) {} + + template requires (is_constructible_v) + _LIBCPP_HIDE_FROM_ABI constexpr explicit expected(unexpect_t, _Args&&... __args) + : __has_value_(false), __unexpected_(std::forward<_Args>(__args)...) {} + + template requires (is_constructible_v, _Args...>) + _LIBCPP_HIDE_FROM_ABI constexpr explicit expected(unexpect_t, initializer_list<_Type2> __il, _Args&&... __args) + : __has_value_(false), __unexpected_(__il, std::forward<_Args>(__args)...) {} + + // [expected.object.dtor] + _LIBCPP_HIDE_FROM_ABI constexpr ~expected() + requires (is_trivially_destructible_v && is_trivially_destructible_v) = default; + + _LIBCPP_HIDE_FROM_ABI constexpr ~expected() + requires (!is_trivially_destructible_v || !is_trivially_destructible_v) { + if (has_value()) + std::destroy_at(std::addressof(__val_)); + else + std::destroy_at(std::addressof(__unexpected_)); + } + + // [expected.object.assign] + +private: + template + _LIBCPP_HIDE_FROM_ABI constexpr void __reinit_expected(_Type1& __newval, _Type2& __oldval, _Args&&... __args) { + if constexpr (is_nothrow_constructible_v<_Type1, _Args...>) { + std::destroy_at(std::addressof(__oldval)); + std::construct_at(std::addressof(__newval), std::forward<_Args>(__args)...); + } else if constexpr (is_nothrow_move_constructible_v<_Type1>) { + _Type1 __tmp(std::forward<_Args>(__args)...); + std::destroy_at(std::addressof(__oldval)); + std::construct_at(std::addressof(__newval), std::move(__tmp)); + } else { + _Type2 __tmp(std::move(__oldval)); + std::destroy_at(addressof(__oldval)); + try { + std::construct_at(std::addressof(__newval), std::forward<_Args>(__args)...); + } catch(...) { + std::construct_at(std::addressof(__oldval), std::move(__tmp)); + throw; + } + } + } + +public: + + constexpr expected& operator=(const expected&) = delete; + _LIBCPP_HIDE_FROM_ABI constexpr expected& operator=(const expected& __rhs) + requires (is_copy_assignable_v + && is_copy_constructible_v + && is_copy_assignable_v + && is_copy_constructible_v + && (is_nothrow_move_constructible_v || is_nothrow_move_constructible_v)) { + if (__rhs.has_value() && has_value()) + __val_ = *__rhs; + else if (has_value()) + __reinit_expected(__unexpected_, __val_, __rhs.error()); + else if (__rhs.has_value()) + __reinit_expected(__val_, __unexpected_, *__rhs); + else + __unexpected_ = __rhs.error(); + __has_value_ = __rhs.has_value(); + return *this; + } + + _LIBCPP_HIDE_FROM_ABI constexpr expected& operator=(expected&& __rhs) + noexcept(is_nothrow_move_assignable_v && is_nothrow_move_constructible_v && + is_nothrow_move_assignable_v && is_nothrow_move_constructible_v) + requires(is_move_constructible_v + && is_move_assignable_v + && is_move_constructible_v + && is_move_assignable_v + && (is_nothrow_move_constructible_v || is_nothrow_move_constructible_v)) { + if (has_value() && __rhs.has_value()) + __val_ = std::move(*__rhs); + else if (has_value()) + __reinit_expected(__unexpected_, __val_, std::move(__rhs.error())); + else if (__rhs.has_value()) + __reinit_expected(__val_, __unexpected_, std::move(*__rhs)); + else + __unexpected_ = std::move(__rhs.error()); + __has_value_ = __rhs.has_value(); + return *this; + } + + template requires (!is_same_v> + && !__is_unexpected> + && is_constructible_v + && is_assignable_v + && (is_nothrow_constructible_v + || is_nothrow_move_constructible_v + || is_nothrow_move_constructible_v)) + _LIBCPP_HIDE_FROM_ABI constexpr expected& operator=(_Type2&& __val) { + if (has_value()) { + __val_ = std::forward<_Type2>(__val); + } else { + __reinit_expected(__val_, __unexpected_, std::forward<_Type2>(__val)); + __has_value_ = true; + } + return *this; + } + + template + static constexpr bool __enable_unexpected_ctor = is_constructible_v + && is_assignable_v + && (is_nothrow_constructible_v + || is_nothrow_move_constructible_v + || is_nothrow_move_constructible_v); + + template requires (__enable_unexpected_ctor) + _LIBCPP_HIDE_FROM_ABI constexpr expected& operator=(const unexpected<_Error2>& __rhs) { + if (has_value()) + __reinit_expected(__unexpected_, __val_, __rhs); + else + __unexpected_ = __rhs.error(); + } + + template requires (__enable_unexpected_ctor<_Error2>) + _LIBCPP_HIDE_FROM_ABI constexpr expected& operator=(unexpected<_Error2>&& __rhs) { + if (has_value()) + __reinit_expected(__unexpected_, __val_, std::move(__rhs)); + else + __unexpected_ = std::move(__rhs.error()); + } + + template requires(is_nothrow_constructible_v) + _LIBCPP_HIDE_FROM_ABI constexpr value_type& emplace(_Args&&... __args) noexcept { + if (has_value()) { + std::destroy_at(std::addressof(__val_)); + } else { + std::destroy_at(std::addressof(__unexpected_)); + __has_value_ = true; + } + return *std::construct_at(std::addressof(__val_), std::forward<_Args>(__args)...); + } + + template + requires(is_nothrow_constructible_v, _Args...>) + _LIBCPP_HIDE_FROM_ABI constexpr value_type& emplace(initializer_list<_Type2> __il, _Args&&... __args) noexcept { + if (has_value()) { + std::destroy_at(std::addressof(__val_)); + } else { + std::destroy_at(std::addressof(__unexpected_)); + __has_value_ = true; + } + return *std::construct_at(std::addressof(__val_), __il, std::forward<_Args>(__args)...); + } + + // [expected.object.swap] + _LIBCPP_HIDE_FROM_ABI constexpr void swap(expected& __rhs) noexcept(false) + requires(is_swappable_v + && is_swappable_v + && is_move_constructible_v + && is_move_constructible_v + && (is_nothrow_move_constructible_v || is_nothrow_move_constructible_v)) { + if (has_value()) { + if (__rhs.has_value()) { + using std::swap; + swap(__val_, __rhs.__val_); + } else { + __rhs.swap(*this); + } + } else { + if (__rhs.has_value()) { + if constexpr (is_nothrow_move_constructible_v) { + error_type __tmp(std::move(__rhs.__unexpected_)); + std::destroy_at(std::addressof(__rhs.__unexpected_)); + try { + std::construct_at(std::addressof(__rhs.__val_), std::move(__val_)); + std::destroy_at(std::addressof(__val_)); + std::construct_at(std::addressof(__unexpected_), std::move(__tmp)); + } catch (...) { + std::construct_at(std::addressof(__rhs.__unexpected_), std::move(__tmp)); + throw; + } + } else { + value_type __tmp(std::move(__val_)); + std::destroy_at(std::addressof(__val_)); + try { + std::construct_at(std::addressof(__unexpected_), std::move(__rhs.__unexpected_)); + std::destroy_at(std::addressof(__rhs.__unexpected_)); + std::construct_at(std::addressof(__rhs.__val_), std::move(__tmp)); + } catch (...) { + std::construct_at(std::addressof(__val_), std::move(__tmp)); + throw; + } + } + } else { + using std::swap; + swap(__unexpected_, __rhs.__unexpected_); + } + } + } + + _LIBCPP_HIDE_FROM_ABI friend constexpr void swap(expected& __lhs, expected& __rhs) + noexcept(noexcept(__lhs.swap(__rhs))) { + __lhs.swap(__rhs); + } + + // [expected.object.obs] + _LIBCPP_HIDE_FROM_ABI constexpr const value_type* operator->() const noexcept { + _LIBCPP_ASSERT(has_value(), "Trying to access value of expected which contains an error."); + return std::addressof(__val_); + } + + _LIBCPP_HIDE_FROM_ABI constexpr value_type* operator->() noexcept { + _LIBCPP_ASSERT(has_value(), "Trying to access value of expected which contains an error."); + return std::addressof(__val_); + } + + _LIBCPP_HIDE_FROM_ABI constexpr const value_type& operator*() const & noexcept { + _LIBCPP_ASSERT(has_value(), "Trying to access value of expected which contains an error."); + return __val_; + } + + _LIBCPP_HIDE_FROM_ABI constexpr value_type& operator*() & noexcept { + _LIBCPP_ASSERT(has_value(), "Trying to access value of expected which contains an error."); + return __val_; + } + + _LIBCPP_HIDE_FROM_ABI constexpr const value_type&& operator*() const && noexcept { + _LIBCPP_ASSERT(has_value(), "Trying to access value of expected which contains an error."); + return std::move(__val_); + } + + _LIBCPP_HIDE_FROM_ABI constexpr value_type&& operator*() && noexcept { + _LIBCPP_ASSERT(has_value(), "Trying to access value of expected which contains an error."); + return std::move(__val_); + } + + _LIBCPP_HIDE_FROM_ABI constexpr explicit operator bool() const noexcept { return has_value(); } + _LIBCPP_HIDE_FROM_ABI constexpr bool has_value() const noexcept { return __has_value_; } + + _LIBCPP_HIDE_FROM_ABI constexpr const value_type& value() const & { + if (has_value()) + return __val_; + throw bad_expected_access(error()); + } + + _LIBCPP_HIDE_FROM_ABI constexpr value_type& value() & { + if (has_value()) + return __val_; + throw bad_expected_access(error()); + } + + _LIBCPP_HIDE_FROM_ABI constexpr const value_type&& value() const && { + if (has_value()) + return std::move(__val_); + throw bad_expected_access(error()); + } + + _LIBCPP_HIDE_FROM_ABI constexpr value_type&& value() && { + if (has_value()) + return std::move(__val_); + throw bad_expected_access(error()); + } + + _LIBCPP_HIDE_FROM_ABI constexpr const error_type& error() const & { + _LIBCPP_ASSERT(has_value(), "Trying to access error of expected which contains a value."); + return __unexpected_; + } + + _LIBCPP_HIDE_FROM_ABI constexpr error_type& error() & { + _LIBCPP_ASSERT(has_value(), "Trying to access error of expected which contains a value."); + return __unexpected_; + } + + _LIBCPP_HIDE_FROM_ABI constexpr const error_type&& error() const && { + _LIBCPP_ASSERT(has_value(), "Trying to access error of expected which contains a value."); + return std::move(__unexpected_); + } + + _LIBCPP_HIDE_FROM_ABI constexpr error_type&& error() && { + _LIBCPP_ASSERT(has_value(), "Trying to access error of expected which contains a value."); + return std::move(__unexpected_); + } + + template + _LIBCPP_HIDE_FROM_ABI constexpr value_type value_or(_Type2&& __val) const & { + static_assert(is_copy_constructible_v, "value_type has to be copy constructible"); + static_assert(is_convertible_v<_Type2, value_type>, "argument has to be convertible to value_type"); + return has_value() ? **this : static_cast(std::forward<_Type2>(__val)); + } + + template + _LIBCPP_HIDE_FROM_ABI constexpr value_type value_or(_Type2&& __val) && { + static_assert(is_copy_constructible_v, "value_type has to be copy constructible"); + static_assert(is_convertible_v<_Type2, value_type>, "argument has to be convertible to value_type"); + return has_value() ? std::move(**this) : static_cast(std::forward<_Type2>(__val)); + } + + // [expected.object.eq] + template requires (!is_void_v<_Type2>) + _LIBCPP_HIDE_FROM_ABI friend constexpr + bool operator==(const expected& __lhs, const expected<_Type2, _Error2>& __rhs) { + static_assert(requires { *__lhs == *__rhs -> convertible_to; }, + "TODO: find a good error message"); + static_assert(requires { __lhs.error() == __rhs.error() -> convertible_to; }, + "TODO: find a good error message"); + if (__lhs.has_value() != __rhs.has_value()) + return false; + if (__lhs.has_value()) + return *__lhs == *__rhs; + return __lhs.error() == __rhs.error(); + } + + template + _LIBCPP_HIDE_FROM_ABI friend constexpr + bool operator==(const expected& __lhs, const _Type2& __rhs) { + static_assert(requires { *__lhs == __rhs -> convertible_to; }, "TODO: find a good error message"); + return __lhs.has_value() && static_cast(*__lhs == __rhs); + } + + template + _LIBCPP_HIDE_FROM_ABI friend constexpr + bool operator==(const expected& __lhs, const unexpected<_Error2> __rhs) { + static_assert(requires { __lhs.error() == __rhs.value() -> convertible_to; }, + "TODO: find a good error message"); + return !__lhs.has_value() && static_cast(__lhs.error() == __rhs.value()); + } + +private: + bool __has_value_; + union { + value_type __val_; + error_type __unexpected_; + }; + + template + friend class expected; +}; + +template requires is_void_v<_Type> +class expected<_Type, _Error> { +public: + using value_type = _Type; + using error_type = _Error; + using unexpected_type = unexpected<_Error>; + + template + using rebind = expected<_Type2, error_type>; + + // [expected.void.ctor] + _LIBCPP_HIDE_FROM_ABI constexpr expected() noexcept : __has_value_(true) {} + + constexpr expected(const expected&) = delete; + constexpr expected(const expected&) requires is_trivially_copy_constructible_v = default; + + _LIBCPP_HIDE_FROM_ABI constexpr explicit(false) expected(const expected& __rhs) + requires is_copy_constructible_v { + if (__rhs.has_value()) + std::construct_at(std::addressof(__unexpected_), __rhs.__unexpected_); + __has_value_ = __rhs.has_value(); + } + + _LIBCPP_HIDE_FROM_ABI constexpr expected(expected&&) requires is_trivially_move_constructible_v = default; + + _LIBCPP_HIDE_FROM_ABI constexpr explicit(false) expected(expected&& __rhs) noexcept(false) + requires is_move_constructible_v { + if (!__rhs.has_value()) + std::construct_at(std::addressof(__rhs.__unexpected_), std::move(__rhs.__unexpected_)); + __has_value_ = __rhs.has_value(); + } + + template + static constexpr bool __enable_other_expected_ctor = + is_void_v<_Type2> + && !is_constructible_v, expected<_Type2, _Error2>&> + && !is_constructible_v, expected<_Type2, _Error2>> + && !is_constructible_v, const expected<_Type2, _Error2>> + && !is_constructible_v, const expected<_Type2, _Error2>>; + + template + requires (__enable_other_expected_ctor<_Type2, _Error2> && is_constructible_v) + _LIBCPP_HIDE_FROM_ABI constexpr explicit(!is_convertible_v) + expected(const expected<_Type2, _Error2>& __rhs) { + if (!__rhs.has_value()) + std::construct_at(std::addressof(__unexpected_), __rhs.__unexpected_); + __has_value_ = __rhs.has_value(); + } + + template + requires (__enable_other_expected_ctor<_Type2, _Error2> && is_constructible_v) + _LIBCPP_HIDE_FROM_ABI constexpr explicit(!is_convertible_v<_Type2, _Error2>) + expected(expected<_Type2, _Error2>&& __rhs) { + if (!__rhs.has_value()) + std::construct_at(std::addressof(__unexpected_), std::move(__rhs.__unexpected_)); + __has_value_ = __rhs.has_value(); + } + + template requires is_constructible_v + _LIBCPP_HIDE_FROM_ABI constexpr explicit(!is_convertible_v) + expected(const unexpected<_Error2>& __err) : __has_value_(false), __unexpected_(__err) {} + + template requires is_constructible_v + _LIBCPP_HIDE_FROM_ABI constexpr expected(unexpected<_Error2>&& __err) + : __has_value_(false), __unexpected_(std::move(__err)) {} + + _LIBCPP_HIDE_FROM_ABI constexpr explicit expected(in_place_t) noexcept : __has_value_(true) {} + + template requires is_constructible_v + _LIBCPP_HIDE_FROM_ABI constexpr explicit expected(unexpect_t, _Args&&... __args) + : __has_value_(false), __unexpected_(std::forward<_Args>(__args)...) {} + + template requires is_constructible_v, _Args...> + _LIBCPP_HIDE_FROM_ABI constexpr explicit expected(unexpect_t, initializer_list<_Type2> __il, _Args&&... __args) + : __has_value_(false), __unexpected_(__il, std::forward<_Args>(__args)...) {} + + // [expected.void.dtor] + _LIBCPP_HIDE_FROM_ABI ~expected() requires is_trivially_destructible_v = default; + + _LIBCPP_HIDE_FROM_ABI ~expected() { + if (!has_value()) + std::destroy_at(std::addressof(__unexpected_)); + } + + // [expected.void.assign] + _LIBCPP_HIDE_FROM_ABI expected& operator=(const expected& __rhs) { + if (has_value() && __rhs.has_value()) + return; + if (has_value()) { + std::construct_at(std::addressof(__unexpected_), __rhs.__unexpected_); + } else if (__rhs.has_value()) { + std::destroy_at(std::addressof(__unexpected_)); + __has_value_ = true; + } else { + __unexpected_ = __rhs.error(); + } + } + + _LIBCPP_HIDE_FROM_ABI constexpr expected& operator=(expected&& __rhs) + noexcept(is_nothrow_move_constructible_v && is_nothrow_move_assignable_v) { + if (has_value() && __rhs.has_value()) + return; + if (has_value()) { + std::construct_at(std::addressof(__unexpected_), std::move(__rhs.__unexpected_)); + __has_value_ = false; + } else if (__rhs.has_value()) { + std::destroy_at(std::addressof(__unexpected_)); + __has_value_ = true; + } else { + __unexpected_ = __rhs.error(); + } + } + + template + requires (is_constructible_v && is_assignable_v) + _LIBCPP_HIDE_FROM_ABI constexpr expected& operator=(const unexpected<_Error2>& __err) { + if (has_value()) { + std::construct_at(std::addressof(__unexpected_), __err.value()); + __has_value_ = false; + } else { + __unexpected_ = __err.value(); + } + return *this; + } + + template requires (is_constructible_v && is_assignable_v) + _LIBCPP_HIDE_FROM_ABI constexpr expected& operator=(unexpected<_Error2>&& __err) { + if (has_value()) { + std::construct_at(std::addressof(__unexpected_), std::move(__err.value())); + __has_value_ = false; + } else { + __unexpected_ = std::move(__err.value()); + } + return *this; + } + + _LIBCPP_HIDE_FROM_ABI constexpr void emplace() noexcept { + if (!has_value()) { + std::destroy_at(std::addressof(__unexpected_)); + __has_value_ = true; + } + } + + // [expected.void.swap] + _LIBCPP_HIDE_FROM_ABI constexpr void swap(expected& __rhs) + noexcept(is_nothrow_move_constructible_v && is_nothrow_swappable_v) + requires(is_swappable_v && is_move_constructible_v) { + if (has_value()) { + if (!__rhs.has_value()) { + std::construct_at(std::addressof(__unexpected_), std::move(__rhs.__unexpected_)); + std::destroy_at(std::addressof(__rhs.__unexpected_)); + __has_value_ = false; + __rhs.__has_value_ = true; + } + } else { + if (__rhs.has_value()) { + __rhs.swap(*this); + } else { + using std::swap; + swap(__unexpected_, __rhs.__unexpected_); + } + } + } + + _LIBCPP_HIDE_FROM_ABI friend constexpr void swap(expected& __lhs, expected& __rhs) + noexcept(noexcept(__lhs.swap(__rhs))) { + __lhs.swap(__rhs); + } + + // [expected.void.obs] + _LIBCPP_HIDE_FROM_ABI constexpr explicit operator bool() const noexcept { return has_value(); } + _LIBCPP_HIDE_FROM_ABI constexpr bool has_value() const noexcept { return __has_value_; } + + _LIBCPP_HIDE_FROM_ABI constexpr void operator*() const noexcept { + _LIBCPP_ASSERT(has_value(), "Trying to access value of expected which contains an error."); + } + + _LIBCPP_HIDE_FROM_ABI constexpr void value() const & { + if (!has_value()) + throw bad_expected_access(error()); + } + + _LIBCPP_HIDE_FROM_ABI constexpr void value() && { + if (!has_value()) + throw bad_expected_access(std::move(error())); + } + + _LIBCPP_HIDE_FROM_ABI constexpr const error_type& error() const & { + _LIBCPP_ASSERT(has_value(), "Trying to access error of expected which contains a value."); + return __unexpected_; + } + + _LIBCPP_HIDE_FROM_ABI constexpr error_type& error() & { + _LIBCPP_ASSERT(has_value(), "Trying to access error of expected which contains a value."); + return __unexpected_; + } + + _LIBCPP_HIDE_FROM_ABI constexpr const error_type&& error() const && { + _LIBCPP_ASSERT(has_value(), "Trying to access error of expected which contains a value."); + return std::move(__unexpected_); + } + + _LIBCPP_HIDE_FROM_ABI constexpr error_type&& error() && { + _LIBCPP_ASSERT(has_value(), "Trying to access error of expected which contains a value."); + return std::move(__unexpected_); + } + + // [expected.void.eq] + template requires is_void_v<_Type2> + _LIBCPP_HIDE_FROM_ABI friend constexpr + bool operator==(const expected& __lhs, const expected<_Type2, _Error2>& __rhs) { + static_assert(requires { __lhs.error() == __rhs.error() -> convertible_to; }, + "TODO: find good error message"); + if (__lhs.has_value() != __rhs.has_value()) + return false; + return __lhs.has_value() || static_cast(__lhs.error() == __rhs.error()); + } + + template + _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const expected& __lhs, const unexpected<_Error2>& __rhs) { + static_assert(requires { __lhs.error() == __rhs.value() -> convertible_to; }, + "TODO: find good error message"); + return !__lhs.has_value() && static_cast(__lhs.error() == __rhs.value()); + } + +private: + bool __has_value_; + union { + error_type __unexpected_; + }; +}; + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER > 20 + +#endif // _LIBCPP___EXPECTED_EXPECTED_H diff --git a/libcxx/include/__expected/unexpected.h b/libcxx/include/__expected/unexpected.h new file mode 100644 --- /dev/null +++ b/libcxx/include/__expected/unexpected.h @@ -0,0 +1,86 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___UNEXPECTED_H +#define _LIBCPP___UNEXPECTED_H + +#include <__config> +#include <__utility/forward.h> +#include <__utility/in_place.h> +#include <__utility/move.h> +#include <__utility/swap.h> +#include +#include + +#if _LIBCPP_STD_VER > 20 + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +class unexpected { +public: + _LIBCPP_HIDE_FROM_ABI constexpr unexpected(const unexpected&) = default; + _LIBCPP_HIDE_FROM_ABI constexpr unexpected(unexpected&&) = default; + + template + requires(is_constructible_v<_Ep, _Args...>) + _LIBCPP_HIDE_FROM_ABI constexpr explicit unexpected(in_place_t, _Args&&... __args) + : __val(std::forward<_Args>(__args)...) {} + + template + requires(is_constructible_v<_Ep, initializer_list<_Up>, _Args...>) + _LIBCPP_HIDE_FROM_ABI constexpr explicit unexpected(in_place_t, initializer_list<_Up> __il, _Args&&... __args) + : __val(__il, std::forward<_Args>(__args)...) {} + + template + requires(!is_same_v, unexpected> && !is_same_v, in_place_t> && + is_constructible_v<_Ep, _Err>) + _LIBCPP_HIDE_FROM_ABI constexpr explicit unexpected(_Err&& __e) : __val(std::forward<_Err>(__e)) {} + + _LIBCPP_HIDE_FROM_ABI constexpr unexpected& operator=(const unexpected&) = default; + _LIBCPP_HIDE_FROM_ABI constexpr unexpected& operator=(unexpected&&) = default; + + _LIBCPP_HIDE_FROM_ABI constexpr const _Ep& value() const& noexcept { return __val; } + _LIBCPP_HIDE_FROM_ABI constexpr _Ep& value() & noexcept { return __val; } + _LIBCPP_HIDE_FROM_ABI constexpr const _Ep&& value() const&& noexcept { return std::move(__val); } + _LIBCPP_HIDE_FROM_ABI constexpr _Ep&& value() && noexcept { return std::move(__val); } + + _LIBCPP_HIDE_FROM_ABI constexpr void swap(unexpected& __other) noexcept(is_nothrow_swappable_v<_Ep>) { + static_assert(is_swappable_v<_Ep>, "E has to be swappable"); + + using std::swap; + swap(__val, __other.__val); + } + + template + _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const unexpected& __lhs, const unexpected<_E2>& __rhs) { + return __lhs.value() == __rhs.value(); + } + + _LIBCPP_HIDE_FROM_ABI friend constexpr + void swap(unexpected& __lhs, unexpected& __rhs) noexcept(noexcept(__lhs.swap(__rhs))) + requires is_swappable_v<_Ep> { + __lhs.swap(__rhs); + } + +private: + _Ep __val; +}; + +template unexpected(_Ep) -> unexpected<_Ep>; + +struct unexpect_t { + explicit unexpect_t() = default; +}; +inline constexpr unexpect_t unexpect{}; + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER > 20 + +#endif // _LIBCPP___UNEXPECTED_H diff --git a/libcxx/include/expected b/libcxx/include/expected new file mode 100644 --- /dev/null +++ b/libcxx/include/expected @@ -0,0 +1,47 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +/* +namespace std { + // [expected.un.object], class template unexpected + template class unexpected; + + // [expected.bad], class template bad_­expected_­access + template class bad_expected_access; + + // [expected.bad.void], specialization for void + template<> class bad_expected_access; + + // in-place construction of unexpected values + struct unexpect_t { + explicit unexpect_t() = default; + }; + inline constexpr unexpect_t unexpect{}; + + // [expected.expected], class template expected + template class expected; + + // [expected.void], partial specialization of expected for void types + template requires is_void_v class expected; +} +*/ + +#ifndef _LIBCPP_EXPECTED +#define _LIBCPP_EXPECTED + +#include <__config> +#include <__expected/bad_expected_access.h> +#include <__expected/expected.h> +#include <__expected/unexpected.h> +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +#endif // _LIBCPP_EXPECTED diff --git a/libcxx/include/module.modulemap b/libcxx/include/module.modulemap --- a/libcxx/include/module.modulemap +++ b/libcxx/include/module.modulemap @@ -499,6 +499,16 @@ header "execution" export * } + module expected { + header "expected" + export * + + module __expected { + module bad_expected_access { private header "__expected/bad_expected_access.h" } + module expected { private header "__expected/expected.h" } + module unexcpected { private header "__expected/unexpected.h" } + } + } module filesystem { header "filesystem" export * diff --git a/libcxx/include/version b/libcxx/include/version --- a/libcxx/include/version +++ b/libcxx/include/version @@ -79,6 +79,7 @@ __cpp_lib_exchange_function 201304L __cpp_lib_execution 201902L 201603L // C++17 +__cpp_lib_expected 202202L __cpp_lib_filesystem 201703L __cpp_lib_format 202106L __cpp_lib_gcd_lcm 201606L @@ -380,6 +381,7 @@ # define __cpp_lib_byteswap 202110L // # define __cpp_lib_constexpr_cmath 202202L // # define __cpp_lib_constexpr_typeinfo 202106L +# define __cpp_lib_expected 202202L // # define __cpp_lib_invoke_r 202106L # define __cpp_lib_is_scoped_enum 202011L # define __cpp_lib_monadic_optional 202110L diff --git a/libcxx/src/CMakeLists.txt b/libcxx/src/CMakeLists.txt --- a/libcxx/src/CMakeLists.txt +++ b/libcxx/src/CMakeLists.txt @@ -7,6 +7,7 @@ assert.cpp atomic.cpp barrier.cpp + bad_expected_access.cpp bind.cpp charconv.cpp chrono.cpp diff --git a/libcxx/src/bad_expected_access.cpp b/libcxx/src/bad_expected_access.cpp new file mode 100644 --- /dev/null +++ b/libcxx/src/bad_expected_access.cpp @@ -0,0 +1,15 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include + +namespace std { +const char* bad_expected_access::what() const noexcept { + return "bad_expected_access"; +} +} // namespace std diff --git a/libcxx/test/libcxx/assertions/headers_declare_assertion_handler.sh.cpp b/libcxx/test/libcxx/assertions/headers_declare_assertion_handler.sh.cpp --- a/libcxx/test/libcxx/assertions/headers_declare_assertion_handler.sh.cpp +++ b/libcxx/test/libcxx/assertions/headers_declare_assertion_handler.sh.cpp @@ -310,458 +310,464 @@ using HandlerType = decltype(std::__libcpp_assertion_handler); #endif -// RUN: %{build} -DTEST_47 -#if defined(TEST_47) && !defined(_LIBCPP_HAS_NO_FILESYSTEM_LIBRARY) -# include +// RUN: %{build} -DTEST_46 +#if defined(TEST_46) +# include using HandlerType = decltype(std::__libcpp_assertion_handler); #endif -// RUN: %{build} -DTEST_49 -#if defined(TEST_49) -# include +// RUN: %{build} -DTEST_48 +#if defined(TEST_48) && !defined(_LIBCPP_HAS_NO_FILESYSTEM_LIBRARY) +# include using HandlerType = decltype(std::__libcpp_assertion_handler); #endif // RUN: %{build} -DTEST_50 #if defined(TEST_50) -# include +# include using HandlerType = decltype(std::__libcpp_assertion_handler); #endif // RUN: %{build} -DTEST_51 -#if defined(TEST_51) && !defined(_LIBCPP_HAS_NO_LOCALIZATION) -# include +#if defined(TEST_51) +# include using HandlerType = decltype(std::__libcpp_assertion_handler); #endif // RUN: %{build} -DTEST_52 -#if defined(TEST_52) -# include +#if defined(TEST_52) && !defined(_LIBCPP_HAS_NO_LOCALIZATION) +# include using HandlerType = decltype(std::__libcpp_assertion_handler); #endif // RUN: %{build} -DTEST_53 -#if defined(TEST_53) && !defined(_LIBCPP_HAS_NO_THREADS) -# include +#if defined(TEST_53) +# include using HandlerType = decltype(std::__libcpp_assertion_handler); #endif // RUN: %{build} -DTEST_54 -#if defined(TEST_54) -# include +#if defined(TEST_54) && !defined(_LIBCPP_HAS_NO_THREADS) +# include using HandlerType = decltype(std::__libcpp_assertion_handler); #endif -// RUN: %{build} -DTEST_56 -#if defined(TEST_56) && !defined(_LIBCPP_HAS_NO_LOCALIZATION) -# include +// RUN: %{build} -DTEST_55 +#if defined(TEST_55) +# include using HandlerType = decltype(std::__libcpp_assertion_handler); #endif // RUN: %{build} -DTEST_57 #if defined(TEST_57) && !defined(_LIBCPP_HAS_NO_LOCALIZATION) -# include +# include using HandlerType = decltype(std::__libcpp_assertion_handler); #endif // RUN: %{build} -DTEST_58 -#if defined(TEST_58) -# include +#if defined(TEST_58) && !defined(_LIBCPP_HAS_NO_LOCALIZATION) +# include using HandlerType = decltype(std::__libcpp_assertion_handler); #endif // RUN: %{build} -DTEST_59 -#if defined(TEST_59) && !defined(_LIBCPP_HAS_NO_LOCALIZATION) -# include +#if defined(TEST_59) +# include using HandlerType = decltype(std::__libcpp_assertion_handler); #endif // RUN: %{build} -DTEST_60 #if defined(TEST_60) && !defined(_LIBCPP_HAS_NO_LOCALIZATION) -# include +# include using HandlerType = decltype(std::__libcpp_assertion_handler); #endif // RUN: %{build} -DTEST_61 -#if defined(TEST_61) -# include +#if defined(TEST_61) && !defined(_LIBCPP_HAS_NO_LOCALIZATION) +# include using HandlerType = decltype(std::__libcpp_assertion_handler); #endif // RUN: %{build} -DTEST_62 -#if defined(TEST_62) && !defined(_LIBCPP_HAS_NO_THREADS) -# include +#if defined(TEST_62) +# include using HandlerType = decltype(std::__libcpp_assertion_handler); #endif // RUN: %{build} -DTEST_63 -#if defined(TEST_63) -# include +#if defined(TEST_63) && !defined(_LIBCPP_HAS_NO_THREADS) +# include using HandlerType = decltype(std::__libcpp_assertion_handler); #endif -// RUN: %{build} -DTEST_65 -#if defined(TEST_65) -# include +// RUN: %{build} -DTEST_64 +#if defined(TEST_64) +# include using HandlerType = decltype(std::__libcpp_assertion_handler); #endif // RUN: %{build} -DTEST_66 -#if defined(TEST_66) && !defined(_LIBCPP_HAS_NO_LOCALIZATION) -# include +#if defined(TEST_66) +# include using HandlerType = decltype(std::__libcpp_assertion_handler); #endif -// RUN: %{build} -DTEST_68 -#if defined(TEST_68) -# include +// RUN: %{build} -DTEST_67 +#if defined(TEST_67) && !defined(_LIBCPP_HAS_NO_LOCALIZATION) +# include using HandlerType = decltype(std::__libcpp_assertion_handler); #endif -// RUN: %{build} -DTEST_70 -#if defined(TEST_70) -# include +// RUN: %{build} -DTEST_69 +#if defined(TEST_69) +# include using HandlerType = decltype(std::__libcpp_assertion_handler); #endif // RUN: %{build} -DTEST_71 -#if defined(TEST_71) && !defined(_LIBCPP_HAS_NO_THREADS) -# include +#if defined(TEST_71) +# include using HandlerType = decltype(std::__libcpp_assertion_handler); #endif // RUN: %{build} -DTEST_72 -#if defined(TEST_72) -# include +#if defined(TEST_72) && !defined(_LIBCPP_HAS_NO_THREADS) +# include using HandlerType = decltype(std::__libcpp_assertion_handler); #endif // RUN: %{build} -DTEST_73 #if defined(TEST_73) -# include +# include using HandlerType = decltype(std::__libcpp_assertion_handler); #endif // RUN: %{build} -DTEST_74 #if defined(TEST_74) -# include +# include using HandlerType = decltype(std::__libcpp_assertion_handler); #endif // RUN: %{build} -DTEST_75 #if defined(TEST_75) -# include +# include using HandlerType = decltype(std::__libcpp_assertion_handler); #endif // RUN: %{build} -DTEST_76 -#if defined(TEST_76) && !defined(_LIBCPP_HAS_NO_LOCALIZATION) -# include +#if defined(TEST_76) +# include using HandlerType = decltype(std::__libcpp_assertion_handler); #endif // RUN: %{build} -DTEST_77 -#if defined(TEST_77) -# include +#if defined(TEST_77) && !defined(_LIBCPP_HAS_NO_LOCALIZATION) +# include using HandlerType = decltype(std::__libcpp_assertion_handler); #endif // RUN: %{build} -DTEST_78 #if defined(TEST_78) -# include +# include using HandlerType = decltype(std::__libcpp_assertion_handler); #endif // RUN: %{build} -DTEST_79 #if defined(TEST_79) -# include +# include using HandlerType = decltype(std::__libcpp_assertion_handler); #endif // RUN: %{build} -DTEST_80 #if defined(TEST_80) -# include +# include using HandlerType = decltype(std::__libcpp_assertion_handler); #endif // RUN: %{build} -DTEST_81 -#if defined(TEST_81) && !defined(_LIBCPP_HAS_NO_LOCALIZATION) -# include +#if defined(TEST_81) +# include using HandlerType = decltype(std::__libcpp_assertion_handler); #endif // RUN: %{build} -DTEST_82 -#if defined(TEST_82) -# include +#if defined(TEST_82) && !defined(_LIBCPP_HAS_NO_LOCALIZATION) +# include using HandlerType = decltype(std::__libcpp_assertion_handler); #endif // RUN: %{build} -DTEST_83 -#if defined(TEST_83) && !defined(_LIBCPP_HAS_NO_THREADS) -# include +#if defined(TEST_83) +# include using HandlerType = decltype(std::__libcpp_assertion_handler); #endif // RUN: %{build} -DTEST_84 -#if defined(TEST_84) +#if defined(TEST_84) && !defined(_LIBCPP_HAS_NO_THREADS) +# include + using HandlerType = decltype(std::__libcpp_assertion_handler); +#endif + +// RUN: %{build} -DTEST_85 +#if defined(TEST_85) # include using HandlerType = decltype(std::__libcpp_assertion_handler); #endif -// RUN: %{build} -DTEST_86 -#if defined(TEST_86) && !defined(_LIBCPP_HAS_NO_THREADS) +// RUN: %{build} -DTEST_87 +#if defined(TEST_87) && !defined(_LIBCPP_HAS_NO_THREADS) # include using HandlerType = decltype(std::__libcpp_assertion_handler); #endif -// RUN: %{build} -DTEST_87 -#if defined(TEST_87) +// RUN: %{build} -DTEST_88 +#if defined(TEST_88) # include using HandlerType = decltype(std::__libcpp_assertion_handler); #endif -// RUN: %{build} -DTEST_88 -#if defined(TEST_88) && !defined(_LIBCPP_HAS_NO_LOCALIZATION) +// RUN: %{build} -DTEST_89 +#if defined(TEST_89) && !defined(_LIBCPP_HAS_NO_LOCALIZATION) # include using HandlerType = decltype(std::__libcpp_assertion_handler); #endif -// RUN: %{build} -DTEST_89 -#if defined(TEST_89) +// RUN: %{build} -DTEST_90 +#if defined(TEST_90) # include using HandlerType = decltype(std::__libcpp_assertion_handler); #endif -// RUN: %{build} -DTEST_92 -#if defined(TEST_92) +// RUN: %{build} -DTEST_93 +#if defined(TEST_93) # include using HandlerType = decltype(std::__libcpp_assertion_handler); #endif -// RUN: %{build} -DTEST_96 -#if defined(TEST_96) && !defined(_LIBCPP_HAS_NO_LOCALIZATION) +// RUN: %{build} -DTEST_97 +#if defined(TEST_97) && !defined(_LIBCPP_HAS_NO_LOCALIZATION) # include using HandlerType = decltype(std::__libcpp_assertion_handler); #endif -// RUN: %{build} -DTEST_97 -#if defined(TEST_97) +// RUN: %{build} -DTEST_98 +#if defined(TEST_98) # include using HandlerType = decltype(std::__libcpp_assertion_handler); #endif -// RUN: %{build} -DTEST_99 -#if defined(TEST_99) +// RUN: %{build} -DTEST_100 +#if defined(TEST_100) # include using HandlerType = decltype(std::__libcpp_assertion_handler); #endif -// RUN: %{build} -DTEST_100 -#if defined(TEST_100) && !defined(_LIBCPP_HAS_NO_LOCALIZATION) +// RUN: %{build} -DTEST_101 +#if defined(TEST_101) && !defined(_LIBCPP_HAS_NO_LOCALIZATION) # include using HandlerType = decltype(std::__libcpp_assertion_handler); #endif -// RUN: %{build} -DTEST_101 -#if defined(TEST_101) +// RUN: %{build} -DTEST_102 +#if defined(TEST_102) # include using HandlerType = decltype(std::__libcpp_assertion_handler); #endif -// RUN: %{build} -DTEST_103 -#if defined(TEST_103) && !defined(_LIBCPP_HAS_NO_THREADS) -# include - using HandlerType = decltype(std::__libcpp_assertion_handler); -#endif - // RUN: %{build} -DTEST_104 -#if defined(TEST_104) -# include +#if defined(TEST_104) && !defined(_LIBCPP_HAS_NO_THREADS) +# include using HandlerType = decltype(std::__libcpp_assertion_handler); #endif // RUN: %{build} -DTEST_105 #if defined(TEST_105) -# include +# include using HandlerType = decltype(std::__libcpp_assertion_handler); #endif // RUN: %{build} -DTEST_106 #if defined(TEST_106) -# include +# include using HandlerType = decltype(std::__libcpp_assertion_handler); #endif // RUN: %{build} -DTEST_107 #if defined(TEST_107) -# include +# include using HandlerType = decltype(std::__libcpp_assertion_handler); #endif -// RUN: %{build} -DTEST_109 -#if defined(TEST_109) -# include +// RUN: %{build} -DTEST_108 +#if defined(TEST_108) +# include using HandlerType = decltype(std::__libcpp_assertion_handler); #endif // RUN: %{build} -DTEST_110 #if defined(TEST_110) -# include +# include using HandlerType = decltype(std::__libcpp_assertion_handler); #endif // RUN: %{build} -DTEST_111 #if defined(TEST_111) -# include +# include using HandlerType = decltype(std::__libcpp_assertion_handler); #endif // RUN: %{build} -DTEST_112 #if defined(TEST_112) -# include +# include using HandlerType = decltype(std::__libcpp_assertion_handler); #endif // RUN: %{build} -DTEST_113 #if defined(TEST_113) -# include +# include using HandlerType = decltype(std::__libcpp_assertion_handler); #endif // RUN: %{build} -DTEST_114 #if defined(TEST_114) -# include +# include using HandlerType = decltype(std::__libcpp_assertion_handler); #endif // RUN: %{build} -DTEST_115 #if defined(TEST_115) -# include +# include using HandlerType = decltype(std::__libcpp_assertion_handler); #endif -// RUN: %{build} -DTEST_118 -#if defined(TEST_118) -# include +// RUN: %{build} -DTEST_116 +#if defined(TEST_116) +# include using HandlerType = decltype(std::__libcpp_assertion_handler); #endif // RUN: %{build} -DTEST_119 -#if defined(TEST_119) && !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_COROUTINES) -# include +#if defined(TEST_119) +# include using HandlerType = decltype(std::__libcpp_assertion_handler); #endif // RUN: %{build} -DTEST_120 -#if defined(TEST_120) && __cplusplus >= 201103L -# include +#if defined(TEST_120) && !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_COROUTINES) +# include using HandlerType = decltype(std::__libcpp_assertion_handler); #endif // RUN: %{build} -DTEST_121 #if defined(TEST_121) && __cplusplus >= 201103L -# include +# include using HandlerType = decltype(std::__libcpp_assertion_handler); #endif // RUN: %{build} -DTEST_122 -#if defined(TEST_122) -# include +#if defined(TEST_122) && __cplusplus >= 201103L +# include using HandlerType = decltype(std::__libcpp_assertion_handler); #endif // RUN: %{build} -DTEST_123 #if defined(TEST_123) -# include +# include using HandlerType = decltype(std::__libcpp_assertion_handler); #endif // RUN: %{build} -DTEST_124 -#if defined(TEST_124) && __cplusplus >= 201103L -# include +#if defined(TEST_124) +# include using HandlerType = decltype(std::__libcpp_assertion_handler); #endif // RUN: %{build} -DTEST_125 #if defined(TEST_125) && __cplusplus >= 201103L -# include +# include using HandlerType = decltype(std::__libcpp_assertion_handler); #endif // RUN: %{build} -DTEST_126 #if defined(TEST_126) && __cplusplus >= 201103L -# include +# include using HandlerType = decltype(std::__libcpp_assertion_handler); #endif // RUN: %{build} -DTEST_127 -#if defined(TEST_127) -# include +#if defined(TEST_127) && __cplusplus >= 201103L +# include using HandlerType = decltype(std::__libcpp_assertion_handler); #endif // RUN: %{build} -DTEST_128 -#if defined(TEST_128) && !defined(_LIBCPP_HAS_NO_LOCALIZATION) && __cplusplus >= 201103L -# include +#if defined(TEST_128) +# include using HandlerType = decltype(std::__libcpp_assertion_handler); #endif // RUN: %{build} -DTEST_129 -#if defined(TEST_129) && __cplusplus >= 201103L -# include +#if defined(TEST_129) && !defined(_LIBCPP_HAS_NO_LOCALIZATION) && __cplusplus >= 201103L +# include using HandlerType = decltype(std::__libcpp_assertion_handler); #endif // RUN: %{build} -DTEST_130 -#if defined(TEST_130) -# include +#if defined(TEST_130) && __cplusplus >= 201103L +# include using HandlerType = decltype(std::__libcpp_assertion_handler); #endif // RUN: %{build} -DTEST_131 -#if defined(TEST_131) && __cplusplus >= 201103L -# include +#if defined(TEST_131) +# include using HandlerType = decltype(std::__libcpp_assertion_handler); #endif // RUN: %{build} -DTEST_132 -#if defined(TEST_132) -# include +#if defined(TEST_132) && __cplusplus >= 201103L +# include using HandlerType = decltype(std::__libcpp_assertion_handler); #endif // RUN: %{build} -DTEST_133 -#if defined(TEST_133) && __cplusplus >= 201103L -# include +#if defined(TEST_133) +# include using HandlerType = decltype(std::__libcpp_assertion_handler); #endif // RUN: %{build} -DTEST_134 #if defined(TEST_134) && __cplusplus >= 201103L -# include +# include using HandlerType = decltype(std::__libcpp_assertion_handler); #endif // RUN: %{build} -DTEST_135 -#if defined(TEST_135) -# include +#if defined(TEST_135) && __cplusplus >= 201103L +# include using HandlerType = decltype(std::__libcpp_assertion_handler); #endif // RUN: %{build} -DTEST_136 -#if defined(TEST_136) && __cplusplus >= 201103L -# include +#if defined(TEST_136) +# include using HandlerType = decltype(std::__libcpp_assertion_handler); #endif // RUN: %{build} -DTEST_137 -#if defined(TEST_137) -# include +#if defined(TEST_137) && __cplusplus >= 201103L +# include using HandlerType = decltype(std::__libcpp_assertion_handler); #endif // RUN: %{build} -DTEST_138 #if defined(TEST_138) +# include + using HandlerType = decltype(std::__libcpp_assertion_handler); +#endif + +// RUN: %{build} -DTEST_139 +#if defined(TEST_139) # include using HandlerType = decltype(std::__libcpp_assertion_handler); #endif diff --git a/libcxx/test/libcxx/clang_tidy.sh.cpp b/libcxx/test/libcxx/clang_tidy.sh.cpp --- a/libcxx/test/libcxx/clang_tidy.sh.cpp +++ b/libcxx/test/libcxx/clang_tidy.sh.cpp @@ -90,6 +90,7 @@ #include #include #include +#include #include #if !defined(_LIBCPP_HAS_NO_FILESYSTEM_LIBRARY) # include diff --git a/libcxx/test/libcxx/double_include.sh.cpp b/libcxx/test/libcxx/double_include.sh.cpp --- a/libcxx/test/libcxx/double_include.sh.cpp +++ b/libcxx/test/libcxx/double_include.sh.cpp @@ -93,6 +93,7 @@ #include #include #include +#include #include #if !defined(_LIBCPP_HAS_NO_FILESYSTEM_LIBRARY) # include diff --git a/libcxx/test/libcxx/min_max_macros.compile.pass.cpp b/libcxx/test/libcxx/min_max_macros.compile.pass.cpp --- a/libcxx/test/libcxx/min_max_macros.compile.pass.cpp +++ b/libcxx/test/libcxx/min_max_macros.compile.pass.cpp @@ -139,6 +139,8 @@ TEST_MACROS(); #include TEST_MACROS(); +#include +TEST_MACROS(); #include TEST_MACROS(); #if !defined(_LIBCPP_HAS_NO_FILESYSTEM_LIBRARY) diff --git a/libcxx/test/libcxx/nasty_macros.compile.pass.cpp b/libcxx/test/libcxx/nasty_macros.compile.pass.cpp --- a/libcxx/test/libcxx/nasty_macros.compile.pass.cpp +++ b/libcxx/test/libcxx/nasty_macros.compile.pass.cpp @@ -203,6 +203,7 @@ #include #include #include +#include #include #if !defined(_LIBCPP_HAS_NO_FILESYSTEM_LIBRARY) # include diff --git a/libcxx/test/libcxx/no_assert_include.compile.pass.cpp b/libcxx/test/libcxx/no_assert_include.compile.pass.cpp --- a/libcxx/test/libcxx/no_assert_include.compile.pass.cpp +++ b/libcxx/test/libcxx/no_assert_include.compile.pass.cpp @@ -90,6 +90,7 @@ #include #include #include +#include #include #if !defined(_LIBCPP_HAS_NO_FILESYSTEM_LIBRARY) # include diff --git a/libcxx/test/libcxx/private_headers.verify.cpp b/libcxx/test/libcxx/private_headers.verify.cpp --- a/libcxx/test/libcxx/private_headers.verify.cpp +++ b/libcxx/test/libcxx/private_headers.verify.cpp @@ -215,6 +215,9 @@ #include <__coroutine/noop_coroutine_handle.h> // expected-error@*:* {{use of private header from outside its module: '__coroutine/noop_coroutine_handle.h'}} #include <__coroutine/trivial_awaitables.h> // expected-error@*:* {{use of private header from outside its module: '__coroutine/trivial_awaitables.h'}} #include <__errc> // expected-error@*:* {{use of private header from outside its module: '__errc'}} +#include <__expected/bad_expected_access.h> // expected-error@*:* {{use of private header from outside its module: '__expected/bad_expected_access.h'}} +#include <__expected/expected.h> // expected-error@*:* {{use of private header from outside its module: '__expected/expected.h'}} +#include <__expected/unexpected.h> // expected-error@*:* {{use of private header from outside its module: '__expected/unexpected.h'}} #include <__filesystem/copy_options.h> // expected-error@*:* {{use of private header from outside its module: '__filesystem/copy_options.h'}} #include <__filesystem/directory_entry.h> // expected-error@*:* {{use of private header from outside its module: '__filesystem/directory_entry.h'}} #include <__filesystem/directory_iterator.h> // expected-error@*:* {{use of private header from outside its module: '__filesystem/directory_iterator.h'}} diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/expected.version.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/expected.version.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/language.support/support.limits/support.limits.general/expected.version.pass.cpp @@ -0,0 +1,60 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// WARNING: This test was generated by generate_feature_test_macro_components.py +// and should not be edited manually. +// +// clang-format off + +// + +// Test the feature test macros defined by + +/* Constant Value + __cpp_lib_expected 202202L [C++2b] +*/ + +#include +#include "test_macros.h" + +#if TEST_STD_VER < 14 + +# ifdef __cpp_lib_expected +# error "__cpp_lib_expected should not be defined before c++2b" +# endif + +#elif TEST_STD_VER == 14 + +# ifdef __cpp_lib_expected +# error "__cpp_lib_expected should not be defined before c++2b" +# endif + +#elif TEST_STD_VER == 17 + +# ifdef __cpp_lib_expected +# error "__cpp_lib_expected should not be defined before c++2b" +# endif + +#elif TEST_STD_VER == 20 + +# ifdef __cpp_lib_expected +# error "__cpp_lib_expected should not be defined before c++2b" +# endif + +#elif TEST_STD_VER > 20 + +# 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" +# endif + +#endif // TEST_STD_VER > 20 + +int main(int, char**) { return 0; } diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.pass.cpp --- a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.pass.cpp +++ b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.pass.cpp @@ -73,6 +73,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_filesystem 201703L [C++17] __cpp_lib_format 202106L [C++20] __cpp_lib_gcd_lcm 201606L [C++17] @@ -404,6 +405,10 @@ # error "__cpp_lib_execution should not be defined before c++17" # endif +# ifdef __cpp_lib_expected +# error "__cpp_lib_expected should not be defined before c++2b" +# endif + # ifdef __cpp_lib_filesystem # error "__cpp_lib_filesystem should not be defined before c++17" # endif @@ -1039,6 +1044,10 @@ # error "__cpp_lib_execution should not be defined before c++17" # endif +# ifdef __cpp_lib_expected +# error "__cpp_lib_expected should not be defined before c++2b" +# endif + # ifdef __cpp_lib_filesystem # error "__cpp_lib_filesystem should not be defined before c++17" # endif @@ -1785,6 +1794,10 @@ # endif # endif +# ifdef __cpp_lib_expected +# error "__cpp_lib_expected should not be defined before c++2b" +# endif + # if !defined(_LIBCPP_AVAILABILITY_DISABLE_FTM___cpp_lib_filesystem) # ifndef __cpp_lib_filesystem # error "__cpp_lib_filesystem should be defined in c++17" @@ -2834,6 +2847,10 @@ # endif # endif +# ifdef __cpp_lib_expected +# error "__cpp_lib_expected should not be defined before c++2b" +# endif + # if !defined(_LIBCPP_AVAILABILITY_DISABLE_FTM___cpp_lib_filesystem) # ifndef __cpp_lib_filesystem # error "__cpp_lib_filesystem should be defined in c++20" @@ -4087,6 +4104,13 @@ # endif # endif +# 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" +# endif + # if !defined(_LIBCPP_AVAILABILITY_DISABLE_FTM___cpp_lib_filesystem) # ifndef __cpp_lib_filesystem # error "__cpp_lib_filesystem should be defined in c++2b" diff --git a/libcxx/test/std/utilities/expected/expected.bad/ctor.pass.cpp b/libcxx/test/std/utilities/expected/expected.bad/ctor.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/expected/expected.bad/ctor.pass.cpp @@ -0,0 +1,27 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// + +#include +#include +#include +#include + +struct S {}; +static_assert(std::is_base_of_v, std::bad_expected_access>); +static_assert(std::is_base_of_v>); + +int main(int, char**) { + std::bad_expected_access e(1); + assert(e.error() == 1); + + return 0; +} diff --git a/libcxx/test/std/utilities/expected/expected.bad/error.pass.cpp b/libcxx/test/std/utilities/expected/expected.bad/error.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/expected/expected.bad/error.pass.cpp @@ -0,0 +1,44 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// + +#include +#include +#include +#include + +int main(int, char**) { + { + std::bad_expected_access e(1); + std::same_as decltype(auto) v = e.error(); + assert(v == 1); + } + + { + const std::bad_expected_access e(1); + std::same_as decltype(auto) v = e.error(); + assert(v == 1); + } + + { + std::bad_expected_access e(1); + std::same_as decltype(auto) v = std::move(e).error(); + assert(v == 1); + } + + { + const std::bad_expected_access e(1); + std::same_as decltype(auto) v = std::move(e).error(); + assert(v == 1); + } + + return 0; +} diff --git a/libcxx/test/std/utilities/expected/expected.bad/what.pass.cpp b/libcxx/test/std/utilities/expected/expected.bad/what.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/expected/expected.bad/what.pass.cpp @@ -0,0 +1,32 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// + +#include +#include + +int main(int, char**) { + { + std::bad_expected_access e(1); + std::same_as decltype(auto) what = e.what(); + while (*what != '\0') + ++what; + } + { + std::bad_expected_access e_(1); + std::bad_expected_access& e = e_; + std::same_as decltype(auto) what = e.what(); + while (*what != '\0') + ++what; + } + + return 0; +} diff --git a/libcxx/test/std/utilities/expected/expected.expected/ctor/copy.pass.cpp b/libcxx/test/std/utilities/expected/expected.expected/ctor/copy.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/expected/expected.expected/ctor/copy.pass.cpp @@ -0,0 +1,57 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// + +// constexpr expected(const expected& rhs); + +#include +#include + +#include "MoveOnly.h" + +struct NotTriviallyCopyConstructible { + NotTriviallyCopyConstructible(const NotTriviallyCopyConstructible&); +}; + +static_assert(std::is_copy_constructible_v>); +static_assert(!std::is_copy_constructible_v>); +static_assert(!std::is_copy_constructible_v>); +static_assert(!std::is_copy_constructible_v>); +static_assert(std::is_trivially_copy_constructible_v>); +static_assert(std::is_trivially_copy_constructible_v>); +static_assert(!std::is_trivially_copy_constructible_v>); +static_assert(!std::is_trivially_copy_constructible_v>); +static_assert(!std::is_trivially_copy_constructible_v>); + +constexpr bool test() { + { + std::expected e(10); + auto e2 = e; + assert(e2.has_value()); + assert(*e2 == 10); + } + { + std::expected e(std::unexpect, 10); + auto e2 = e; + assert(!e2.has_value()); + assert(e2.error() == 10); + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/utilities/expected/expected.expected/ctor/copy_other.pass.cpp b/libcxx/test/std/utilities/expected/expected.expected/ctor/copy_other.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/expected/expected.expected/ctor/copy_other.pass.cpp @@ -0,0 +1,53 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// + +#include +#include +#include +#include + +template +struct ConvertibleFrom { + T t; + constexpr ConvertibleFrom() = default; + constexpr ConvertibleFrom(const T& o) : t(o) {} +}; +static_assert(std::is_convertible_v>); + +template +struct ConstructibleFrom { + T t; + constexpr ConstructibleFrom() = default; + constexpr explicit ConstructibleFrom(T& o) : t(std::move(o)) {} + constexpr explicit ConstructibleFrom(const T& o) : t(o) {} + constexpr explicit ConstructibleFrom(T&& o) : t(std::move(o)) {} + constexpr explicit ConstructibleFrom(const T&& o) : t(std::move(o)) {} +}; + +static_assert(!std::is_constructible_v>, char>, + std::expected&>); + +static_assert(!std::is_constructible_v>, char>, + const std::expected&>); + +constexpr bool test() { + std::expected e; + std::expected, char> e2 = e; + assert(e2.value().t == 0); + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); +} diff --git a/libcxx/test/std/utilities/expected/expected.expected/ctor/default.pass.cpp b/libcxx/test/std/utilities/expected/expected.expected/ctor/default.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/expected/expected.expected/ctor/default.pass.cpp @@ -0,0 +1,45 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// + +// constexpr expected(); + +#include +#include + +struct ThrowOnConstruction { + ThrowOnConstruction() { throw 1; } +}; + +void test_exception() { + try { + std::expected e; + } catch(int) { + return; + } + assert(false); +} + +constexpr bool test() { + std::expected e; + assert(e.has_value()); + assert(e.value() == 0); + + return true; +} + +int main(int, char**) { + test_exception(); + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/utilities/expected/expected.expected/ctor/in_place.pass.cpp b/libcxx/test/std/utilities/expected/expected.expected/ctor/in_place.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/expected/expected.expected/ctor/in_place.pass.cpp @@ -0,0 +1,40 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// + +#include +#include +#include + +#include "MoveOnly.h" + +struct NonMovable { + MoveOnly i; + + constexpr explicit NonMovable(MoveOnly&& i_) : i(std::move(i_)) {} + NonMovable(NonMovable&&) = delete; +}; + +static_assert(!std::is_constructible_v, std::in_place_t, int, const char*>); + +constexpr bool test() { + std::expected e(std::in_place, MoveOnly(1)); + assert(e.value().i.get() == 1); + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/utilities/expected/expected.expected/ctor/in_place_init_list.pass.cpp b/libcxx/test/std/utilities/expected/expected.expected/ctor/in_place_init_list.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/expected/expected.expected/ctor/in_place_init_list.pass.cpp @@ -0,0 +1,40 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// + +#include +#include +#include + +#include "MoveOnly.h" + +struct NonMovable { + MoveOnly i; + + constexpr explicit NonMovable(std::initializer_list, MoveOnly&& i_) : i(std::move(i_)) {} + NonMovable(NonMovable&&) = delete; +}; + +static_assert(!std::is_constructible_v, std::in_place_t, int, const char*>); + +constexpr bool test() { + std::expected e(std::in_place, {1, 2, 3, 4}, MoveOnly(1)); + assert(e.value().i.get() == 1); + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/utilities/expected/expected.expected/ctor/move.pass.cpp b/libcxx/test/std/utilities/expected/expected.expected/ctor/move.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/expected/expected.expected/ctor/move.pass.cpp @@ -0,0 +1,43 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// + +// constexpr expected(expected&& rhs) noexcept(see below); + +#include +#include + +#include "MoveOnly.h" + +static_assert(std::is_move_constructible_v>); +static_assert(std::is_move_constructible_v>); +static_assert(std::is_move_constructible_v>); +static_assert(std::is_move_constructible_v>); +static_assert(std::is_trivially_move_constructible_v>); +static_assert(!std::is_trivially_move_constructible_v>); +static_assert(!std::is_trivially_move_constructible_v>); +static_assert(!std::is_trivially_move_constructible_v>); + +constexpr bool test() { + std::expected e; + auto e2 = std::move(e); + assert(e2->get() == 1); + assert(e->get() == 0); + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/utilities/expected/expected.expected/ctor/unexpect.pass.cpp b/libcxx/test/std/utilities/expected/expected.expected/ctor/unexpect.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/expected/expected.expected/ctor/unexpect.pass.cpp @@ -0,0 +1,39 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// + +#include +#include + +#include "MoveOnly.h" + +struct NonMovable { + MoveOnly i; + + constexpr explicit NonMovable(MoveOnly&& i_) : i(std::move(i_)) {} + NonMovable(NonMovable&&) = delete; +}; + +static_assert(!std::is_constructible_v, std::unexpect_t, int, const char*>); + +constexpr bool test() { + std::expected e(std::unexpect, MoveOnly(1)); + assert(e.error().i.get() == 1); + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/utilities/expected/expected.expected/ctor/unexpect_init_list.pass.cpp b/libcxx/test/std/utilities/expected/expected.expected/ctor/unexpect_init_list.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/expected/expected.expected/ctor/unexpect_init_list.pass.cpp @@ -0,0 +1,40 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// + +#include +#include +#include + +#include "MoveOnly.h" + +struct NonMovable { + MoveOnly i; + + constexpr explicit NonMovable(std::initializer_list, MoveOnly&& i_) : i(std::move(i_)) {} + NonMovable(NonMovable&&) = delete; +}; + +static_assert(!std::is_constructible_v, std::unexpect_t, int, const char*>); + +constexpr bool test() { + std::expected e(std::unexpect, {1, 2, 3, 4}, MoveOnly(1)); + assert(e.error().i.get() == 1); + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/utilities/expected/expected.expected/dtor.pass.cpp b/libcxx/test/std/utilities/expected/expected.expected/dtor.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/expected/expected.expected/dtor.pass.cpp @@ -0,0 +1,41 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// + +#include +#include +#include + +struct InstanceCounter { + int* counter; + constexpr InstanceCounter(int* counter_) : counter(counter_) { ++*counter; } + constexpr ~InstanceCounter() { --*counter; } + InstanceCounter(InstanceCounter&&) = delete; +}; + +constexpr bool test() { + int instanceCount = 0; + + { + std::expected e(std::in_place, &instanceCount); + assert(instanceCount == 1); + } + assert(instanceCount == 0); + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/utilities/expected/expected.unexpected/assign.pass.cpp b/libcxx/test/std/utilities/expected/expected.unexpected/assign.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/expected/expected.unexpected/assign.pass.cpp @@ -0,0 +1,45 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// + +// constexpr unexpected& operator=(const unexpected&) = default; +// constexpr unexpected& operator=(unexpected&&) = default; + +#include +#include + +#include "MoveOnly.h" + +constexpr bool test() { + { // constexpr unexpected& operator=(const unexpected&) + std::unexpected e(1); + std::unexpected e2(45); + e2 = e; + assert(e2.value() == 1); + } + + { // constexpr unexpected& operator=(unexpected&&) + std::unexpected e(1); + std::unexpected e2(45); + e2 = std::move(e); + assert(e2.value().get() == 1); + assert(e.value().get() == 0); + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/utilities/expected/expected.unexpected/ctor.pass.cpp b/libcxx/test/std/utilities/expected/expected.unexpected/ctor.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/expected/expected.unexpected/ctor.pass.cpp @@ -0,0 +1,213 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// + +// constexpr unexpected(const unexpected&) = default; +// constexpr unexpected(unexpected&&) = default; +// template +// constexpr explicit unexpected(in_place_t, Args&&...); +// template +// constexpr explicit unexpected(in_place_t, initializer_list, Args&&...); +// template +// constexpr explicit unexpected(Err&&); + +#include +#include +#include + +struct ConstCopyConstructible { + constexpr ConstCopyConstructible() = default; + constexpr ConstCopyConstructible(const ConstCopyConstructible&) {} + constexpr ConstCopyConstructible(ConstCopyConstructible&) = delete; + constexpr ConstCopyConstructible(ConstCopyConstructible&&) = delete; + constexpr ConstCopyConstructible(const ConstCopyConstructible&&) = delete; +}; +struct MutableCopyConstructible { + constexpr MutableCopyConstructible() = default; + constexpr MutableCopyConstructible(MutableCopyConstructible&) {} + constexpr MutableCopyConstructible(const MutableCopyConstructible&) = delete; +}; +struct ConstMoveConstructible { + constexpr ConstMoveConstructible() = default; + constexpr ConstMoveConstructible(const ConstMoveConstructible&&) {} + constexpr ConstMoveConstructible(ConstMoveConstructible&&) = delete; +}; +struct MutableMoveConstructible { + constexpr MutableMoveConstructible() = default; + constexpr MutableMoveConstructible(MutableMoveConstructible&&) {} + constexpr MutableMoveConstructible(const MutableMoveConstructible&&) = delete; +}; + +static_assert( std::is_constructible_v, MutableCopyConstructible&>); +static_assert(!std::is_constructible_v, const MutableCopyConstructible&>); +static_assert(!std::is_constructible_v, MutableCopyConstructible&&>); +static_assert(!std::is_constructible_v, const MutableCopyConstructible&&>); + +static_assert(!std::is_constructible_v, ConstCopyConstructible&>); +static_assert( std::is_constructible_v, const ConstCopyConstructible&>); +static_assert(!std::is_constructible_v, ConstCopyConstructible&&>); +static_assert(!std::is_constructible_v, const ConstCopyConstructible&&>); + +static_assert(!std::is_constructible_v, MutableMoveConstructible&>); +static_assert(!std::is_constructible_v, const MutableMoveConstructible&>); +static_assert( std::is_constructible_v, MutableMoveConstructible&&>); +static_assert(!std::is_constructible_v, const MutableMoveConstructible&&>); + +static_assert(!std::is_constructible_v, ConstMoveConstructible&>); +static_assert(!std::is_constructible_v, const ConstMoveConstructible&>); +static_assert(!std::is_constructible_v, ConstMoveConstructible&&>); +static_assert( std::is_constructible_v, const ConstMoveConstructible&&>); + +struct ImmobileRVal { + constexpr ImmobileRVal(int&&) {} + ImmobileRVal(const ImmobileRVal&) = delete; + ImmobileRVal(ImmobileRVal&&) = delete; +}; + +struct ImmobileLVal { + constexpr ImmobileLVal(int&) {} + ImmobileLVal(const ImmobileLVal&) = delete; + ImmobileLVal(ImmobileLVal&&) = delete; +}; + +static_assert(!std::is_constructible_v, std::in_place_t, int&>); +static_assert(!std::is_constructible_v, std::in_place_t, const int&>); +static_assert( std::is_constructible_v, std::in_place_t, int&&>); +static_assert(!std::is_constructible_v, std::in_place_t, const int&& >); + +static_assert( std::is_constructible_v, std::in_place_t, int&>); +static_assert(!std::is_constructible_v, std::in_place_t, const int&>); +static_assert(!std::is_constructible_v, std::in_place_t, int&&>); +static_assert(!std::is_constructible_v, std::in_place_t, const int&& >); + +struct ImmobileRValInitList { + constexpr ImmobileRValInitList(std::initializer_list, int&&) {} + ImmobileRValInitList(const ImmobileRValInitList&) = delete; + ImmobileRValInitList(ImmobileRValInitList&&) = delete; +}; + +struct ImmobileLValInitList { + constexpr ImmobileLValInitList(std::initializer_list, int&) {} + ImmobileLValInitList(const ImmobileLValInitList&) = delete; + ImmobileLValInitList(ImmobileLValInitList&&) = delete; +}; + +static_assert(!std::is_constructible_v, std::in_place_t, std::initializer_list, int&>); +static_assert(!std::is_constructible_v, std::in_place_t, std::initializer_list, const int&>); +static_assert( std::is_constructible_v, std::in_place_t, std::initializer_list, int&&>); +static_assert(!std::is_constructible_v, std::in_place_t, std::initializer_list, const int&& >); + +static_assert( std::is_constructible_v, std::in_place_t, std::initializer_list, int&>); +static_assert(!std::is_constructible_v, std::in_place_t, std::initializer_list, const int&>); +static_assert(!std::is_constructible_v, std::in_place_t, std::initializer_list, int&&>); +static_assert(!std::is_constructible_v, std::in_place_t, std::initializer_list, const int&& >); + +struct CopyThrows { + CopyThrows(const CopyThrows&) noexcept(false) {} +}; + +struct CopyNothrow { + CopyNothrow(const CopyNothrow&) noexcept(true) {} +}; +struct MoveThrows { + MoveThrows(MoveThrows&&) noexcept(false) {} +}; + +struct MoveNothrow { + MoveNothrow(MoveNothrow&&) noexcept(true) {} +}; + +static_assert(!std::is_nothrow_copy_constructible_v); +static_assert( std::is_nothrow_copy_constructible_v); +static_assert(!std::is_nothrow_move_constructible_v); +static_assert( std::is_nothrow_move_constructible_v); + +constexpr bool test() { + { // test unexpected(_Err&&) + { + std::unexpected e {1L}; + assert(e.value() == 1); + } + { + const ConstCopyConstructible a; + [[maybe_unused]] std::unexpected e {a}; + } + { + MutableCopyConstructible a; + [[maybe_unused]] std::unexpected e {a}; + } + { + const ConstMoveConstructible a; + [[maybe_unused]] std::unexpected e {std::move(a)}; + } + { + MutableMoveConstructible a; + [[maybe_unused]] std::unexpected e {std::move(a)}; + } + } + + { // test unexpected(in_place_t, _Args&&... __args) + { + [[maybe_unused]] std::unexpected e {std::in_place_t{}, 1}; + } + { + int i = 1; + [[maybe_unused]] std::unexpected e {std::in_place_t{}, i}; + } + } + + { // test unexpected(in_place_t, initializer_list<_Up> __il, _Args&&... __args) + { + [[maybe_unused]] std::unexpected e {std::in_place_t{}, {2L}, 1}; + } + { + int i = 1; + [[maybe_unused]] std::unexpected e {std::in_place_t{}, {2L}, i}; + } + } + + { // test unexpected(const unexpected&) + struct CopyCounter { + int* counter; + constexpr CopyCounter(int* counter_) : counter(counter_) {} + constexpr CopyCounter(const CopyCounter& other) : counter(other.counter) { ++*counter; } + }; + + int counter = 0; + std::unexpected e { &counter }; + auto e2 = e; + auto e3 = std::move(e); + assert(counter == 2); + } + + { // test unexpected(unexpected&&) + struct MoveCounter { + int* counter; + constexpr MoveCounter(int* counter_) : counter(counter_) {} + constexpr MoveCounter(MoveCounter&& other) : counter(other.counter) { ++*counter; } + }; + + int counter = 0; + std::unexpected e { &counter }; + auto e3 = std::move(e); + assert(counter == 1); + } + + std::unexpected a {1}; + assert(a.value() == 1); + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); +} diff --git a/libcxx/test/std/utilities/expected/expected.unexpected/equality.pass.cpp b/libcxx/test/std/utilities/expected/expected.unexpected/equality.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/expected/expected.unexpected/equality.pass.cpp @@ -0,0 +1,47 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// + +#include +#include +#include + +struct Comparable { + bool compare; + int* set; + + constexpr bool operator==(const Comparable&) const { + *set = 42; + return compare; + } +}; + +constexpr bool test() { + int first = 0; + int second = 0; + std::unexpected e1(Comparable{true, &first}); + std::unexpected e2(Comparable{true, &second}); + assert(e1 == e2); + assert(first == 42); + assert(second == 0); + assert(e2 == e1); + assert(first == 42); + assert(second == 42); + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/utilities/expected/expected.unexpected/swap.pass.cpp b/libcxx/test/std/utilities/expected/expected.unexpected/swap.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/expected/expected.unexpected/swap.pass.cpp @@ -0,0 +1,49 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// + +#include +#include +#include + +struct CustomSwap { int i; }; + +constexpr void swap(CustomSwap& lhs, CustomSwap& rhs) { + lhs.i *= 2; + rhs.i /= 2; +} + +constexpr bool test() { + { + std::unexpected e1(CustomSwap{30}); + std::unexpected e2(CustomSwap{20}); + e1.swap(e2); + assert(e1.value().i == 60); + assert(e2.value().i = 10); + } + + { + std::unexpected e1(CustomSwap{30}); + std::unexpected e2(CustomSwap{20}); + swap(e1, e2); + assert(e1.value().i == 60); + assert(e2.value().i = 10); + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/utilities/expected/expected.unexpected/value.pass.cpp b/libcxx/test/std/utilities/expected/expected.unexpected/value.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/expected/expected.unexpected/value.pass.cpp @@ -0,0 +1,57 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// + +// constexpr const E& value() const & noexcept; +// constexpr E& value() & noexcept; +// constexpr const E&& value() const && noexcept; +// constexpr E&& value() && noexcept; + +#include +#include +#include + +#include "MoveOnly.h" + +constexpr bool test() { + { // constexpr const E& value() const & noexcept; + const std::unexpected e(45); + std::same_as decltype(auto) val = e.value(); + assert(val == 45); + } + + { // constexpr E& value() & noexcept; + std::unexpected e(45); + std::same_as decltype(auto) val = e.value(); + assert(val == 45); + } + + { // constexpr const E&& value() const && noexcept; + const std::unexpected e(45); + std::same_as decltype(auto) val = std::move(e).value(); + assert(val == 45); + } + + { // constexpr E& value() & noexcept; + std::unexpected e(45); + std::same_as decltype(auto) val = std::move(e).value(); + assert(val == 45); + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + 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 @@ -303,6 +303,10 @@ "values": { "c++17": 201603, "c++20": 201902 }, "headers": ["execution"], "unimplemented": True, + }, { + "name": "__cpp_lib_expected", + "values": { "c++2b": 202202 }, + "headers": ["expected"], }, { "name": "__cpp_lib_filesystem", "values": { "c++17": 201703 },