diff --git a/stl/CMakeLists.txt b/stl/CMakeLists.txt
index 318279f3fb..5bcd5e643d 100644
--- a/stl/CMakeLists.txt
+++ b/stl/CMakeLists.txt
@@ -131,6 +131,7 @@ set(HEADERS
${CMAKE_CURRENT_LIST_DIR}/inc/deque
${CMAKE_CURRENT_LIST_DIR}/inc/exception
${CMAKE_CURRENT_LIST_DIR}/inc/execution
+ ${CMAKE_CURRENT_LIST_DIR}/inc/expected
${CMAKE_CURRENT_LIST_DIR}/inc/experimental/coroutine
${CMAKE_CURRENT_LIST_DIR}/inc/experimental/deque
${CMAKE_CURRENT_LIST_DIR}/inc/experimental/filesystem
diff --git a/stl/debugger/STL.natvis b/stl/debugger/STL.natvis
index 5885050d8d..8216bd9f12 100644
--- a/stl/debugger/STL.natvis
+++ b/stl/debugger/STL.natvis
@@ -247,6 +247,45 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+
+ {unex()}
+
+ - unex()
+
+
+
+
+
+ {unex()}
+
+ - unex()
+
+
+
+
+
+
+
+ {value()}
+ {unex()}
+
+ - value()
+ - unex()
+
+
+
+
+
+
+ void
+ {unex()}
+
+ - unex()
+
+
+
+
{{ size={$T1} }}
diff --git a/stl/inc/__msvc_all_public_headers.hpp b/stl/inc/__msvc_all_public_headers.hpp
index 3d7a53d472..71c8782195 100644
--- a/stl/inc/__msvc_all_public_headers.hpp
+++ b/stl/inc/__msvc_all_public_headers.hpp
@@ -88,6 +88,7 @@
#include
#include
#include
+#include
#include
#include
#include
diff --git a/stl/inc/expected b/stl/inc/expected
new file mode 100644
index 0000000000..00164414f4
--- /dev/null
+++ b/stl/inc/expected
@@ -0,0 +1,1088 @@
+// expected standard header
+
+// Copyright (c) Microsoft Corporation.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+#pragma once
+#ifndef _EXPECTED_
+#define _EXPECTED_
+#include
+#if _STL_COMPILER_PREPROCESSOR
+#ifndef __cpp_lib_expected
+#pragma message("The contents of are available only with C++23 or later.")
+#else // ^^^ !__cpp_lib_expected / __cpp_lib_expected vvv
+#include
+#include
+#include
+#include
+
+#pragma pack(push, _CRT_PACKING)
+#pragma warning(push, _STL_WARNING_LEVEL)
+#pragma warning(disable : _STL_DISABLED_WARNINGS)
+_STL_DISABLE_CLANG_WARNINGS
+#pragma push_macro("new")
+#undef new
+
+_STD_BEGIN
+
+template
+class unexpected;
+
+template
+struct _Check_unexpected_argument : true_type {
+ static_assert(is_object_v<_Err>, "E must be an object type. (N4910 [expected.un.object.general]/1)");
+ static_assert(!is_array_v<_Err>, "E must not be an array type. (N4910 [expected.un.object.general]/1)");
+ static_assert(!is_const_v<_Err>, "E must not be const. (N4910 [expected.un.object.general]/1)");
+ static_assert(!is_volatile_v<_Err>, "E must not be volatile. (N4910 [expected.un.object.general]/1)");
+ static_assert(!_Is_specialization_v<_Err, unexpected>,
+ "E must not be a specialization of unexpected. (N4910 [expected.un.object.general]/1)");
+};
+
+// [expected.un.general]
+template
+class unexpected {
+ static_assert(_Check_unexpected_argument<_Err>::value);
+
+ template
+ friend class expected;
+
+public:
+ // [expected.un.ctor]
+
+ // clang-format off
+ template
+ requires (!is_same_v, unexpected> && !is_same_v, in_place_t>
+ && is_constructible_v<_Err, _UError>)
+ constexpr explicit unexpected(_UError&& _Unex) noexcept(is_nothrow_constructible_v<_Err, _UError>) // strengthened
+ : _Unexpected(_STD forward<_UError>(_Unex)) {}
+ // clang-format on
+
+ template
+ requires is_constructible_v<_Err, _Args...>
+ constexpr explicit unexpected(in_place_t, _Args&&... _Vals) noexcept(
+ is_nothrow_constructible_v<_Err, _Args...>) // strengthened
+ : _Unexpected(_STD forward<_Args>(_Vals)...) {}
+
+ // clang-format off
+ template
+ requires is_constructible_v<_Err, initializer_list<_Uty>&, _Args...>
+ constexpr explicit unexpected(in_place_t, initializer_list<_Uty> _Ilist, _Args&&... _Vals) noexcept(
+ is_nothrow_constructible_v<_Err, initializer_list<_Uty>&, _Args...>) // strengthened
+ : _Unexpected(_Ilist, _STD forward<_Args>(_Vals)...) {}
+ // clang-format on
+
+ // [expected.un.obs]
+ _NODISCARD constexpr const _Err& error() const& noexcept {
+ return _Unexpected;
+ }
+ _NODISCARD constexpr _Err& error() & noexcept {
+ return _Unexpected;
+ }
+ _NODISCARD constexpr const _Err&& error() const&& noexcept {
+ return _STD move(_Unexpected);
+ }
+ _NODISCARD constexpr _Err&& error() && noexcept {
+ return _STD move(_Unexpected);
+ }
+
+ // [expected.un.swap]
+ constexpr void swap(unexpected& _Other) noexcept(is_nothrow_swappable_v<_Err>) {
+ static_assert(is_swappable_v<_Err>, "E must be swappable");
+ _Swap_adl(_Unexpected, _Other._Unexpected);
+ }
+
+ friend constexpr void swap(unexpected& _Left, unexpected& _Right) noexcept(is_nothrow_swappable_v<_Err>) //
+ requires is_swappable_v<_Err> {
+ _Left.swap(_Right);
+ }
+
+ // [expected.un.eq]
+ template
+ _NODISCARD_FRIEND constexpr bool operator==(const unexpected& _Left, const unexpected<_UErr>& _Right) noexcept( //
+ noexcept(_Implicitly_convert_to(_Left._Unexpected == _Right.error()))) { // strengthened
+ return _Left._Unexpected == _Right.error();
+ }
+
+private:
+ _Err _Unexpected;
+};
+
+template
+unexpected(_Err) -> unexpected<_Err>;
+
+template
+class bad_expected_access;
+
+template <>
+class bad_expected_access : public exception {
+public:
+ _NODISCARD const char* __CLR_OR_THIS_CALL what() const noexcept override {
+ return "Bad expected access";
+ }
+
+protected:
+ bad_expected_access() = default;
+ bad_expected_access(const bad_expected_access&) = default;
+ bad_expected_access(bad_expected_access&&) = default;
+ bad_expected_access& operator=(const bad_expected_access&) = default;
+ bad_expected_access& operator=(bad_expected_access&&) = default;
+
+#if !_HAS_EXCEPTIONS
+ void _Doraise() const override { // perform class-specific exception handling
+ _RAISE(*this);
+ }
+#endif // !_HAS_EXCEPTIONS
+};
+
+template
+class bad_expected_access : public bad_expected_access {
+public:
+ explicit bad_expected_access(_Err _Unex) noexcept(is_nothrow_move_constructible_v<_Err>) // strengthened
+ : _Unexpected(_STD move(_Unex)) {}
+
+ _NODISCARD const _Err& error() const& noexcept {
+ return _Unexpected;
+ }
+ _NODISCARD _Err& error() & noexcept {
+ return _Unexpected;
+ }
+ _NODISCARD const _Err&& error() const&& noexcept {
+ return _STD move(_Unexpected);
+ }
+ _NODISCARD _Err&& error() && noexcept {
+ return _STD move(_Unexpected);
+ }
+
+private:
+ _Err _Unexpected;
+};
+
+struct unexpect_t {
+ explicit unexpect_t() = default;
+};
+
+inline constexpr unexpect_t unexpect{};
+
+template
+class expected {
+ static_assert(!is_reference_v<_Ty>, "T must not be a reference type. (N4910 [expected.object.general]/2)");
+ static_assert(!is_function_v<_Ty>, "T must not be a function type. (N4910 [expected.object.general]/2)");
+ static_assert(!is_same_v, in_place_t>,
+ "T must not be (possibly cv-qualified) in_place_t. (N4910 [expected.object.general]/2)");
+ static_assert(!is_same_v, unexpect_t>,
+ "T must not be (possibly cv-qualified) unexpect_t. (N4910 [expected.object.general]/2)");
+ static_assert(!_Is_specialization_v, unexpected>,
+ "T must not be a (possibly cv-qualified) specialization of unexpected. (N4910 [expected.object.general]/2)");
+
+ static_assert(_Check_unexpected_argument<_Err>::value);
+
+ template
+ friend class expected;
+
+public:
+ using value_type = _Ty;
+ using error_type = _Err;
+ using unexpected_type = unexpected<_Err>;
+
+ template
+ using rebind = expected<_Uty, error_type>;
+
+ // [expected.object.ctor]
+ constexpr expected() noexcept(is_nothrow_default_constructible_v<_Ty>) // strengthened
+ requires is_default_constructible_v<_Ty> //
+ : _Value(), _Has_value(true) {}
+
+ // clang-format off
+ constexpr expected(const expected& _Other) noexcept(
+ is_nothrow_copy_constructible_v<_Ty>&& is_nothrow_copy_constructible_v<_Err>) // strengthened
+ requires (!(is_trivially_copy_constructible_v<_Ty> && is_trivially_copy_constructible_v<_Err>)
+ && is_copy_constructible_v<_Ty> && is_copy_constructible_v<_Err>)
+ : _Has_value(_Other._Has_value) {
+ // clang-format on
+ if (_Has_value) {
+ _STD construct_at(_STD addressof(_Value), _Other._Value);
+ } else {
+ _STD construct_at(_STD addressof(_Unexpected), _Other._Unexpected);
+ }
+ }
+
+ // clang-format off
+ expected(const expected&) requires
+ is_trivially_copy_constructible_v<_Ty> && is_trivially_copy_constructible_v<_Err> = default;
+
+ constexpr expected(expected&& _Other) noexcept(
+ is_nothrow_move_constructible_v<_Ty>&& is_nothrow_move_constructible_v<_Err>)
+ requires (!(is_trivially_move_constructible_v<_Ty> && is_trivially_move_constructible_v<_Err>)
+ && is_move_constructible_v<_Ty> && is_move_constructible_v<_Err>)
+ : _Has_value(_Other._Has_value) {
+ // clang-format on
+ if (_Has_value) {
+ _STD construct_at(_STD addressof(_Value), _STD move(_Other._Value));
+ } else {
+ _STD construct_at(_STD addressof(_Unexpected), _STD move(_Other._Unexpected));
+ }
+ }
+
+ // clang-format off
+ expected(expected&&) requires
+ is_trivially_move_constructible_v<_Ty> && is_trivially_move_constructible_v<_Err> = default;
+ // clang-format on
+
+ template
+ static constexpr bool _Allow_unwrapping = !is_constructible_v<_Ty, expected<_Uty, _UErr>&> //
+ && !is_constructible_v<_Ty, expected<_Uty, _UErr>> //
+ && !is_constructible_v<_Ty, const expected<_Uty, _UErr>&> //
+ && !is_constructible_v<_Ty, const expected<_Uty, _UErr>> //
+ && !is_convertible_v&, _Ty> //
+ && !is_convertible_v&&, _Ty> //
+ && !is_convertible_v&, _Ty> //
+ && !is_convertible_v&&, _Ty> //
+ && !is_constructible_v, expected<_Uty, _UErr>&> //
+ && !is_constructible_v, expected<_Uty, _UErr>> //
+ && !is_constructible_v, const expected<_Uty, _UErr>&> //
+ && !is_constructible_v, const expected<_Uty, _UErr>>;
+
+ template
+ requires is_constructible_v<_Ty, const _Uty&> && is_constructible_v<_Err, const _UErr&> //
+ && _Allow_unwrapping<_Uty, _UErr>
+ constexpr explicit(!is_convertible_v || !is_convertible_v)
+ expected(const expected<_Uty, _UErr>& _Other) noexcept(is_nothrow_constructible_v<_Ty, const _Uty&> //
+ && is_nothrow_constructible_v<_Err, const _UErr&>) // strengthened
+ : _Has_value(_Other._Has_value) {
+ if (_Has_value) {
+ _STD construct_at(_STD addressof(_Value), _Other._Value);
+ } else {
+ _STD construct_at(_STD addressof(_Unexpected), _Other._Unexpected);
+ }
+ }
+
+ template
+ requires is_constructible_v<_Ty, _Uty> && is_constructible_v<_Err, _UErr> && _Allow_unwrapping<_Uty, _UErr>
+ constexpr explicit(!is_convertible_v<_Uty, _Ty> || !is_convertible_v<_UErr, _Err>)
+ expected(expected<_Uty, _UErr>&& _Other) noexcept(
+ is_nothrow_constructible_v<_Ty, _Uty>&& is_nothrow_constructible_v<_Err, _UErr>) // strengthened
+ : _Has_value(_Other._Has_value) {
+ if (_Has_value) {
+ _STD construct_at(_STD addressof(_Value), _STD move(_Other._Value));
+ } else {
+ _STD construct_at(_STD addressof(_Unexpected), _STD move(_Other._Unexpected));
+ }
+ }
+
+ // clang-format off
+ template
+ requires (!is_same_v, in_place_t> && !is_same_v, expected>
+ && !_Is_specialization_v, unexpected> && is_constructible_v<_Ty, _Uty>)
+ constexpr explicit(!is_convertible_v<_Uty, _Ty>)
+ expected(_Uty&& _Other) noexcept(is_nothrow_constructible_v<_Ty, _Uty>) // strengthened
+ : _Value(_STD forward<_Uty>(_Other)), _Has_value(true) {}
+ // clang-format on
+
+ template
+ requires is_constructible_v<_Err, const _UErr&>
+ constexpr explicit(!is_convertible_v) expected(const unexpected<_UErr>& _Other) //
+ noexcept(is_nothrow_constructible_v<_Err, const _UErr&>) // strengthened
+ : _Unexpected(_Other._Unexpected), _Has_value(false) {}
+
+ template
+ requires is_constructible_v<_Err, _UErr>
+ constexpr explicit(!is_convertible_v<_UErr, _Err>) expected(unexpected<_UErr>&& _Other) //
+ noexcept(is_nothrow_constructible_v<_Err, _UErr>) // strengthened
+ : _Unexpected(_STD move(_Other._Unexpected)), _Has_value(false) {}
+
+ template
+ requires is_constructible_v<_Ty, _Args...>
+ constexpr explicit expected(in_place_t, _Args&&... _Vals) noexcept(
+ is_nothrow_constructible_v<_Ty, _Args...>) // strengthened
+ : _Value(_STD forward<_Args>(_Vals)...), _Has_value(true) {}
+
+ // clang-format off
+ template
+ requires is_constructible_v<_Ty, initializer_list<_Uty>&, _Args...>
+ constexpr explicit expected(in_place_t, initializer_list<_Uty> _Ilist, _Args&&... _Vals) noexcept(
+ is_nothrow_constructible_v<_Ty, initializer_list<_Uty>&, _Args...>) // strengthened
+ : _Value(_Ilist, _STD forward<_Args>(_Vals)...), _Has_value(true) {}
+ // clang-format on
+
+ template
+ requires is_constructible_v<_Err, _Args...>
+ constexpr explicit expected(unexpect_t, _Args&&... _Vals) noexcept(
+ is_nothrow_constructible_v<_Err, _Args...>) // strengthened
+ : _Unexpected(_STD forward<_Args>(_Vals)...), _Has_value(false) {}
+
+ // clang-format off
+ template
+ requires is_constructible_v<_Err, initializer_list<_Uty>&, _Args...>
+ constexpr explicit expected(unexpect_t, initializer_list<_Uty> _Ilist, _Args&&... _Vals) noexcept(
+ is_nothrow_constructible_v<_Err, initializer_list<_Uty>&, _Args...>) // strengthened
+ : _Unexpected(_Ilist, _STD forward<_Args>(_Vals)...), _Has_value(false) {}
+ // clang-format on
+
+ // [expected.object.dtor]
+ constexpr ~expected() noexcept {
+ if (_Has_value) {
+ if constexpr (!is_trivially_destructible_v<_Ty>) {
+ _Value.~_Ty();
+ }
+ } else {
+ if constexpr (!is_trivially_destructible_v<_Err>) {
+ _Unexpected.~_Err();
+ }
+ }
+ }
+
+ // clang-format off
+ // TRANSITION, LLVM-46269, destructor order is significant
+ ~expected() requires is_trivially_destructible_v<_Ty> && is_trivially_destructible_v<_Err> = default;
+ // clang-format on
+
+ // [expected.object.assign]
+ template
+ requires is_nothrow_move_constructible_v<_Uty>
+ struct _NODISCARD _GuardTy {
+ constexpr _GuardTy(_Uty* _Target_, _Uty* _Tmp_) noexcept : _Target(_Target_), _Tmp(_Tmp_) {}
+ constexpr ~_GuardTy() noexcept {
+ if (_Target) {
+ _STD construct_at(_Target, _STD move(*_Tmp));
+ }
+ }
+ _Uty* _Target;
+ _Uty* _Tmp;
+ };
+
+ template
+ static constexpr void _Reinit_expected(_First& _New_val, _Second& _Old_val, _Args&&... _Vals) noexcept(
+ is_nothrow_constructible_v<_First, _Args...>) // strengthened
+ {
+ if constexpr (is_nothrow_constructible_v<_First, _Args...>) {
+ if constexpr (!is_trivially_destructible_v<_Second>) {
+ _Old_val.~_Second();
+ }
+ _STD construct_at(_STD addressof(_New_val), _STD forward<_Args>(_Vals)...);
+ } else if constexpr (is_nothrow_move_constructible_v<_First>) {
+ _First _Tmp(_STD forward<_Args>(_Vals)...);
+ if constexpr (!is_trivially_destructible_v<_Second>) {
+ _Old_val.~_Second();
+ }
+ _STD construct_at(_STD addressof(_New_val), _STD move(_Tmp));
+ } else {
+ _Second _Tmp(_STD move(_Old_val));
+ if constexpr (!is_trivially_destructible_v<_Second>) {
+ _Old_val.~_Second();
+ }
+
+ _GuardTy<_Second> _Guard{_STD addressof(_Old_val), _STD addressof(_Tmp)};
+ _STD construct_at(_STD addressof(_New_val), _STD forward<_Args>(_Vals)...);
+ _Guard._Target = nullptr;
+ }
+ }
+
+ constexpr expected& operator=(const expected& _Other) noexcept(
+ is_nothrow_copy_constructible_v<_Ty>&& is_nothrow_copy_constructible_v<_Err> //
+ && is_nothrow_copy_assignable_v<_Ty>&& is_nothrow_copy_assignable_v<_Err>) // strengthened
+ requires is_copy_assignable_v<_Ty> && is_copy_constructible_v<_Ty> //
+ && is_copy_assignable_v<_Err> && is_copy_constructible_v<_Err> //
+ &&(is_nothrow_move_constructible_v<_Ty> || is_nothrow_move_constructible_v<_Err>) {
+ if (_Has_value && _Other._Has_value) {
+ _Value = _Other._Value;
+ } else if (_Has_value) {
+ _Reinit_expected(_Unexpected, _Value, _Other._Unexpected);
+ } else if (_Other._Has_value) {
+ _Reinit_expected(_Value, _Unexpected, _Other._Value);
+ } else {
+ _Unexpected = _Other._Unexpected;
+ }
+
+ _Has_value = _Other._Has_value;
+ return *this;
+ }
+
+ constexpr expected& operator=(expected&& _Other) noexcept(
+ is_nothrow_move_constructible_v<_Ty>&& is_nothrow_move_constructible_v<_Err> //
+ && is_nothrow_move_assignable_v<_Ty>&& is_nothrow_move_assignable_v<_Err>) //
+ requires is_move_assignable_v<_Ty> && is_move_constructible_v<_Ty> //
+ && is_move_assignable_v<_Err> && is_move_constructible_v<_Err> //
+ &&(is_nothrow_move_constructible_v<_Ty> || is_nothrow_move_constructible_v<_Err>) {
+ if (_Has_value && _Other._Has_value) {
+ _Value = _STD move(_Other._Value);
+ } else if (_Has_value) {
+ _Reinit_expected(_Unexpected, _Value, _STD move(_Other._Unexpected));
+ } else if (_Other._Has_value) {
+ _Reinit_expected(_Value, _Unexpected, _STD move(_Other._Value));
+ } else {
+ _Unexpected = _STD move(_Other._Unexpected);
+ }
+
+ _Has_value = _Other._Has_value;
+ return *this;
+ }
+
+ // clang-format off
+ template
+ requires (!is_same_v, expected> && !_Is_specialization_v, unexpected>
+ && is_constructible_v<_Ty, _Uty> && is_assignable_v<_Ty&, _Uty> && (is_nothrow_constructible_v<_Ty, _Uty>
+ || is_nothrow_move_constructible_v<_Ty> || is_nothrow_move_constructible_v<_Err>))
+ constexpr expected& operator=(_Uty&& _Other) noexcept(
+ is_nothrow_constructible_v<_Ty, _Uty>&& is_nothrow_assignable_v<_Ty&, _Uty>) { // strengthened
+ // clang-format on
+ if (_Has_value) {
+ _Value = _STD forward<_Uty>(_Other);
+ } else {
+ _Reinit_expected(_Value, _Unexpected, _STD forward<_Uty>(_Other));
+ _Has_value = true;
+ }
+
+ return *this;
+ }
+
+ // clang-format off
+ template
+ requires (is_constructible_v<_Err, const _UErr&>&& is_assignable_v<_Err&, const _UErr&>
+ && (is_nothrow_constructible_v<_Err, const _UErr&> || is_nothrow_move_constructible_v<_Ty>
+ || is_nothrow_move_constructible_v<_Err>) )
+ constexpr expected& operator=(const unexpected<_UErr>& _Other) noexcept(
+ is_nothrow_constructible_v<_Err, const _UErr&>&& is_nothrow_assignable_v<_Err&, const _UErr&>) { // strengthened
+ // clang-format on
+ if (_Has_value) {
+ _Reinit_expected(_Unexpected, _Value, _Other._Unexpected);
+ _Has_value = false;
+ } else {
+ _Unexpected = _Other._Unexpected;
+ }
+
+ return *this;
+ }
+
+ // clang-format off
+ template
+ requires (is_constructible_v<_Err, _UErr>&& is_assignable_v<_Err&, _UErr>
+ && (is_nothrow_constructible_v<_Err, _UErr> || is_nothrow_move_constructible_v<_Ty>
+ || is_nothrow_move_constructible_v<_Err>) )
+ constexpr expected& operator=(unexpected<_UErr>&& _Other) noexcept(
+ is_nothrow_constructible_v<_Err, _UErr>&& is_nothrow_assignable_v<_Err&, _UErr>) { // strengthened
+ // clang-format on
+ if (_Has_value) {
+ _Reinit_expected(_Unexpected, _Value, _STD move(_Other._Unexpected));
+ _Has_value = false;
+ } else {
+ _Unexpected = _STD move(_Other._Unexpected);
+ }
+
+ return *this;
+ }
+
+ template
+ requires is_nothrow_constructible_v<_Ty, _Args...>
+ constexpr _Ty& emplace(_Args&&... _Vals) noexcept {
+ if (_Has_value) {
+ if constexpr (!is_trivially_destructible_v<_Ty>) {
+ _Value.~_Ty();
+ }
+ } else {
+ if constexpr (!is_trivially_destructible_v<_Err>) {
+ _Unexpected.~_Err();
+ }
+ _Has_value = true;
+ }
+
+ return *_STD construct_at(_STD addressof(_Value), _STD forward<_Args>(_Vals)...);
+ }
+
+ // clang-format off
+ template
+ requires is_nothrow_constructible_v<_Ty, initializer_list<_Uty>&, _Args...>
+ constexpr _Ty& emplace(initializer_list<_Uty> _Ilist, _Args&&... _Vals) noexcept {
+ // clang-format on
+ if (_Has_value) {
+ if constexpr (!is_trivially_destructible_v<_Ty>) {
+ _Value.~_Ty();
+ }
+ } else {
+ if constexpr (!is_trivially_destructible_v<_Err>) {
+ _Unexpected.~_Err();
+ }
+ _Has_value = true;
+ }
+
+ return *_STD construct_at(_STD addressof(_Value), _Ilist, _STD forward<_Args>(_Vals)...);
+ }
+
+ // [expected.object.swap]
+ constexpr void swap(expected& _Other) noexcept(is_nothrow_move_constructible_v<_Ty>&& is_nothrow_swappable_v<_Ty>&&
+ is_nothrow_move_constructible_v<_Err>&& is_nothrow_swappable_v<_Err>) //
+ requires is_swappable_v<_Ty> && is_swappable_v<_Err> //
+ && is_move_constructible_v<_Ty> && is_move_constructible_v<_Err> //
+ &&(is_nothrow_move_constructible_v<_Ty> || is_nothrow_move_constructible_v<_Err>) {
+ if (_Has_value && _Other._Has_value) {
+ _Swap_adl(_Value, _Other._Value);
+ } else if (_Has_value) {
+ if constexpr (is_nothrow_move_constructible_v<_Err>) {
+ _Err _Tmp(_STD move(_Other._Unexpected));
+ if constexpr (!is_trivially_destructible_v<_Err>) {
+ _Other._Unexpected.~_Err();
+ }
+
+ if constexpr (is_nothrow_move_constructible_v<_Ty>) {
+ _STD construct_at(_STD addressof(_Other._Value), _STD move(_Value));
+ } else {
+ _GuardTy<_Err> _Guard{_STD addressof(_Other._Unexpected), _STD addressof(_Tmp)};
+ _STD construct_at(_STD addressof(_Other._Value), _STD move(_Value));
+ _Guard._Target = nullptr;
+ }
+
+ if constexpr (!is_trivially_destructible_v<_Ty>) {
+ _Value.~_Ty();
+ }
+ _STD construct_at(_STD addressof(_Unexpected), _STD move(_Tmp));
+ } else {
+ _Ty _Tmp(_STD move(_Value));
+ if constexpr (!is_trivially_destructible_v<_Ty>) {
+ _Value.~_Ty();
+ }
+
+ _GuardTy<_Ty> _Guard{_STD addressof(_Value), _STD addressof(_Tmp)};
+ _STD construct_at(_STD addressof(_Unexpected), _STD move(_Other._Unexpected));
+ _Guard._Target = nullptr;
+
+ if constexpr (!is_trivially_destructible_v<_Err>) {
+ _Other._Unexpected.~_Err();
+ }
+ _STD construct_at(_STD addressof(_Other._Value), _STD move(_Tmp));
+ }
+
+ _Has_value = false;
+ _Other._Has_value = true;
+ } else if (_Other._Has_value) {
+ _Other.swap(*this);
+ } else {
+ _Swap_adl(_Unexpected, _Other._Unexpected);
+ }
+ }
+
+ friend constexpr void swap(expected& _Lhs, expected& _Rhs) noexcept(is_nothrow_move_constructible_v<_Ty>&&
+ is_nothrow_swappable_v<_Ty>&& is_nothrow_move_constructible_v<_Err>&& is_nothrow_swappable_v<_Err>) //
+ requires is_swappable_v<_Ty> && is_swappable_v<_Err> //
+ && is_move_constructible_v<_Ty> && is_move_constructible_v<_Err> //
+ &&(is_nothrow_move_constructible_v<_Ty> || is_nothrow_move_constructible_v<_Err>) {
+ _Lhs.swap(_Rhs);
+ }
+
+ // [expected.object.obs]
+ _NODISCARD constexpr const _Ty* operator->() const noexcept {
+#if _CONTAINER_DEBUG_LEVEL > 0
+ _STL_VERIFY(_Has_value, "expected stores an error, not a value");
+#endif // _CONTAINER_DEBUG_LEVEL > 0
+ return _STD addressof(_Value);
+ }
+ _NODISCARD constexpr _Ty* operator->() noexcept {
+#if _CONTAINER_DEBUG_LEVEL > 0
+ _STL_VERIFY(_Has_value, "expected stores an error, not a value");
+#endif // _CONTAINER_DEBUG_LEVEL > 0
+ return _STD addressof(_Value);
+ }
+
+ _NODISCARD constexpr const _Ty& operator*() const& noexcept {
+#if _CONTAINER_DEBUG_LEVEL > 0
+ _STL_VERIFY(_Has_value, "expected stores an error, not a value");
+#endif // _CONTAINER_DEBUG_LEVEL > 0
+ return _Value;
+ }
+ _NODISCARD constexpr _Ty& operator*() & noexcept {
+#if _CONTAINER_DEBUG_LEVEL > 0
+ _STL_VERIFY(_Has_value, "expected stores an error, not a value");
+#endif // _CONTAINER_DEBUG_LEVEL > 0
+ return _Value;
+ }
+ _NODISCARD constexpr const _Ty&& operator*() const&& noexcept {
+#if _CONTAINER_DEBUG_LEVEL > 0
+ _STL_VERIFY(_Has_value, "expected stores an error, not a value");
+#endif // _CONTAINER_DEBUG_LEVEL > 0
+ return _STD move(_Value);
+ }
+ _NODISCARD constexpr _Ty&& operator*() && noexcept {
+#if _CONTAINER_DEBUG_LEVEL > 0
+ _STL_VERIFY(_Has_value, "expected stores an error, not a value");
+#endif // _CONTAINER_DEBUG_LEVEL > 0
+ return _STD move(_Value);
+ }
+
+ _NODISCARD constexpr explicit operator bool() const noexcept {
+ return _Has_value;
+ }
+ _NODISCARD constexpr bool has_value() const noexcept {
+ return _Has_value;
+ }
+
+ _NODISCARD constexpr const _Ty& value() const& {
+ if (_Has_value) {
+ return _Value;
+ }
+
+ _Throw_bad_expected_access_lv();
+ }
+ _NODISCARD constexpr _Ty& value() & {
+ if (_Has_value) {
+ return _Value;
+ }
+
+ _Throw_bad_expected_access_lv();
+ }
+ _NODISCARD constexpr const _Ty&& value() const&& {
+ if (_Has_value) {
+ return _STD move(_Value);
+ }
+
+ _Throw_bad_expected_access_rv();
+ }
+ _NODISCARD constexpr _Ty&& value() && {
+ if (_Has_value) {
+ return _STD move(_Value);
+ }
+
+ _Throw_bad_expected_access_rv();
+ }
+
+ _NODISCARD constexpr const _Err& error() const& noexcept {
+#if _CONTAINER_DEBUG_LEVEL > 0
+ _STL_VERIFY(!_Has_value, "expected stores a value, not an error");
+#endif // _CONTAINER_DEBUG_LEVEL > 0
+ return _Unexpected;
+ }
+ _NODISCARD constexpr _Err& error() & noexcept {
+#if _CONTAINER_DEBUG_LEVEL > 0
+ _STL_VERIFY(!_Has_value, "expected stores a value, not an error");
+#endif // _CONTAINER_DEBUG_LEVEL > 0
+ return _Unexpected;
+ }
+ _NODISCARD constexpr const _Err&& error() const&& noexcept {
+#if _CONTAINER_DEBUG_LEVEL > 0
+ _STL_VERIFY(!_Has_value, "expected stores a value, not an error");
+#endif // _CONTAINER_DEBUG_LEVEL > 0
+ return _STD move(_Unexpected);
+ }
+ _NODISCARD constexpr _Err&& error() && noexcept {
+#if _CONTAINER_DEBUG_LEVEL > 0
+ _STL_VERIFY(!_Has_value, "expected stores a value, not an error");
+#endif // _CONTAINER_DEBUG_LEVEL > 0
+ return _STD move(_Unexpected);
+ }
+
+ template
+ _NODISCARD constexpr _Ty value_or(_Uty&& _Other) const& noexcept(
+ is_nothrow_copy_constructible_v<_Ty>&& is_nothrow_convertible_v<_Uty, _Ty>) { // strengthened
+ static_assert(
+ is_copy_constructible_v<_Ty>, "is_copy_constructible_v must be true. (N4910 [expected.object.obs]/16)");
+ static_assert(
+ is_convertible_v<_Uty, _Ty>, "is_convertible_v must be true. (N4910 [expected.object.obs]/16)");
+
+ if (_Has_value) {
+ return _Value;
+ } else {
+ return static_cast<_Ty>(_STD forward<_Uty>(_Other));
+ }
+ }
+ template
+ _NODISCARD constexpr _Ty value_or(_Uty&& _Other) && noexcept(
+ is_nothrow_move_constructible_v<_Ty>&& is_nothrow_convertible_v<_Uty, _Ty>) { // strengthened
+ static_assert(
+ is_move_constructible_v<_Ty>, "is_move_constructible_v must be true. (N4910 [expected.object.obs]/18)");
+ static_assert(
+ is_convertible_v<_Uty, _Ty>, "is_convertible_v must be true. (N4910 [expected.object.obs]/18)");
+
+ if (_Has_value) {
+ return _STD move(_Value);
+ } else {
+ return static_cast<_Ty>(_STD forward<_Uty>(_Other));
+ }
+ }
+
+ // [expected.object.eq]
+
+ // clang-format off
+ template
+ requires (!is_void_v<_Uty>)
+ _NODISCARD_FRIEND constexpr bool operator==(const expected& _Left, const expected<_Uty, _UErr>& _Right) noexcept(
+ noexcept(_Implicitly_convert_to(_Left._Value == *_Right)) && noexcept(
+ _Implicitly_convert_to(_Left._Unexpected == _Right.error()))) { // strengthened
+ // clang-format on
+ if (_Left._Has_value != _Right.has_value()) {
+ return false;
+ } else if (_Left._Has_value) {
+ return _Left._Value == *_Right;
+ } else {
+ return _Left._Unexpected == _Right.error();
+ }
+ }
+
+ template
+ _NODISCARD_FRIEND constexpr bool operator==(const expected& _Left, const _Uty& _Right) noexcept(
+ noexcept(static_cast(_Left._Value == _Right))) { // strengthened
+ if (_Left._Has_value) {
+ return static_cast(_Left._Value == _Right);
+ } else {
+ return false;
+ }
+ }
+
+ template
+ _NODISCARD_FRIEND constexpr bool operator==(const expected& _Left, const unexpected<_UErr>& _Right) noexcept(
+ noexcept(static_cast(_Left._Unexpected == _Right.error()))) { // strengthened
+ if (_Left._Has_value) {
+ return false;
+ } else {
+ return static_cast(_Left._Unexpected == _Right.error());
+ }
+ }
+
+private:
+ [[noreturn]] void _Throw_bad_expected_access_lv() const {
+ _THROW(bad_expected_access{_Unexpected});
+ }
+ [[noreturn]] void _Throw_bad_expected_access_lv() {
+ _THROW(bad_expected_access{_Unexpected});
+ }
+ [[noreturn]] void _Throw_bad_expected_access_rv() const {
+ _THROW(bad_expected_access{_STD move(_Unexpected)});
+ }
+ [[noreturn]] void _Throw_bad_expected_access_rv() {
+ _THROW(bad_expected_access{_STD move(_Unexpected)});
+ }
+
+ union {
+ _Ty _Value;
+ _Err _Unexpected;
+ };
+ bool _Has_value;
+};
+
+template
+ requires is_void_v<_Ty>
+class expected<_Ty, _Err> {
+ static_assert(_Check_unexpected_argument<_Err>::value);
+
+ template
+ friend class expected;
+
+public:
+ using value_type = _Ty;
+ using error_type = _Err;
+ using unexpected_type = unexpected<_Err>;
+
+ template
+ using rebind = expected<_Uty, error_type>;
+
+ // [expected.void.ctor]
+ constexpr expected() noexcept : _Has_value(true) {}
+
+ // clang-format off
+ constexpr expected(const expected& _Other) noexcept(is_nothrow_copy_constructible_v<_Err>) // strengthened
+ requires (!is_trivially_copy_constructible_v<_Err> && is_copy_constructible_v<_Err>)
+ : _Has_value(_Other._Has_value) {
+ if (!_Has_value) {
+ _STD construct_at(_STD addressof(_Unexpected), _Other._Unexpected);
+ }
+ }
+
+ expected(const expected&) requires is_trivially_copy_constructible_v<_Err> = default;
+
+ constexpr expected(expected&& _Other) noexcept(is_nothrow_move_constructible_v<_Err>)
+ requires (!is_trivially_move_constructible_v<_Err> && is_move_constructible_v<_Err>)
+ : _Has_value(_Other._Has_value) {
+ if (!_Has_value) {
+ _STD construct_at(_STD addressof(_Unexpected), _STD move(_Other._Unexpected));
+ }
+ }
+
+ expected(expected&&) requires is_trivially_move_constructible_v<_Err> = default;
+ // clang-format on
+
+ template
+ static constexpr bool _Allow_unwrapping = !is_constructible_v, expected<_Uty, _UErr>&> //
+ && !is_constructible_v, expected<_Uty, _UErr>> //
+ && !is_constructible_v, const expected<_Uty, _UErr>&> //
+ && !is_constructible_v, const expected<_Uty, _UErr>>;
+
+ template
+ requires is_void_v<_Uty> && is_constructible_v<_Err, const _UErr&> && _Allow_unwrapping<_Uty, _UErr>
+ constexpr explicit(!is_convertible_v) expected(const expected<_Uty, _UErr>& _Other) noexcept(
+ is_nothrow_constructible_v<_Err, const _UErr&>) // strengthened
+ : _Has_value(_Other._Has_value) {
+ if (!_Has_value) {
+ _STD construct_at(_STD addressof(_Unexpected), _Other._Unexpected);
+ }
+ }
+
+ template
+ requires is_void_v<_Uty> && is_constructible_v<_Err, _UErr> && _Allow_unwrapping<_Uty, _UErr>
+ constexpr explicit(!is_convertible_v<_UErr, _Err>)
+ expected(expected<_Uty, _UErr>&& _Other) noexcept(is_nothrow_constructible_v<_Err, _UErr>) // strengthened
+ : _Has_value(_Other._Has_value) {
+ if (!_Has_value) {
+ _STD construct_at(_STD addressof(_Unexpected), _STD move(_Other._Unexpected));
+ }
+ }
+
+ template
+ requires is_constructible_v<_Err, const _UErr&>
+ constexpr explicit(!is_convertible_v) expected(const unexpected<_UErr>& _Other) //
+ noexcept(is_nothrow_constructible_v<_Err, const _UErr&>) // strengthened
+ : _Unexpected(_Other._Unexpected), _Has_value(false) {}
+
+ template
+ requires is_constructible_v<_Err, _UErr>
+ constexpr explicit(!is_convertible_v<_UErr, _Err>) expected(unexpected<_UErr>&& _Other) //
+ noexcept(is_nothrow_constructible_v<_Err, _UErr>) // strengthened
+ : _Unexpected(_STD move(_Other._Unexpected)), _Has_value(false) {}
+
+ constexpr explicit expected(in_place_t) noexcept : _Has_value(true) {}
+
+ template
+ requires is_constructible_v<_Err, _Args...>
+ constexpr explicit expected(unexpect_t, _Args&&... _Vals) noexcept(
+ is_nothrow_constructible_v<_Err, _Args...>) // strengthened
+ : _Unexpected(_STD forward<_Args>(_Vals)...), _Has_value(false) {}
+
+ // clang-format off
+ template
+ requires is_constructible_v<_Err, initializer_list<_Uty>&, _Args...>
+ constexpr explicit expected(unexpect_t, initializer_list<_Uty> _Ilist, _Args&&... _Vals) noexcept(
+ is_nothrow_constructible_v<_Err, initializer_list<_Uty>&, _Args...>) // strengthened
+ : _Unexpected(_Ilist, _STD forward<_Args>(_Vals)...), _Has_value(false) {}
+ // clang-format on
+
+ // [expected.void.dtor]
+ constexpr ~expected() noexcept {
+ if (!_Has_value) {
+ _Unexpected.~_Err();
+ }
+ }
+
+ // clang-format off
+ // TRANSITION, LLVM-46269, destructor order is significant
+ ~expected() requires is_trivially_destructible_v<_Err> = default;
+ // clang-format on
+
+ // [expected.void.assign]
+ constexpr expected& operator=(const expected& _Other) noexcept(
+ is_nothrow_copy_constructible_v<_Err>&& is_nothrow_copy_assignable_v<_Err>) // strengthened
+ requires is_copy_assignable_v<_Err> && is_copy_constructible_v<_Err> {
+ if (_Has_value && _Other._Has_value) {
+ // nothing to do
+ } else if (_Has_value) {
+ _STD construct_at(_STD addressof(_Unexpected), _Other._Unexpected);
+ _Has_value = false;
+ } else if (_Other._Has_value) {
+ if constexpr (!is_trivially_destructible_v<_Err>) {
+ _Unexpected.~_Err();
+ }
+ _Has_value = true;
+ } else {
+ _Unexpected = _Other._Unexpected;
+ }
+
+ return *this;
+ }
+
+ constexpr expected& operator=(expected&& _Other) noexcept(
+ is_nothrow_move_constructible_v<_Err>&& is_nothrow_move_assignable_v<_Err>) //
+ requires is_move_assignable_v<_Err> && is_move_constructible_v<_Err> {
+ if (_Has_value && _Other._Has_value) {
+ // nothing to do
+ } else if (_Has_value) {
+ _STD construct_at(_STD addressof(_Unexpected), _STD move(_Other._Unexpected));
+ _Has_value = false;
+ } else if (_Other._Has_value) {
+ if constexpr (!is_trivially_destructible_v<_Err>) {
+ _Unexpected.~_Err();
+ }
+ _Has_value = true;
+ } else {
+ _Unexpected = _STD move(_Other._Unexpected);
+ }
+
+ return *this;
+ }
+
+ template
+ requires is_constructible_v<_Err, const _UErr&> && is_assignable_v<_Err&, const _UErr&>
+ constexpr expected& operator=(const unexpected<_UErr>& _Other) noexcept(
+ is_nothrow_constructible_v<_Err, const _UErr&>&& is_nothrow_assignable_v<_Err&, const _UErr&>) { // strengthened
+ if (_Has_value) {
+ _STD construct_at(_STD addressof(_Unexpected), _Other._Unexpected);
+ _Has_value = false;
+ } else {
+ _Unexpected = _Other._Unexpected;
+ }
+
+ return *this;
+ }
+
+ template
+ requires is_constructible_v<_Err, _UErr> && is_assignable_v<_Err&, _UErr>
+ constexpr expected& operator=(unexpected<_UErr>&& _Other) noexcept(
+ is_nothrow_constructible_v<_Err, _UErr>&& is_nothrow_assignable_v<_Err&, _UErr>) { // strengthened
+ if (_Has_value) {
+ _STD construct_at(_STD addressof(_Unexpected), _STD move(_Other._Unexpected));
+ _Has_value = false;
+ } else {
+ _Unexpected = _STD move(_Other._Unexpected);
+ }
+
+ return *this;
+ }
+
+ constexpr void emplace() noexcept {
+ if (!_Has_value) {
+ if constexpr (!is_trivially_destructible_v<_Err>) {
+ _Unexpected.~_Err();
+ }
+ _Has_value = true;
+ }
+ }
+
+ // [expected.void.swap]
+ constexpr void swap(expected& _Other) noexcept(
+ is_nothrow_move_constructible_v<_Err>&& is_nothrow_swappable_v<_Err>) //
+ requires is_swappable_v<_Err> && is_move_constructible_v<_Err> {
+ if (_Has_value && _Other._Has_value) {
+ // nothing
+ } else if (_Has_value) {
+ _STD construct_at(_STD addressof(_Unexpected), _STD move(_Other._Unexpected));
+ if constexpr (!is_trivially_destructible_v<_Err>) {
+ _Other._Unexpected.~_Err();
+ }
+ _Has_value = false;
+ _Other._Has_value = true;
+ } else if (_Other._Has_value) {
+ _STD construct_at(_STD addressof(_Other._Unexpected), _STD move(_Unexpected));
+ if constexpr (!is_trivially_destructible_v<_Err>) {
+ _Unexpected.~_Err();
+ }
+ _Has_value = true;
+ _Other._Has_value = false;
+ } else {
+ _Swap_adl(_Unexpected, _Other._Unexpected);
+ }
+ }
+
+ friend constexpr void swap(expected& _Left, expected& _Right) noexcept(
+ is_nothrow_move_constructible_v<_Err>&& is_nothrow_swappable_v<_Err>) //
+ requires is_swappable_v<_Err> && is_move_constructible_v<_Err> {
+ if (_Left._Has_value && _Right._Has_value) {
+ // nothing
+ } else if (_Left._Has_value) {
+ _STD construct_at(_STD addressof(_Left._Unexpected), _STD move(_Right._Unexpected));
+ if constexpr (!is_trivially_destructible_v<_Err>) {
+ _Right._Unexpected.~_Err();
+ }
+ _Left._Has_value = false;
+ _Right._Has_value = true;
+ } else if (_Right._Has_value) {
+ _STD construct_at(_STD addressof(_Right._Unexpected), _STD move(_Left._Unexpected));
+ if constexpr (!is_trivially_destructible_v<_Err>) {
+ _Left._Unexpected.~_Err();
+ }
+ _Left._Has_value = true;
+ _Right._Has_value = false;
+ } else {
+ _Swap_adl(_Left._Unexpected, _Right._Unexpected);
+ }
+ }
+
+ // [expected.void.obs]
+ _NODISCARD constexpr explicit operator bool() const noexcept {
+ return _Has_value;
+ }
+ _NODISCARD constexpr bool has_value() const noexcept {
+ return _Has_value;
+ }
+
+ constexpr void operator*() const noexcept {
+#if _CONTAINER_DEBUG_LEVEL > 0
+ _STL_VERIFY(_Has_value, "expected stores an error, not a value");
+#endif // _CONTAINER_DEBUG_LEVEL > 0
+ }
+
+ constexpr void value() const& {
+ if (!_Has_value) {
+ _Throw_bad_expected_access_lv();
+ }
+ }
+ constexpr void value() && {
+ if (!_Has_value) {
+ _Throw_bad_expected_access_rv();
+ }
+ }
+
+ _NODISCARD constexpr const _Err& error() const& noexcept {
+#if _CONTAINER_DEBUG_LEVEL > 0
+ _STL_VERIFY(!_Has_value, "expected stores a value, not an error");
+#endif // _CONTAINER_DEBUG_LEVEL > 0
+ return _Unexpected;
+ }
+ _NODISCARD constexpr _Err& error() & noexcept {
+#if _CONTAINER_DEBUG_LEVEL > 0
+ _STL_VERIFY(!_Has_value, "expected stores a value, not an error");
+#endif // _CONTAINER_DEBUG_LEVEL > 0
+ return _Unexpected;
+ }
+ _NODISCARD constexpr const _Err&& error() const&& noexcept {
+#if _CONTAINER_DEBUG_LEVEL > 0
+ _STL_VERIFY(!_Has_value, "expected stores a value, not an error");
+#endif // _CONTAINER_DEBUG_LEVEL > 0
+ return _STD move(_Unexpected);
+ }
+ _NODISCARD constexpr _Err&& error() && noexcept {
+#if _CONTAINER_DEBUG_LEVEL > 0
+ _STL_VERIFY(!_Has_value, "expected stores a value, not an error");
+#endif // _CONTAINER_DEBUG_LEVEL > 0
+ return _STD move(_Unexpected);
+ }
+
+ // [expected.void.eq]
+ // clang-format off
+ template
+ requires is_void_v<_Uty>
+ _NODISCARD_FRIEND constexpr bool operator==(const expected& _Left, const expected<_Uty, _UErr>& _Right) noexcept(
+ noexcept(static_cast(_Left._Unexpected == _Right.error()))) { // strengthened
+ // clang-format on
+ if (_Left._Has_value != _Right.has_value()) {
+ return false;
+ } else {
+ return _Left._Has_value || static_cast(_Left._Unexpected == _Right.error());
+ }
+ }
+
+ template
+ _NODISCARD_FRIEND constexpr bool operator==(const expected& _Left, const unexpected<_UErr>& _Right) noexcept(
+ noexcept(static_cast(_Left._Unexpected == _Right.error()))) { // strengthened
+ if (_Left._Has_value) {
+ return false;
+ } else {
+ return static_cast(_Left._Unexpected == _Right.error());
+ }
+ }
+
+private:
+ [[noreturn]] void _Throw_bad_expected_access_lv() const {
+ _THROW(bad_expected_access{_Unexpected});
+ }
+ [[noreturn]] void _Throw_bad_expected_access_rv() {
+ _THROW(bad_expected_access{_STD move(_Unexpected)});
+ }
+
+ union {
+ _Err _Unexpected;
+ };
+ bool _Has_value;
+};
+
+_STD_END
+
+#pragma pop_macro("new")
+_STL_RESTORE_CLANG_WARNINGS
+#pragma warning(pop)
+#pragma pack(pop)
+#endif // __cpp_lib_expected
+#endif // _STL_COMPILER_PREPROCESSOR
+#endif // _EXPECTED_
diff --git a/stl/inc/header-units.json b/stl/inc/header-units.json
index 476bff26a5..f63097a68f 100644
--- a/stl/inc/header-units.json
+++ b/stl/inc/header-units.json
@@ -55,6 +55,7 @@
"deque",
"exception",
"execution",
+ "expected",
"filesystem",
"format",
"forward_list",
diff --git a/stl/inc/yvals_core.h b/stl/inc/yvals_core.h
index 01c3f352d2..088b22c121 100644
--- a/stl/inc/yvals_core.h
+++ b/stl/inc/yvals_core.h
@@ -281,6 +281,7 @@
// _HAS_CXX23 directly controls:
// P0288R9 move_only_function
+// P0323R12
// P0401R6 Providing Size Feedback In The Allocator Interface
// P0448R4
// P0627R6 unreachable()
@@ -307,6 +308,7 @@
// (changes to pair, tuple, and vector::reference only)
// P2442R1 Windowing Range Adaptors: views::chunk, views::slide
// P2443R1 views::chunk_by
+// P2549R0 unexpected::error()
// Parallel Algorithms Notes
// C++ allows an implementation to implement parallel algorithms as calls to the serial algorithms.
@@ -1438,9 +1440,14 @@
#define __cpp_lib_associative_heterogeneous_erasure 202110L
#define __cpp_lib_byteswap 202110L
-#define __cpp_lib_invoke_r 202106L
-#define __cpp_lib_is_scoped_enum 202011L
-#define __cpp_lib_move_only_function 202110L
+
+#ifdef __cpp_lib_concepts
+#define __cpp_lib_expected 202202L
+#endif // __cpp_lib_concepts
+
+#define __cpp_lib_invoke_r 202106L
+#define __cpp_lib_is_scoped_enum 202011L
+#define __cpp_lib_move_only_function 202110L
#ifdef __cpp_lib_concepts
#define __cpp_lib_out_ptr 202106L
diff --git a/tests/std/test.lst b/tests/std/test.lst
index 11293348bf..1240901c1b 100644
--- a/tests/std/test.lst
+++ b/tests/std/test.lst
@@ -257,6 +257,7 @@ tests\P0220R1_searchers
tests\P0220R1_string_view
tests\P0288R9_move_only_function
tests\P0295R0_gcd_lcm
+tests\P0323R12_expected
tests\P0325R4_to_array
tests\P0339R6_polymorphic_allocator
tests\P0355R7_calendars_and_time_zones_clocks
diff --git a/tests/std/tests/P0323R12_expected/env.lst b/tests/std/tests/P0323R12_expected/env.lst
new file mode 100644
index 0000000000..8ac7033b20
--- /dev/null
+++ b/tests/std/tests/P0323R12_expected/env.lst
@@ -0,0 +1,4 @@
+# Copyright (c) Microsoft Corporation.
+# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+RUNALL_INCLUDE ..\strict_concepts_latest_matrix.lst
diff --git a/tests/std/tests/P0323R12_expected/test.cpp b/tests/std/tests/P0323R12_expected/test.cpp
new file mode 100644
index 0000000000..9ccf3753a5
--- /dev/null
+++ b/tests/std/tests/P0323R12_expected/test.cpp
@@ -0,0 +1,2081 @@
+// Copyright (c) Microsoft Corporation.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+#define _CONTAINER_DEBUG_LEVEL 1
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+using namespace std;
+
+enum class IsDefaultConstructible : bool { Not, Yes };
+enum class IsTriviallyCopyConstructible : bool { Not, Yes };
+enum class IsTriviallyMoveConstructible : bool { Not, Yes };
+enum class IsTriviallyDestructible : bool { Not, Yes };
+
+enum class IsNothrowConstructible : bool { Not, Yes };
+enum class IsNothrowCopyConstructible : bool { Not, Yes };
+enum class IsNothrowMoveConstructible : bool { Not, Yes };
+enum class IsNothrowCopyAssignable : bool { Not, Yes };
+enum class IsNothrowMoveAssignable : bool { Not, Yes };
+enum class IsNothrowConvertible : bool { Not, Yes };
+enum class IsNothrowComparable : bool { Not, Yes };
+enum class IsNothrowSwappable : bool { Not, Yes };
+
+enum class IsExplicitConstructible : bool { Not, Yes };
+
+template
+[[nodiscard]] constexpr bool IsYes(const E e) noexcept {
+ return e == E::Yes;
+}
+
+struct convertible {
+ constexpr convertible() = default;
+ constexpr convertible(const int val) noexcept : _val(val) {}
+
+ [[nodiscard]] constexpr bool operator==(const int other) const noexcept {
+ return other == _val;
+ }
+
+ int _val = 0;
+};
+
+namespace test_unexpected {
+ template
+ constexpr void test() {
+ constexpr bool copy_construction_is_noexcept = IsYes(nothrowCopyConstructible);
+ constexpr bool move_construction_is_noexcept = IsYes(nothrowMoveConstructible);
+ constexpr bool compare_is_noexcept = IsYes(nothrowComparable);
+
+ struct test_error {
+ constexpr test_error(const int& val) noexcept(copy_construction_is_noexcept) : _val(val) {}
+ constexpr test_error(int&& val) noexcept(move_construction_is_noexcept) : _val(val) {}
+
+ constexpr test_error(initializer_list, const int& val) noexcept(copy_construction_is_noexcept)
+ : _val(val) {}
+ constexpr test_error(initializer_list, int&& val) noexcept(move_construction_is_noexcept)
+ : _val(val) {}
+
+ constexpr test_error(const convertible& other) noexcept(copy_construction_is_noexcept) : _val(other._val) {}
+ constexpr test_error(convertible&& other) noexcept(move_construction_is_noexcept) : _val(other._val) {}
+
+ [[nodiscard]] constexpr bool operator==(const test_error& right) const noexcept(compare_is_noexcept) {
+ return _val == right._val;
+ }
+ [[nodiscard]] constexpr bool operator==(const convertible& right) const noexcept(compare_is_noexcept) {
+ return _val == right._val;
+ }
+
+ int _val = 0;
+ };
+ using Unexpect = std::unexpected;
+
+ // [expected.un.ctor]
+ const int& input = 1;
+ Unexpect in_place_lvalue_constructed{in_place, input};
+ static_assert(noexcept(Unexpect{in_place, input}) == copy_construction_is_noexcept);
+ assert(in_place_lvalue_constructed == Unexpect{test_error{1}});
+
+ Unexpect in_place_rvalue_constructed{in_place, 42};
+ static_assert(noexcept(Unexpect{in_place, 42}) == move_construction_is_noexcept);
+ assert(in_place_rvalue_constructed == Unexpect{test_error{42}});
+
+ Unexpect in_place_ilist_lvalue_constructed{in_place, {2}, input};
+ static_assert(noexcept(Unexpect{in_place, {2}, input}) == copy_construction_is_noexcept);
+ assert(in_place_ilist_lvalue_constructed == Unexpect{test_error{1}});
+
+ Unexpect in_place_ilist_rvalue_constructed{in_place, {2}, 1337};
+ static_assert(noexcept(Unexpect{in_place, {2}, 1337}) == move_construction_is_noexcept);
+ assert(in_place_ilist_rvalue_constructed == Unexpect{test_error{1337}});
+
+ Unexpect base_error_constructed{test_error{3}};
+ static_assert(noexcept(Unexpect{test_error{3}}) == move_construction_is_noexcept);
+ assert(base_error_constructed.error()._val == 3);
+
+ Unexpect conversion_error_constructed{convertible{4}};
+ static_assert(noexcept(Unexpect{convertible{4}}) == move_construction_is_noexcept);
+ assert(conversion_error_constructed.error()._val == 4);
+
+ Unexpect brace_error_constructed{{5}};
+ static_assert(noexcept(Unexpect{{5}}) == move_construction_is_noexcept);
+ assert(brace_error_constructed.error()._val == 5);
+
+ // [expected.un.eq]
+ assert(in_place_lvalue_constructed == in_place_lvalue_constructed);
+ assert(in_place_lvalue_constructed != in_place_rvalue_constructed);
+ static_assert(noexcept(in_place_lvalue_constructed == in_place_lvalue_constructed) == compare_is_noexcept);
+ static_assert(noexcept(in_place_lvalue_constructed != in_place_lvalue_constructed) == compare_is_noexcept);
+
+ const auto converted = std::unexpected{convertible{3}};
+ assert(base_error_constructed == converted);
+ assert(conversion_error_constructed != converted);
+ static_assert(noexcept(base_error_constructed == converted) == compare_is_noexcept);
+ static_assert(noexcept(conversion_error_constructed != converted) == compare_is_noexcept);
+
+ // [expected.un.swap]
+ in_place_lvalue_constructed.swap(in_place_rvalue_constructed);
+ assert(in_place_lvalue_constructed == Unexpect{test_error{42}});
+ assert(in_place_rvalue_constructed == Unexpect{test_error{1}});
+ static_assert(noexcept(in_place_lvalue_constructed.swap(in_place_rvalue_constructed)));
+
+ swap(base_error_constructed, conversion_error_constructed);
+ assert(base_error_constructed == Unexpect{test_error{4}});
+ assert(conversion_error_constructed == Unexpect{test_error{3}});
+ static_assert(noexcept(swap(base_error_constructed, conversion_error_constructed)));
+
+ // [expected.un.obs]
+ auto&& lvalue_error = base_error_constructed.error();
+ assert(lvalue_error == test_error{4});
+ static_assert(is_same_v);
+
+ auto&& rvalue_error = move(conversion_error_constructed).error();
+ assert(rvalue_error == test_error{3});
+ static_assert(is_same_v);
+
+ auto&& const_lvalue_error = as_const(in_place_lvalue_constructed).error();
+ assert(const_lvalue_error == test_error{42});
+ static_assert(is_same_v);
+
+ auto&& const_rvalue_error = move(as_const(in_place_ilist_lvalue_constructed)).error();
+ assert(const_rvalue_error == test_error{1});
+ static_assert(is_same_v);
+
+ // deduction guide
+ std::unexpected deduced(test_error{42});
+ static_assert(same_as);
+ }
+
+ constexpr bool test_all() {
+ test();
+ test();
+ test();
+ test();
+ test();
+ test();
+ test();
+ test();
+
+ return true;
+ }
+} // namespace test_unexpected
+
+namespace test_unexpect {
+ auto copy = unexpect;
+ static_assert(is_same_v);
+ static_assert(is_trivial_v);
+ static_assert(is_empty_v);
+} // namespace test_unexpect
+
+namespace test_expected {
+ constexpr void test_aliases() {
+ struct value_tag {};
+ struct error_tag {};
+
+ {
+ using Expected = expected;
+ static_assert(same_as);
+ static_assert(same_as);
+ static_assert(same_as>);
+
+ static_assert(same_as, expected>);
+ }
+
+ {
+ using Expected = expected;
+ static_assert(same_as);
+ static_assert(same_as);
+ static_assert(same_as>);
+
+ static_assert(same_as, expected>);
+ }
+ }
+
+ template
+ constexpr void test_default_constructors() {
+ constexpr bool should_be_defaultable = IsYes(defaultConstructible);
+
+ struct payload_default_constructor {
+ constexpr payload_default_constructor() requires(should_be_defaultable) : _val(42) {}
+
+ [[nodiscard]] constexpr bool operator==(const int val) const noexcept {
+ return _val == val;
+ }
+
+ int _val = 0;
+ };
+
+ static_assert(is_default_constructible_v> == should_be_defaultable);
+ // we only care about payload type
+ static_assert(is_default_constructible_v>);
+ static_assert(is_default_constructible_v>);
+
+ if constexpr (should_be_defaultable) {
+ const expected defaulted;
+ assert(defaulted);
+ assert(defaulted.value() == 42);
+ }
+ }
+
+ template
+ constexpr void test_copy_constructors() {
+ constexpr bool should_be_trivial = IsYes(triviallyCopyConstructible);
+ constexpr bool should_be_noexcept = should_be_trivial || IsYes(nothrowCopyConstructible);
+
+ struct payload_copy_constructor {
+ payload_copy_constructor() = default;
+ payload_copy_constructor& operator=(const payload_copy_constructor&) = delete;
+ constexpr payload_copy_constructor(const payload_copy_constructor&) noexcept(should_be_noexcept) //
+ requires(!should_be_trivial)
+ : _val(42) {}
+ constexpr payload_copy_constructor(const payload_copy_constructor&) = default;
+
+ [[nodiscard]] constexpr bool operator==(const int val) const noexcept {
+ return _val == val;
+ }
+
+ int _val = 0;
+ };
+
+ { // Check payload type
+ using Expected = expected;
+#ifndef __clang__ // TRANSITION, LLVM-46269
+ static_assert(is_trivially_copy_constructible_v == should_be_trivial);
+#endif // !__clang__
+ static_assert(is_copy_constructible_v);
+
+ const Expected with_value{in_place};
+ const Expected from_value{with_value};
+ assert(from_value);
+ assert(from_value.value() == (should_be_trivial ? 0 : 42));
+ static_assert(noexcept(Expected{with_value}) == should_be_noexcept);
+
+ const Expected with_error{unexpect};
+ const Expected from_error{with_error};
+ assert(!from_error);
+ assert(from_error.error() == 0);
+ static_assert(noexcept(Expected{with_error}) == should_be_noexcept);
+ }
+
+ { // Check error type
+ using Expected = expected;
+#ifndef __clang__ // TRANSITION, LLVM-46269
+ static_assert(is_trivially_copy_constructible_v == should_be_trivial);
+#endif // !__clang__
+ static_assert(is_copy_constructible_v);
+
+ const Expected with_value{in_place};
+ const Expected from_value{with_value};
+ assert(from_value);
+ assert(from_value.value() == 0);
+ static_assert(noexcept(Expected{with_value}) == should_be_noexcept);
+
+ const Expected with_error{unexpect};
+ const Expected from_error{with_error};
+ assert(!from_error);
+ assert(from_error.error() == (should_be_trivial ? 0 : 42));
+ static_assert(noexcept(Expected{with_error}) == should_be_noexcept);
+ }
+
+ { // Check void payload
+ using Expected = expected;
+#ifndef __clang__ // TRANSITION, LLVM-46269
+ static_assert(is_trivially_copy_constructible_v == should_be_trivial);
+#endif // !__clang__
+ static_assert(is_copy_constructible_v);
+
+ const Expected with_value{in_place};
+ const Expected from_value{with_value};
+ assert(from_value);
+ static_assert(noexcept(Expected{with_value}) == should_be_noexcept);
+
+ const Expected with_error{unexpect};
+ const Expected from_error{with_error};
+ assert(!from_error);
+ assert(from_error.error() == (should_be_trivial ? 0 : 42));
+ static_assert(noexcept(Expected{with_error}) == should_be_noexcept);
+ }
+
+ { // ensure we are not copy constructible if either the payload or the error are not
+ struct not_copy_constructible {
+ not_copy_constructible(const not_copy_constructible&) = delete;
+ };
+
+ static_assert(!is_copy_constructible_v>);
+ static_assert(!is_copy_constructible_v>);
+ static_assert(!is_copy_constructible_v>);
+ }
+ }
+
+ template
+ constexpr void test_move_constructors() {
+ constexpr bool should_be_trivial = IsYes(triviallyMoveConstructible);
+ constexpr bool should_be_noexcept = should_be_trivial || IsYes(nothrowMoveConstructible);
+
+ struct payload_move_constructor {
+ payload_move_constructor() = default;
+ payload_move_constructor(const payload_move_constructor&) = default;
+ payload_move_constructor& operator=(payload_move_constructor&&) = delete;
+ constexpr payload_move_constructor(payload_move_constructor&&) noexcept(should_be_noexcept) //
+ requires(!should_be_trivial)
+ : _val(42) {}
+ constexpr payload_move_constructor(payload_move_constructor&&) = default;
+
+ [[nodiscard]] constexpr bool operator==(const int val) const noexcept {
+ return _val == val;
+ }
+
+ int _val = 0;
+ };
+
+ { // Check payload type
+ using Expected = expected;
+#ifndef __clang__ // TRANSITION, LLVM-46269
+ static_assert(is_trivially_move_constructible_v == should_be_trivial);
+#endif // !__clang__
+ static_assert(is_move_constructible_v);
+
+ Expected value_input{in_place};
+ const Expected from_value{move(value_input)};
+ assert(from_value);
+ assert(from_value.value() == (should_be_trivial ? 0 : 42));
+ static_assert(noexcept(Expected{move(value_input)}) == should_be_noexcept);
+
+ Expected error_input{unexpect};
+ const Expected from_error{move(error_input)};
+ assert(!from_error);
+ assert(from_error.error() == 0);
+ static_assert(noexcept(Expected{move(error_input)}) == should_be_noexcept);
+ }
+
+ { // Check error type
+ using Expected = expected;
+#ifndef __clang__ // TRANSITION, LLVM-46269
+ static_assert(is_trivially_move_constructible_v == should_be_trivial);
+#endif // !__clang__
+ static_assert(is_move_constructible_v);
+
+ Expected value_input{in_place};
+ const Expected from_value{move(value_input)};
+ assert(from_value);
+ assert(from_value.value() == 0);
+ static_assert(noexcept(Expected{move(value_input)}) == should_be_noexcept);
+
+ Expected error_input{unexpect};
+ const Expected from_error{move(error_input)};
+ assert(!from_error);
+ assert(from_error.error() == (should_be_trivial ? 0 : 42));
+ static_assert(noexcept(Expected{move(error_input)}) == should_be_noexcept);
+ }
+
+ { // Check void payload
+ using Expected = expected;
+#ifndef __clang__ // TRANSITION, LLVM-46269
+ static_assert(is_trivially_move_constructible_v == should_be_trivial);
+#endif // !__clang__
+ static_assert(is_move_constructible_v);
+
+ Expected value_input{in_place};
+ const Expected from_value{move(value_input)};
+ assert(from_value);
+ static_assert(noexcept(Expected{move(value_input)}) == should_be_noexcept);
+
+ Expected error_input{unexpect};
+ const Expected from_error{move(error_input)};
+ assert(!from_error);
+ assert(from_error.error() == (should_be_trivial ? 0 : 42));
+ static_assert(noexcept(Expected{move(error_input)}) == should_be_noexcept);
+ }
+
+ { // ensure we are not move constructible if either the payload or the error are not
+ struct not_move_constructible {
+ not_move_constructible(not_move_constructible&&) = delete;
+ };
+
+ static_assert(!is_move_constructible_v>);
+ static_assert(!is_move_constructible_v>);
+ static_assert(!is_move_constructible_v>);
+ }
+ }
+
+ template
+ struct payload_destructor {
+ constexpr payload_destructor(bool& destructor_called) : _destructor_called(destructor_called) {}
+ bool& _destructor_called;
+ };
+ template <> // TRANSITION, LLVM-46269
+ struct payload_destructor {
+ constexpr payload_destructor(bool& destructor_called) : _destructor_called(destructor_called) {}
+ payload_destructor(const payload_destructor&) = default;
+ constexpr ~payload_destructor() {
+ _destructor_called = true;
+ };
+
+ bool& _destructor_called;
+ };
+ template
+ constexpr void test_destructors() {
+ constexpr bool is_trivial = IsYes(triviallyDestructible);
+ bool destructor_called = false;
+ { // Check payload
+ using Expected = expected, int>;
+#ifndef __clang__ // TRANSITION, LLVM-46269
+ static_assert(is_trivially_destructible_v == is_trivial);
+#endif // !__clang__
+
+ Expected val{in_place, destructor_called};
+ }
+ assert(destructor_called == !is_trivial);
+ destructor_called = false;
+
+ { // Check error
+ using Expected = expected>;
+#ifndef __clang__ // TRANSITION, LLVM-46269
+ static_assert(is_trivially_destructible_v == is_trivial);
+#endif // !__clang__
+
+ Expected err{unexpect, destructor_called};
+ }
+ assert(destructor_called == !is_trivial);
+ destructor_called = false;
+
+ { // Check void error
+ using Expected = expected>;
+#ifndef __clang__ // TRANSITION, LLVM-46269
+ static_assert(is_trivially_destructible_v == is_trivial);
+#endif // !__clang__
+
+ Expected err{unexpect, destructor_called};
+ }
+ assert(destructor_called == !is_trivial);
+ }
+
+ constexpr void test_special_members() {
+ test_default_constructors();
+ test_default_constructors();
+
+ test_copy_constructors();
+ test_copy_constructors();
+ test_copy_constructors();
+ test_copy_constructors();
+
+ test_move_constructors();
+ test_move_constructors();
+ test_move_constructors();
+ test_move_constructors();
+
+ test_destructors();
+ test_destructors();
+ }
+
+ template
+ constexpr void test_constructors() noexcept {
+ constexpr bool should_be_noexcept = IsYes(nothrowConstructible);
+ constexpr bool should_be_explicit = IsYes(explicitConstructible);
+
+ struct payload_constructors {
+ payload_constructors() = default;
+ // Note clang does not accept local variables in explicit
+ constexpr explicit(IsYes(explicitConstructible))
+ payload_constructors(const convertible&) noexcept(should_be_noexcept)
+ : _val(3) {}
+ constexpr explicit(IsYes(explicitConstructible))
+ payload_constructors(convertible&&) noexcept(should_be_noexcept)
+ : _val(42) {}
+ constexpr explicit(IsYes(explicitConstructible))
+ payload_constructors(initializer_list&, convertible) noexcept(should_be_noexcept)
+ : _val(1337) {}
+
+ [[nodiscard]] constexpr bool operator==(const int val) const noexcept {
+ return _val == val;
+ }
+
+ int _val = 0;
+ };
+
+ { // constructing from convertible payload
+ using Input = convertible;
+ using Expected = expected;
+ static_assert(is_convertible_v != should_be_explicit);
+ static_assert(is_convertible_v != should_be_explicit);
+
+ const Input const_input_value{};
+ const Expected copy_constructed_value{const_input_value};
+ assert(copy_constructed_value);
+ assert(copy_constructed_value.value() == 3);
+ static_assert(noexcept(Expected{const_input_value}) == should_be_noexcept);
+
+ const Expected move_constructed_value{Input{}};
+ assert(move_constructed_value);
+ assert(move_constructed_value.value() == 42);
+ static_assert(noexcept(Expected{Input{}}) == should_be_noexcept);
+
+ const Expected brace_constructed_value{{}};
+ assert(brace_constructed_value);
+ assert(brace_constructed_value.value() == 0);
+ static_assert(noexcept(Expected{{}}));
+ }
+
+ { // converting from different expected
+ using Input = expected;
+ using Expected = expected;
+ static_assert(is_convertible_v != should_be_explicit);
+ static_assert(is_convertible_v != should_be_explicit);
+
+ const Input const_input_value{};
+ const Expected copy_constructed_value{const_input_value};
+ assert(copy_constructed_value);
+ assert(copy_constructed_value.value() == 3);
+ static_assert(noexcept(Expected{const_input_value}) == should_be_noexcept);
+
+ const Expected move_constructed_value{Input{in_place}};
+ assert(move_constructed_value);
+ assert(move_constructed_value.value() == 42);
+ static_assert(noexcept(Expected{Input{in_place}}) == should_be_noexcept);
+
+ const Input const_input_error{unexpect};
+ const Expected copy_constructed_error{const_input_error};
+ assert(!copy_constructed_error);
+ assert(copy_constructed_error.error() == 3);
+ static_assert(noexcept(Expected{const_input_error}) == should_be_noexcept);
+
+ const Expected move_constructed_error{Input{unexpect}};
+ assert(!move_constructed_error);
+ assert(move_constructed_error.error() == 42);
+ static_assert(noexcept(Expected{Input{unexpect}}) == should_be_noexcept);
+ }
+
+ { // converting from unexpected
+ using Input = std::unexpected;
+ using Expected = expected;
+
+ const Input const_input{in_place};
+ const Expected copy_constructed{const_input};
+ assert(!copy_constructed);
+ assert(copy_constructed.error() == 3);
+ static_assert(noexcept(Expected{const_input}) == should_be_noexcept);
+
+ const Expected move_constructed{Input{in_place}};
+ assert(!move_constructed);
+ assert(move_constructed.error() == 42);
+ static_assert(noexcept(Expected{Input{in_place}}) == should_be_noexcept);
+ }
+
+ { // in place payload
+ using Expected = expected;
+ const Expected default_constructed{in_place};
+ assert(default_constructed);
+ assert(default_constructed.value() == 0);
+ static_assert(noexcept(Expected{in_place}));
+
+ const Expected value_constructed{in_place, convertible{}};
+ assert(value_constructed);
+ assert(value_constructed.value() == 42);
+ static_assert(noexcept(Expected{in_place, convertible{}}) == should_be_noexcept);
+
+ const Expected ilist_value_constructed{in_place, {1}, convertible{}};
+ assert(ilist_value_constructed);
+ assert(ilist_value_constructed.value() == 1337);
+ static_assert(noexcept(Expected{in_place, {1}, convertible{}}) == should_be_noexcept);
+ }
+
+ { // in place error
+ using Expected = expected;
+ const Expected default_constructed{unexpect};
+ assert(!default_constructed);
+ assert(default_constructed.error() == 0);
+ static_assert(noexcept(Expected{unexpect}));
+
+ const Expected value_constructed{unexpect, convertible{}};
+ assert(!value_constructed);
+ assert(value_constructed.error() == 42);
+ static_assert(noexcept(Expected{unexpect, convertible{}}) == should_be_noexcept);
+
+ const Expected ilist_value_constructed{unexpect, {1}, convertible{}};
+ assert(!ilist_value_constructed);
+ assert(ilist_value_constructed.error() == 1337);
+ static_assert(noexcept(Expected{unexpect, {1}, convertible{}}) == should_be_noexcept);
+ }
+
+ { // expected: converting from different expected
+ using Input = expected;
+ using Expected = expected;
+ static_assert(is_convertible_v != should_be_explicit);
+ static_assert(is_convertible_v != should_be_explicit);
+
+ const Input const_input_value{};
+ const Expected copy_constructed_value{const_input_value};
+ assert(copy_constructed_value);
+ copy_constructed_value.value();
+ static_assert(noexcept(Expected{const_input_value}) == should_be_noexcept);
+
+ const Expected move_constructed_value{Input{in_place}};
+ assert(move_constructed_value);
+ move_constructed_value.value();
+ static_assert(noexcept(Expected{Input{in_place}}) == should_be_noexcept);
+
+ const Input const_input_error{unexpect};
+ const Expected copy_constructed_error{const_input_error};
+ assert(!copy_constructed_error);
+ assert(copy_constructed_error.error() == 3);
+ static_assert(noexcept(Expected{const_input_error}) == should_be_noexcept);
+
+ const Expected move_constructed_error{Input{unexpect}};
+ assert(!move_constructed_error);
+ assert(move_constructed_error.error() == 42);
+ static_assert(noexcept(Expected{Input{unexpect}}) == should_be_noexcept);
+ }
+
+ { // expected: converting from unexpected
+ using Input = std::unexpected;
+ using Expected = expected;
+
+ const Input const_input{in_place};
+ const Expected copy_constructed{const_input};
+ assert(!copy_constructed);
+ assert(copy_constructed.error() == 3);
+ static_assert(noexcept(Expected{const_input}) == should_be_noexcept);
+
+ const Expected move_constructed{Input{in_place}};
+ assert(!move_constructed);
+ assert(move_constructed.error() == 42);
+ static_assert(noexcept(Expected{Input{in_place}}) == should_be_noexcept);
+ }
+
+ { // expected: in place payload
+ using Expected = expected;
+ const Expected default_constructed{in_place};
+ assert(default_constructed);
+ default_constructed.value();
+ static_assert(noexcept(Expected{in_place}));
+ }
+
+ { // expected: in place error
+ using Expected = expected;
+ const Expected default_constructed{unexpect};
+ assert(!default_constructed);
+ assert(default_constructed.error() == 0);
+ static_assert(noexcept(Expected{unexpect}));
+
+ const Expected value_constructed{unexpect, convertible{}};
+ assert(!value_constructed);
+ assert(value_constructed.error() == 42);
+ static_assert(noexcept(Expected{unexpect, convertible{}}) == should_be_noexcept);
+
+ const Expected ilist_value_constructed{unexpect, {1}, convertible{}};
+ assert(!ilist_value_constructed);
+ assert(ilist_value_constructed.error() == 1337);
+ static_assert(noexcept(Expected{unexpect, {1}, convertible{}}) == should_be_noexcept);
+ }
+ }
+
+ constexpr void test_constructors() noexcept {
+ test_constructors();
+ test_constructors();
+ test_constructors();
+ test_constructors();
+ }
+
+ template
+ constexpr void test_assignment() noexcept {
+ constexpr bool nothrow_copy_constructible = IsYes(nothrowCopyConstructible);
+ constexpr bool nothrow_move_constructible = IsYes(nothrowMoveConstructible);
+ constexpr bool nothrow_copy_assignable = IsYes(nothrowCopyAssignable);
+ constexpr bool nothrow_move_assignable = IsYes(nothrowMoveAssignable);
+
+ struct payload_assign {
+ payload_assign() = default;
+ constexpr payload_assign(const int val) noexcept : _val(val) {}
+ constexpr payload_assign(const payload_assign& other) noexcept(nothrow_copy_constructible)
+ : _val(other._val) {}
+ constexpr payload_assign(payload_assign&& other) noexcept(nothrow_move_constructible) : _val(other._val) {}
+ constexpr payload_assign& operator=(const payload_assign& other) noexcept(nothrow_copy_assignable) {
+ _val = other._val;
+ return *this;
+ }
+ constexpr payload_assign& operator=(payload_assign&& other) noexcept(nothrow_move_assignable) {
+ _val = other._val;
+ return *this;
+ }
+
+ constexpr payload_assign(const convertible& other) noexcept(nothrow_copy_constructible)
+ : _val(other._val) {}
+ constexpr payload_assign(convertible&& other) noexcept(nothrow_move_constructible) : _val(other._val) {}
+ constexpr payload_assign& operator=(const convertible& other) noexcept(nothrow_copy_assignable) {
+ _val = other._val;
+ return *this;
+ }
+ constexpr payload_assign& operator=(convertible&& other) noexcept(nothrow_move_assignable) {
+ _val = other._val;
+ return *this;
+ }
+
+ [[nodiscard]] constexpr bool operator==(const int other) const noexcept {
+ return other == _val;
+ }
+ int _val = 0;
+ };
+
+ { // assign same expected as const ref check payload
+ constexpr bool should_be_noexcept = nothrow_copy_constructible && nothrow_copy_assignable;
+ using Expected = expected;
+ const Expected input_value{in_place, 42};
+ const Expected input_error{unexpect, 1337};
+
+ Expected assign_value_to_value{in_place, 1};
+ assign_value_to_value = input_value;
+ assert(assign_value_to_value);
+ assert(assign_value_to_value.value() == 42);
+ static_assert(noexcept(assign_value_to_value = input_value) == should_be_noexcept);
+
+ Expected assign_error_to_value{in_place, 1};
+ assign_error_to_value = input_error;
+ assert(!assign_error_to_value);
+ assert(assign_error_to_value.error() == 1337);
+ static_assert(noexcept(assign_error_to_value = input_error) == should_be_noexcept);
+
+ Expected assign_value_to_error{unexpect, 1};
+ assign_value_to_error = input_value;
+ assert(assign_value_to_error);
+ assert(assign_value_to_error.value() == 42);
+ static_assert(noexcept(assign_value_to_error = input_value) == should_be_noexcept);
+
+ Expected assign_error_to_error{unexpect, 1};
+ assign_error_to_error = input_error;
+ assert(!assign_error_to_error);
+ assert(assign_error_to_error.error() == 1337);
+ static_assert(noexcept(assign_error_to_error = input_error) == should_be_noexcept);
+ }
+
+ { // assign same expected as const ref check error
+ constexpr bool should_be_noexcept = nothrow_copy_constructible && nothrow_copy_assignable;
+ using Expected = expected;
+ const Expected input_value{in_place, 42};
+ const Expected input_error{unexpect, 1337};
+
+ Expected assign_value_to_value{in_place, 1};
+ assign_value_to_value = input_value;
+ assert(assign_value_to_value);
+ assert(assign_value_to_value.value() == 42);
+ static_assert(noexcept(assign_value_to_value = input_value) == should_be_noexcept);
+
+ Expected assign_error_to_value{in_place, 1};
+ assign_error_to_value = input_error;
+ assert(!assign_error_to_value);
+ assert(assign_error_to_value.error() == 1337);
+ static_assert(noexcept(assign_error_to_value = input_error) == should_be_noexcept);
+
+ Expected assign_value_to_error{unexpect, 1};
+ assign_value_to_error = input_value;
+ assert(assign_value_to_error);
+ assert(assign_value_to_error.value() == 42);
+ static_assert(noexcept(assign_value_to_error = input_value) == should_be_noexcept);
+
+ Expected assign_error_to_error{unexpect, 1};
+ assign_error_to_error = input_error;
+ assert(!assign_error_to_error);
+ assert(assign_error_to_error.error() == 1337);
+ static_assert(noexcept(assign_error_to_error = input_error) == should_be_noexcept);
+ }
+
+ { // assign same expected as const ref check error
+ constexpr bool should_be_noexcept = nothrow_copy_constructible && nothrow_copy_assignable;
+ using Expected = expected;
+ const Expected input_value{in_place};
+ const Expected input_error{unexpect, 1337};
+
+ Expected assign_value_to_value{in_place};
+ assign_value_to_value = input_value;
+ assert(assign_value_to_value);
+ static_assert(noexcept(assign_value_to_value = input_value) == should_be_noexcept);
+
+ Expected assign_error_to_value{in_place};
+ assign_error_to_value = input_error;
+ assert(!assign_error_to_value);
+ assert(assign_error_to_value.error() == 1337);
+ static_assert(noexcept(assign_error_to_value = input_error) == should_be_noexcept);
+
+ Expected assign_value_to_error{unexpect, 1};
+ assign_value_to_error = input_value;
+ assert(assign_value_to_error);
+ static_assert(noexcept(assign_value_to_error = input_value) == should_be_noexcept);
+
+ Expected assign_error_to_error{unexpect, 1};
+ assign_error_to_error = input_error;
+ assert(!assign_error_to_error);
+ assert(assign_error_to_error.error() == 1337);
+ static_assert(noexcept(assign_error_to_error = input_error) == should_be_noexcept);
+ }
+
+ { // assign same expected as rvalue check payload
+ constexpr bool should_be_noexcept = nothrow_move_constructible && nothrow_move_assignable;
+ using Expected = expected;
+
+ Expected assign_value_to_value{in_place, 1};
+ assign_value_to_value = Expected{in_place, 42};
+ assert(assign_value_to_value);
+ assert(assign_value_to_value.value() == 42);
+ static_assert(noexcept(assign_value_to_value = Expected{in_place, 42}) == should_be_noexcept);
+
+ Expected assign_error_to_value{in_place, 1};
+ assign_error_to_value = Expected{unexpect, 1337};
+ assert(!assign_error_to_value);
+ assert(assign_error_to_value.error() == 1337);
+ static_assert(noexcept(assign_error_to_value = Expected{unexpect, 1337}) == should_be_noexcept);
+
+ Expected assign_value_to_error{unexpect, 1};
+ assign_value_to_error = Expected{in_place, 42};
+ assert(assign_value_to_error);
+ assert(assign_value_to_error.value() == 42);
+ static_assert(noexcept(assign_value_to_error = Expected{in_place, 42}) == should_be_noexcept);
+
+ Expected assign_error_to_error{unexpect, 1};
+ assign_error_to_error = Expected{unexpect, 1337};
+ assert(!assign_error_to_error);
+ assert(assign_error_to_error.error() == 1337);
+ static_assert(noexcept(assign_error_to_error = Expected{unexpect, 1337}) == should_be_noexcept);
+ }
+
+ { // assign same expected as rvalue check error
+ constexpr bool should_be_noexcept = nothrow_move_constructible && nothrow_move_assignable;
+ using Expected = expected;
+
+ Expected assign_value_to_value{in_place, 1};
+ assign_value_to_value = Expected{in_place, 42};
+ assert(assign_value_to_value);
+ assert(assign_value_to_value.value() == 42);
+ static_assert(noexcept(assign_value_to_value = Expected{in_place, 42}) == should_be_noexcept);
+
+ Expected assign_error_to_value{in_place, 1};
+ assign_error_to_value = Expected{unexpect, 1337};
+ assert(!assign_error_to_value);
+ assert(assign_error_to_value.error() == 1337);
+ static_assert(noexcept(assign_error_to_value = Expected{unexpect, 1337}) == should_be_noexcept);
+
+ Expected assign_value_to_error{unexpect, 1};
+ assign_value_to_error = Expected{in_place, 42};
+ assert(assign_value_to_error);
+ assert(assign_value_to_error.value() == 42);
+ static_assert(noexcept(assign_value_to_error = Expected{in_place, 42}) == should_be_noexcept);
+
+ Expected assign_error_to_error{unexpect, 1};
+ assign_error_to_error = Expected{unexpect, 1337};
+ assert(!assign_error_to_error);
+ assert(assign_error_to_error.error() == 1337);
+ static_assert(noexcept(assign_error_to_error = Expected{unexpect, 1337}) == should_be_noexcept);
+ }
+
+ { // assign same expected as rvalue check error
+ constexpr bool should_be_noexcept = nothrow_move_constructible && nothrow_move_assignable;
+ using Expected = expected;
+
+ Expected assign_value_to_value{in_place};
+ assign_value_to_value = Expected{in_place};
+ assert(assign_value_to_value);
+ static_assert(noexcept(assign_value_to_value = Expected{in_place}) == should_be_noexcept);
+
+ Expected assign_error_to_value{in_place};
+ assign_error_to_value = Expected{unexpect, 1337};
+ assert(!assign_error_to_value);
+ assert(assign_error_to_value.error() == 1337);
+ static_assert(noexcept(assign_error_to_value = Expected{unexpect, 1337}) == should_be_noexcept);
+
+ Expected assign_value_to_error{unexpect, 1};
+ assign_value_to_error = Expected{in_place};
+ assert(assign_value_to_error);
+ static_assert(noexcept(assign_value_to_error = Expected{in_place}) == should_be_noexcept);
+
+ Expected assign_error_to_error{unexpect, 1};
+ assign_error_to_error = Expected{unexpect, 1337};
+ assert(!assign_error_to_error);
+ assert(assign_error_to_error.error() == 1337);
+ static_assert(noexcept(assign_error_to_error = Expected{unexpect, 1337}) == should_be_noexcept);
+ }
+
+ { // assign base type const ref
+ constexpr bool should_be_noexcept = nothrow_copy_constructible && nothrow_copy_assignable;
+ using Expected = expected;
+ const payload_assign input_value{42};
+
+ Expected assign_value_to_value{in_place, 1};
+ assign_value_to_value = input_value;
+ assert(assign_value_to_value);
+ assert(assign_value_to_value.value() == 42);
+ static_assert(noexcept(assign_value_to_value = input_value) == should_be_noexcept);
+
+ Expected assign_value_to_error{unexpect, 1};
+ assign_value_to_error = input_value;
+ assert(assign_value_to_error);
+ assert(assign_value_to_error.value() == 42);
+ static_assert(noexcept(assign_value_to_error = input_value) == should_be_noexcept);
+ }
+
+ { // assign base type rvalue
+ constexpr bool should_be_noexcept = nothrow_move_constructible && nothrow_move_assignable;
+ using Expected = expected;
+
+ Expected assign_value_to_value{in_place, 1};
+ assign_value_to_value = payload_assign{42};
+ assert(assign_value_to_value);
+ assert(assign_value_to_value.value() == 42);
+ static_assert(noexcept(assign_value_to_value = payload_assign{42}) == should_be_noexcept);
+
+ Expected assign_value_to_error{unexpect, 1};
+ assign_value_to_error = payload_assign{42};
+ assert(assign_value_to_error);
+ assert(assign_value_to_error.value() == 42);
+ static_assert(noexcept(assign_value_to_error = payload_assign{42}) == should_be_noexcept);
+ }
+
+ { // assign base type braces
+ constexpr bool should_be_noexcept = nothrow_move_constructible && nothrow_move_assignable;
+ using Expected = expected;
+
+ Expected assign_value_to_value{in_place, 1};
+ assign_value_to_value = {42};
+ assert(assign_value_to_value);
+ assert(assign_value_to_value.value() == 42);
+ static_assert(noexcept(assign_value_to_value = {42}) == should_be_noexcept);
+
+ Expected assign_value_to_error{unexpect, 1};
+ assign_value_to_error = {42};
+ assert(assign_value_to_error);
+ assert(assign_value_to_error.value() == 42);
+ static_assert(noexcept(assign_value_to_error = {42}) == should_be_noexcept);
+ }
+
+ { // assign convertible type const ref
+ constexpr bool should_be_noexcept = nothrow_copy_constructible && nothrow_copy_assignable;
+ using Expected = expected;
+ const convertible input_value{42};
+
+ Expected assign_value_to_value{in_place, 1};
+ assign_value_to_value = input_value;
+ assert(assign_value_to_value);
+ assert(assign_value_to_value.value() == 42);
+ static_assert(noexcept(assign_value_to_value = input_value) == should_be_noexcept);
+
+ Expected assign_value_to_error{unexpect, 1};
+ assign_value_to_error = input_value;
+ assert(assign_value_to_error);
+ assert(assign_value_to_error.value() == 42);
+ static_assert(noexcept(assign_value_to_error = input_value) == should_be_noexcept);
+ }
+
+ { // assign convertible type rvalue
+ constexpr bool should_be_noexcept = nothrow_move_constructible && nothrow_move_assignable;
+ using Expected = expected;
+
+ Expected assign_value_to_value{in_place, 1};
+ assign_value_to_value = convertible{42};
+ assert(assign_value_to_value);
+ assert(assign_value_to_value.value() == 42);
+ static_assert(noexcept(assign_value_to_value = convertible{42}) == should_be_noexcept);
+
+ Expected assign_value_to_error{unexpect, 1};
+ assign_value_to_error = convertible{42};
+ assert(assign_value_to_error);
+ assert(assign_value_to_error.value() == 42);
+ static_assert(noexcept(assign_value_to_error = convertible{42}) == should_be_noexcept);
+ }
+
+ { // assign error type const ref
+ constexpr bool should_be_noexcept = nothrow_copy_constructible && nothrow_copy_assignable;
+ using Expected = expected;
+ using Unexpected = std::unexpected;
+ const Unexpected input_error{42};
+
+ Expected assign_error_to_value{in_place, 1};
+ assign_error_to_value = input_error;
+ assert(!assign_error_to_value);
+ assert(assign_error_to_value.error() == 42);
+ static_assert(noexcept(assign_error_to_value = input_error) == should_be_noexcept);
+
+ Expected assign_error_to_error{unexpect, 1};
+ assign_error_to_error = input_error;
+ assert(!assign_error_to_error);
+ assert(assign_error_to_error.error() == 42);
+ static_assert(noexcept(assign_error_to_error = input_error) == should_be_noexcept);
+ }
+
+ { // assign expected error type const ref
+ constexpr bool should_be_noexcept = nothrow_copy_constructible && nothrow_copy_assignable;
+ using Expected = expected;
+ using Unexpected = std::unexpected;
+ const Unexpected input_error{42};
+
+ Expected assign_error_to_value{in_place};
+ assign_error_to_value = input_error;
+ assert(!assign_error_to_value);
+ assert(assign_error_to_value.error() == 42);
+ static_assert(noexcept(assign_error_to_value = input_error) == should_be_noexcept);
+
+ Expected assign_error_to_error{unexpect, 1};
+ assign_error_to_error = input_error;
+ assert(!assign_error_to_error);
+ assert(assign_error_to_error.error() == 42);
+ static_assert(noexcept(assign_error_to_error = input_error) == should_be_noexcept);
+ }
+
+ { // assign error type rvalue
+ constexpr bool should_be_noexcept = nothrow_move_constructible && nothrow_move_assignable;
+ using Expected = expected;
+ using Unexpected = std::unexpected;
+
+ Expected assign_error_to_value{in_place, 1};
+ assign_error_to_value = Unexpected{42};
+ assert(!assign_error_to_value);
+ assert(assign_error_to_value.error() == 42);
+ static_assert(noexcept(assign_error_to_value = Unexpected{42}) == should_be_noexcept);
+
+ Expected assign_error_to_error{unexpect, 1};
+ assign_error_to_error = Unexpected{42};
+ assert(!assign_error_to_error);
+ assert(assign_error_to_error.error() == 42);
+ static_assert(noexcept(assign_error_to_error = Unexpected{42}) == should_be_noexcept);
+ }
+
+ { // assign expected error type rvalue
+ constexpr bool should_be_noexcept = nothrow_move_constructible && nothrow_move_assignable;
+ using Expected = expected