[libcxx-commits] [libcxx] [libc++] Ensure that `std::expected` has no tail padding (PR #69673)
Jan Kokemüller via libcxx-commits
libcxx-commits at lists.llvm.org
Sat Dec 2 08:47:06 PST 2023
https://github.com/jiixyj updated https://github.com/llvm/llvm-project/pull/69673
>From ab4525407818e8fe31342845bee02ffff4e4b5c3 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jan=20Kokem=C3=BCller?= <jan.kokemueller at gmail.com>
Date: Sun, 15 Oct 2023 22:09:51 +0200
Subject: [PATCH 01/37] ensure that expected has no tail padding
---
libcxx/include/__expected/expected.h | 20 ++++++++++++++++++++
1 file changed, 20 insertions(+)
diff --git a/libcxx/include/__expected/expected.h b/libcxx/include/__expected/expected.h
index bf16c8f720d26..8475075e1557d 100644
--- a/libcxx/include/__expected/expected.h
+++ b/libcxx/include/__expected/expected.h
@@ -18,6 +18,7 @@
#include <__memory/addressof.h>
#include <__memory/construct_at.h>
#include <__type_traits/conjunction.h>
+#include <__type_traits/datasizeof.h>
#include <__type_traits/disjunction.h>
#include <__type_traits/integral_constant.h>
#include <__type_traits/is_assignable.h>
@@ -942,8 +943,17 @@ class expected {
_LIBCPP_NO_UNIQUE_ADDRESS _ErrorType __unex_;
};
+ _LIBCPP_HIDE_FROM_ABI static constexpr auto __calculate_padding() {
+ struct __calc_expected {
+ _LIBCPP_NO_UNIQUE_ADDRESS __union_t<_Tp, _Err> __union_;
+ bool __has_val_;
+ };
+ return sizeof(__calc_expected) - __libcpp_datasizeof<__calc_expected>::value;
+ }
+
_LIBCPP_NO_UNIQUE_ADDRESS __union_t<_Tp, _Err> __union_;
bool __has_val_;
+ char __padding_[__calculate_padding()]{};
};
template <class _Tp, class _Err>
@@ -1539,8 +1549,18 @@ class expected<_Tp, _Err> {
_LIBCPP_NO_UNIQUE_ADDRESS _ErrorType __unex_;
};
+
+ _LIBCPP_HIDE_FROM_ABI static constexpr auto __calculate_padding() {
+ struct __calc_expected {
+ _LIBCPP_NO_UNIQUE_ADDRESS __union_t<_Err> __union_;
+ bool __has_val_;
+ };
+ return sizeof(__calc_expected) - __libcpp_datasizeof<__calc_expected>::value;
+ }
+
_LIBCPP_NO_UNIQUE_ADDRESS __union_t<_Err> __union_;
bool __has_val_;
+ char __padding_[__calculate_padding()]{};
};
_LIBCPP_END_NAMESPACE_STD
>From 9e10550e1ff4d18705fe6bf09103a2751b68f9ac Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jan=20Kokem=C3=BCller?= <jan.kokemueller at gmail.com>
Date: Fri, 20 Oct 2023 19:40:18 +0200
Subject: [PATCH 02/37] handle GCC's warning in __libcpp_datasizeof
---
libcxx/include/__type_traits/datasizeof.h | 1 +
1 file changed, 1 insertion(+)
diff --git a/libcxx/include/__type_traits/datasizeof.h b/libcxx/include/__type_traits/datasizeof.h
index 5688e3293a69e..96404ad15a733 100644
--- a/libcxx/include/__type_traits/datasizeof.h
+++ b/libcxx/include/__type_traits/datasizeof.h
@@ -51,6 +51,7 @@ struct __libcpp_datasizeof {
// the use as an extension.
_LIBCPP_DIAGNOSTIC_PUSH
_LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Winvalid-offsetof")
+ _LIBCPP_GCC_DIAGNOSTIC_IGNORED("-Winvalid-offsetof")
static const size_t value = offsetof(_FirstPaddingByte<>, __first_padding_byte_);
_LIBCPP_DIAGNOSTIC_POP
};
>From 4f80d7e77cd27c30b52523d2d7f2eb6942df9d81 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jan=20Kokem=C3=BCller?= <jan.kokemueller at gmail.com>
Date: Fri, 20 Oct 2023 19:53:22 +0200
Subject: [PATCH 03/37] implement different approach to padding calculation
This tries to fix two issues:
- There should be no artificial padding if the parameter type(s) don't
need it, for example if they have no tail padding
- Prevent the padding array being zero length
---
libcxx/include/__expected/expected.h | 53 +++++++++++++++++-----------
1 file changed, 32 insertions(+), 21 deletions(-)
diff --git a/libcxx/include/__expected/expected.h b/libcxx/include/__expected/expected.h
index 8475075e1557d..3b1ae3c40df62 100644
--- a/libcxx/include/__expected/expected.h
+++ b/libcxx/include/__expected/expected.h
@@ -89,6 +89,34 @@ _LIBCPP_HIDE_FROM_ABI void __throw_bad_expected_access(_Arg&& __arg) {
# endif
}
+template <size_t __Padding>
+struct __expected_padding {
+ using type = char[__Padding];
+};
+
+template <>
+struct __expected_padding<0> {
+ using type = struct {};
+};
+
+template <class _Union>
+_LIBCPP_HIDE_FROM_ABI constexpr size_t __expected_calculate_padding() {
+ struct __calc_expected {
+ _LIBCPP_NO_UNIQUE_ADDRESS _Union __union_;
+ bool __has_val_;
+ };
+
+ size_t __datasize = __libcpp_datasizeof<__calc_expected>::value;
+ return sizeof(_Union) < __datasize ? 0 : sizeof(_Union) - __datasize;
+}
+
+// An object of this type must be the last member of the `expected` class to
+// ensure `expected`'s datasize is large enough to fit the parameter type(s).
+// It should be value-initialized so it is safe to copy when `expected`'s
+// copy operators are invoked.
+template <typename _Union>
+using __expected_padding_t = __expected_padding<__expected_calculate_padding<_Union>()>::type;
+
template <class _Tp, class _Err>
class expected {
static_assert(
@@ -943,17 +971,9 @@ class expected {
_LIBCPP_NO_UNIQUE_ADDRESS _ErrorType __unex_;
};
- _LIBCPP_HIDE_FROM_ABI static constexpr auto __calculate_padding() {
- struct __calc_expected {
- _LIBCPP_NO_UNIQUE_ADDRESS __union_t<_Tp, _Err> __union_;
- bool __has_val_;
- };
- return sizeof(__calc_expected) - __libcpp_datasizeof<__calc_expected>::value;
- }
-
_LIBCPP_NO_UNIQUE_ADDRESS __union_t<_Tp, _Err> __union_;
- bool __has_val_;
- char __padding_[__calculate_padding()]{};
+ _LIBCPP_NO_UNIQUE_ADDRESS bool __has_val_;
+ _LIBCPP_NO_UNIQUE_ADDRESS __expected_padding_t<__union_t<_Tp, _Err>> __padding_{};
};
template <class _Tp, class _Err>
@@ -1549,18 +1569,9 @@ class expected<_Tp, _Err> {
_LIBCPP_NO_UNIQUE_ADDRESS _ErrorType __unex_;
};
-
- _LIBCPP_HIDE_FROM_ABI static constexpr auto __calculate_padding() {
- struct __calc_expected {
- _LIBCPP_NO_UNIQUE_ADDRESS __union_t<_Err> __union_;
- bool __has_val_;
- };
- return sizeof(__calc_expected) - __libcpp_datasizeof<__calc_expected>::value;
- }
-
_LIBCPP_NO_UNIQUE_ADDRESS __union_t<_Err> __union_;
- bool __has_val_;
- char __padding_[__calculate_padding()]{};
+ _LIBCPP_NO_UNIQUE_ADDRESS bool __has_val_;
+ _LIBCPP_NO_UNIQUE_ADDRESS __expected_padding_t<__union_t<_Err>> __padding_{};
};
_LIBCPP_END_NAMESPACE_STD
>From fba7a6a117241e4d9676eaeb7634dccb1fd15c50 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jan=20Kokem=C3=BCller?= <jan.kokemueller at gmail.com>
Date: Fri, 20 Oct 2023 19:56:59 +0200
Subject: [PATCH 04/37] add tests
---
.../no_unique_address.compile.pass.cpp | 17 +++++++++++++++++
.../no_unique_address.compile.pass.cpp | 15 +++++++++++++++
2 files changed, 32 insertions(+)
diff --git a/libcxx/test/libcxx/utilities/expected/expected.expected/no_unique_address.compile.pass.cpp b/libcxx/test/libcxx/utilities/expected/expected.expected/no_unique_address.compile.pass.cpp
index c8c217054ae6c..06f597d54871e 100644
--- a/libcxx/test/libcxx/utilities/expected/expected.expected/no_unique_address.compile.pass.cpp
+++ b/libcxx/test/libcxx/utilities/expected/expected.expected/no_unique_address.compile.pass.cpp
@@ -26,6 +26,13 @@ struct B : public A {
virtual ~B() = default;
};
+struct BoolWithPadding {
+ explicit operator bool() { return b; }
+
+private:
+ alignas(1024) bool b = false;
+};
+
static_assert(sizeof(std::expected<Empty, Empty>) == sizeof(bool));
static_assert(sizeof(std::expected<Empty, A>) == 2 * sizeof(int) + alignof(std::expected<Empty, A>));
static_assert(sizeof(std::expected<Empty, B>) == sizeof(B) + alignof(std::expected<Empty, B>));
@@ -33,3 +40,13 @@ static_assert(sizeof(std::expected<A, Empty>) == 2 * sizeof(int) + alignof(std::
static_assert(sizeof(std::expected<A, A>) == 2 * sizeof(int) + alignof(std::expected<A, A>));
static_assert(sizeof(std::expected<B, Empty>) == sizeof(B) + alignof(std::expected<B, Empty>));
static_assert(sizeof(std::expected<B, B>) == sizeof(B) + alignof(std::expected<B, B>));
+
+// Check that `expected`'s datasize is large enough for the parameter type(s).
+static_assert(sizeof(std::expected<BoolWithPadding, Empty>) ==
+ std::__libcpp_datasizeof<std::expected<BoolWithPadding, Empty>>::value);
+static_assert(sizeof(std::expected<Empty, BoolWithPadding>) ==
+ std::__libcpp_datasizeof<std::expected<Empty, BoolWithPadding>>::value);
+
+// In this case, there should be tail padding in the `expected` because `A`
+// itself does _not_ have tail padding.
+static_assert(sizeof(std::expected<A, A>) > std::__libcpp_datasizeof<std::expected<A, A>>::value);
diff --git a/libcxx/test/libcxx/utilities/expected/expected.void/no_unique_address.compile.pass.cpp b/libcxx/test/libcxx/utilities/expected/expected.void/no_unique_address.compile.pass.cpp
index dc59a6228386b..29cf8dff0d2b2 100644
--- a/libcxx/test/libcxx/utilities/expected/expected.void/no_unique_address.compile.pass.cpp
+++ b/libcxx/test/libcxx/utilities/expected/expected.void/no_unique_address.compile.pass.cpp
@@ -26,6 +26,21 @@ struct B : public A {
virtual ~B() = default;
};
+struct BoolWithPadding {
+ explicit operator bool() { return b; }
+
+private:
+ alignas(1024) bool b = false;
+};
+
static_assert(sizeof(std::expected<void, Empty>) == sizeof(bool));
static_assert(sizeof(std::expected<void, A>) == 2 * sizeof(int) + alignof(std::expected<void, A>));
static_assert(sizeof(std::expected<void, B>) == sizeof(B) + alignof(std::expected<void, B>));
+
+// Check that `expected`'s datasize is large enough for the parameter type(s).
+static_assert(sizeof(std::expected<void, BoolWithPadding>) ==
+ std::__libcpp_datasizeof<std::expected<void, BoolWithPadding>>::value);
+
+// In this case, there should be tail padding in the `expected` because `A`
+// itself does _not_ have tail padding.
+static_assert(sizeof(std::expected<void, A>) > std::__libcpp_datasizeof<std::expected<void, A>>::value);
>From cb13aa5ecd790586f856ce059465e0ea652570f8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jan=20Kokem=C3=BCller?= <jan.kokemueller at gmail.com>
Date: Fri, 20 Oct 2023 22:02:20 +0200
Subject: [PATCH 05/37] implement repr/compact_pair approach
---
libcxx/include/__expected/expected.h | 443 +++++++++---------
.../no_unique_address.compile.pass.cpp | 1 +
.../no_unique_address.compile.pass.cpp | 1 +
3 files changed, 212 insertions(+), 233 deletions(-)
diff --git a/libcxx/include/__expected/expected.h b/libcxx/include/__expected/expected.h
index 3b1ae3c40df62..ab7cae1c1007f 100644
--- a/libcxx/include/__expected/expected.h
+++ b/libcxx/include/__expected/expected.h
@@ -89,33 +89,11 @@ _LIBCPP_HIDE_FROM_ABI void __throw_bad_expected_access(_Arg&& __arg) {
# endif
}
-template <size_t __Padding>
-struct __expected_padding {
- using type = char[__Padding];
-};
-
-template <>
-struct __expected_padding<0> {
- using type = struct {};
-};
-
template <class _Union>
-_LIBCPP_HIDE_FROM_ABI constexpr size_t __expected_calculate_padding() {
- struct __calc_expected {
- _LIBCPP_NO_UNIQUE_ADDRESS _Union __union_;
- bool __has_val_;
- };
-
- size_t __datasize = __libcpp_datasizeof<__calc_expected>::value;
- return sizeof(_Union) < __datasize ? 0 : sizeof(_Union) - __datasize;
-}
-
-// An object of this type must be the last member of the `expected` class to
-// ensure `expected`'s datasize is large enough to fit the parameter type(s).
-// It should be value-initialized so it is safe to copy when `expected`'s
-// copy operators are invoked.
-template <typename _Union>
-using __expected_padding_t = __expected_padding<__expected_calculate_padding<_Union>()>::type;
+struct __expected_repr {
+ [[no_unique_address]] _Union __union_;
+ [[no_unique_address]] bool __has_val_;
+};
template <class _Tp, class _Err>
class expected {
@@ -148,7 +126,7 @@ class expected {
_LIBCPP_HIDE_FROM_ABI constexpr expected()
noexcept(is_nothrow_default_constructible_v<_Tp>) // strengthened
requires is_default_constructible_v<_Tp>
- : __union_(std::in_place), __has_val_(true) {}
+ : __repr_{.__union_{std::in_place}, .__has_val_ = true} {}
_LIBCPP_HIDE_FROM_ABI constexpr expected(const expected&) = delete;
@@ -163,7 +141,7 @@ class expected {
noexcept(is_nothrow_copy_constructible_v<_Tp> && is_nothrow_copy_constructible_v<_Err>) // strengthened
requires(is_copy_constructible_v<_Tp> && is_copy_constructible_v<_Err> &&
!(is_trivially_copy_constructible_v<_Tp> && is_trivially_copy_constructible_v<_Err>))
- : __union_(__other.__has_val_, __other.__union_), __has_val_(__other.__has_val_) { }
+ : __repr_{.__union_{__other.__repr_.__has_val_, __other.__repr_.__union_}, .__has_val_ = __other.__repr_.__has_val_} { }
_LIBCPP_HIDE_FROM_ABI constexpr expected(expected&&)
requires(is_move_constructible_v<_Tp> && is_move_constructible_v<_Err>
@@ -174,7 +152,8 @@ class expected {
noexcept(is_nothrow_move_constructible_v<_Tp> && is_nothrow_move_constructible_v<_Err>)
requires(is_move_constructible_v<_Tp> && is_move_constructible_v<_Err> &&
!(is_trivially_move_constructible_v<_Tp> && is_trivially_move_constructible_v<_Err>))
- : __union_(__other.__has_val_, std::move(__other.__union_)), __has_val_(__other.__has_val_) { }
+ : __repr_{.__union_{__other.__repr_.__has_val_, std::move(__other.__repr_.__union_)},
+ .__has_val_ = __other.__repr_.__has_val_} { }
private:
template <class _Up, class _OtherErr, class _UfQual, class _OtherErrQual>
@@ -199,12 +178,12 @@ class expected {
template <class _Func, class... _Args>
_LIBCPP_HIDE_FROM_ABI constexpr explicit expected(
std::__expected_construct_in_place_from_invoke_tag __tag, _Func&& __f, _Args&&... __args)
- : __union_(__tag, std::forward<_Func>(__f), std::forward<_Args>(__args)...), __has_val_(true) {}
+ : __repr_{.__union_{__tag, std::forward<_Func>(__f), std::forward<_Args>(__args)...}, .__has_val_ = true} {}
template <class _Func, class... _Args>
_LIBCPP_HIDE_FROM_ABI constexpr explicit expected(
std::__expected_construct_unexpected_from_invoke_tag __tag, _Func&& __f, _Args&&... __args)
- : __union_(__tag, std::forward<_Func>(__f), std::forward<_Args>(__args)...), __has_val_(false) {}
+ : __repr_{.__union_{__tag, std::forward<_Func>(__f), std::forward<_Args>(__args)...}, .__has_val_ = false} {}
public:
template <class _Up, class _OtherErr>
@@ -214,14 +193,16 @@ class expected {
expected(const expected<_Up, _OtherErr>& __other)
noexcept(is_nothrow_constructible_v<_Tp, const _Up&> &&
is_nothrow_constructible_v<_Err, const _OtherErr&>) // strengthened
- : __union_(__other.__has_val_, __other.__union_), __has_val_(__other.__has_val_) {}
+ : __repr_{.__union_{__other.__repr_.__has_val_, __other.__repr_.__union_},
+ .__has_val_ = __other.__repr_.__has_val_} {}
template <class _Up, class _OtherErr>
requires __can_convert<_Up, _OtherErr, _Up, _OtherErr>::value
_LIBCPP_HIDE_FROM_ABI constexpr explicit(!is_convertible_v<_Up, _Tp> || !is_convertible_v<_OtherErr, _Err>)
expected(expected<_Up, _OtherErr>&& __other)
noexcept(is_nothrow_constructible_v<_Tp, _Up> && is_nothrow_constructible_v<_Err, _OtherErr>) // strengthened
- : __union_(__other.__has_val_, std::move(__other.__union_)), __has_val_(__other.__has_val_) {}
+ : __repr_{.__union_{__other.__repr_.__has_val_, std::move(__other.__repr_.__union_)},
+ .__has_val_ = __other.__repr_.__has_val_} {}
template <class _Up = _Tp>
requires(!is_same_v<remove_cvref_t<_Up>, in_place_t> && !is_same_v<expected, remove_cvref_t<_Up>> &&
@@ -229,47 +210,47 @@ class expected {
(!is_same_v<remove_cv_t<_Tp>, bool> || !__is_std_expected<remove_cvref_t<_Up>>::value))
_LIBCPP_HIDE_FROM_ABI constexpr explicit(!is_convertible_v<_Up, _Tp>)
expected(_Up&& __u) noexcept(is_nothrow_constructible_v<_Tp, _Up>) // strengthened
- : __union_(std::in_place, std::forward<_Up>(__u)), __has_val_(true) {}
+ : __repr_{.__union_{std::in_place, std::forward<_Up>(__u)}, .__has_val_ = true} {}
template <class _OtherErr>
requires is_constructible_v<_Err, const _OtherErr&>
_LIBCPP_HIDE_FROM_ABI constexpr explicit(!is_convertible_v<const _OtherErr&, _Err>)
expected(const unexpected<_OtherErr>& __unex)
noexcept(is_nothrow_constructible_v<_Err, const _OtherErr&>) // strengthened
- : __union_(std::unexpect, __unex.error()), __has_val_(false) {}
+ : __repr_{.__union_{std::unexpect, __unex.error()}, .__has_val_ = false} {}
template <class _OtherErr>
requires is_constructible_v<_Err, _OtherErr>
_LIBCPP_HIDE_FROM_ABI constexpr explicit(!is_convertible_v<_OtherErr, _Err>)
expected(unexpected<_OtherErr>&& __unex)
noexcept(is_nothrow_constructible_v<_Err, _OtherErr>) // strengthened
- : __union_(std::unexpect, std::move(__unex.error())), __has_val_(false) {}
+ : __repr_{.__union_{std::unexpect, std::move(__unex.error())}, .__has_val_ = false} {}
template <class... _Args>
requires is_constructible_v<_Tp, _Args...>
_LIBCPP_HIDE_FROM_ABI constexpr explicit expected(in_place_t, _Args&&... __args)
noexcept(is_nothrow_constructible_v<_Tp, _Args...>) // strengthened
- : __union_(std::in_place, std::forward<_Args>(__args)...), __has_val_(true) {}
+ : __repr_{.__union_{std::in_place, std::forward<_Args>(__args)...}, .__has_val_ = true} {}
template <class _Up, class... _Args>
requires is_constructible_v< _Tp, initializer_list<_Up>&, _Args... >
_LIBCPP_HIDE_FROM_ABI constexpr explicit
expected(in_place_t, initializer_list<_Up> __il, _Args&&... __args)
noexcept(is_nothrow_constructible_v<_Tp, initializer_list<_Up>&, _Args...>) // strengthened
- : __union_(std::in_place, __il, std::forward<_Args>(__args)...), __has_val_(true) {}
+ : __repr_{.__union_{std::in_place, __il, std::forward<_Args>(__args)...}, .__has_val_ = true} {}
template <class... _Args>
requires is_constructible_v<_Err, _Args...>
_LIBCPP_HIDE_FROM_ABI constexpr explicit expected(unexpect_t, _Args&&... __args)
noexcept(is_nothrow_constructible_v<_Err, _Args...>) // strengthened
- : __union_(std::unexpect, std::forward<_Args>(__args)...), __has_val_(false) {}
+ : __repr_{.__union_{std::unexpect, std::forward<_Args>(__args)...}, .__has_val_ = false} {}
template <class _Up, class... _Args>
requires is_constructible_v< _Err, initializer_list<_Up>&, _Args... >
_LIBCPP_HIDE_FROM_ABI constexpr explicit
expected(unexpect_t, initializer_list<_Up> __il, _Args&&... __args)
noexcept(is_nothrow_constructible_v<_Err, initializer_list<_Up>&, _Args...>) // strengthened
- : __union_(std::unexpect, __il, std::forward<_Args>(__args)...), __has_val_(false) {}
+ : __repr_{.__union_{std::unexpect, __il, std::forward<_Args>(__args)...}, .__has_val_ = false} {}
// [expected.object.dtor], destructor
@@ -280,10 +261,10 @@ class expected {
_LIBCPP_HIDE_FROM_ABI constexpr ~expected()
requires(!is_trivially_destructible_v<_Tp> || !is_trivially_destructible_v<_Err>)
{
- if (__has_val_) {
- std::destroy_at(std::addressof(__union_.__val_));
+ if (__repr_.__has_val_) {
+ std::destroy_at(std::addressof(__repr_.__union_.__val_));
} else {
- std::destroy_at(std::addressof(__union_.__unex_));
+ std::destroy_at(std::addressof(__repr_.__union_.__unex_));
}
}
@@ -327,17 +308,17 @@ class expected {
(is_nothrow_move_constructible_v<_Tp> ||
is_nothrow_move_constructible_v<_Err>))
{
- if (__has_val_ && __rhs.__has_val_) {
- __union_.__val_ = __rhs.__union_.__val_;
- } else if (__has_val_) {
- __reinit_expected(__union_.__unex_, __union_.__val_, __rhs.__union_.__unex_);
- } else if (__rhs.__has_val_) {
- __reinit_expected(__union_.__val_, __union_.__unex_, __rhs.__union_.__val_);
+ if (__repr_.__has_val_ && __rhs.__repr_.__has_val_) {
+ __repr_.__union_.__val_ = __rhs.__repr_.__union_.__val_;
+ } else if (__repr_.__has_val_) {
+ __reinit_expected(__repr_.__union_.__unex_, __repr_.__union_.__val_, __rhs.__repr_.__union_.__unex_);
+ } else if (__rhs.__repr_.__has_val_) {
+ __reinit_expected(__repr_.__union_.__val_, __repr_.__union_.__unex_, __rhs.__repr_.__union_.__val_);
} else {
- __union_.__unex_ = __rhs.__union_.__unex_;
+ __repr_.__union_.__unex_ = __rhs.__repr_.__union_.__unex_;
}
// note: only reached if no exception+rollback was done inside __reinit_expected
- __has_val_ = __rhs.__has_val_;
+ __repr_.__has_val_ = __rhs.__repr_.__has_val_;
return *this;
}
@@ -353,17 +334,17 @@ class expected {
(is_nothrow_move_constructible_v<_Tp> ||
is_nothrow_move_constructible_v<_Err>))
{
- if (__has_val_ && __rhs.__has_val_) {
- __union_.__val_ = std::move(__rhs.__union_.__val_);
- } else if (__has_val_) {
- __reinit_expected(__union_.__unex_, __union_.__val_, std::move(__rhs.__union_.__unex_));
- } else if (__rhs.__has_val_) {
- __reinit_expected(__union_.__val_, __union_.__unex_, std::move(__rhs.__union_.__val_));
+ if (__repr_.__has_val_ && __rhs.__repr_.__has_val_) {
+ __repr_.__union_.__val_ = std::move(__rhs.__repr_.__union_.__val_);
+ } else if (__repr_.__has_val_) {
+ __reinit_expected(__repr_.__union_.__unex_, __repr_.__union_.__val_, std::move(__rhs.__repr_.__union_.__unex_));
+ } else if (__rhs.__repr_.__has_val_) {
+ __reinit_expected(__repr_.__union_.__val_, __repr_.__union_.__unex_, std::move(__rhs.__repr_.__union_.__val_));
} else {
- __union_.__unex_ = std::move(__rhs.__union_.__unex_);
+ __repr_.__union_.__unex_ = std::move(__rhs.__repr_.__union_.__unex_);
}
// note: only reached if no exception+rollback was done inside __reinit_expected
- __has_val_ = __rhs.__has_val_;
+ __repr_.__has_val_ = __rhs.__repr_.__has_val_;
return *this;
}
@@ -377,11 +358,11 @@ class expected {
is_nothrow_move_constructible_v<_Tp> ||
is_nothrow_move_constructible_v<_Err>))
{
- if (__has_val_) {
- __union_.__val_ = std::forward<_Up>(__v);
+ if (__repr_.__has_val_) {
+ __repr_.__union_.__val_ = std::forward<_Up>(__v);
} else {
- __reinit_expected(__union_.__val_, __union_.__unex_, std::forward<_Up>(__v));
- __has_val_ = true;
+ __reinit_expected(__repr_.__union_.__val_, __repr_.__union_.__unex_, std::forward<_Up>(__v));
+ __repr_.__has_val_ = true;
}
return *this;
}
@@ -400,11 +381,11 @@ class expected {
template <class _OtherErr>
requires(__can_assign_from_unexpected<const _OtherErr&>)
_LIBCPP_HIDE_FROM_ABI constexpr expected& operator=(const unexpected<_OtherErr>& __un) {
- if (__has_val_) {
- __reinit_expected(__union_.__unex_, __union_.__val_, __un.error());
- __has_val_ = false;
+ if (__repr_.__has_val_) {
+ __reinit_expected(__repr_.__union_.__unex_, __repr_.__union_.__val_, __un.error());
+ __repr_.__has_val_ = false;
} else {
- __union_.__unex_ = __un.error();
+ __repr_.__union_.__unex_ = __un.error();
}
return *this;
}
@@ -412,11 +393,11 @@ class expected {
template <class _OtherErr>
requires(__can_assign_from_unexpected<_OtherErr>)
_LIBCPP_HIDE_FROM_ABI constexpr expected& operator=(unexpected<_OtherErr>&& __un) {
- if (__has_val_) {
- __reinit_expected(__union_.__unex_, __union_.__val_, std::move(__un.error()));
- __has_val_ = false;
+ if (__repr_.__has_val_) {
+ __reinit_expected(__repr_.__union_.__unex_, __repr_.__union_.__val_, std::move(__un.error()));
+ __repr_.__has_val_ = false;
} else {
- __union_.__unex_ = std::move(__un.error());
+ __repr_.__union_.__unex_ = std::move(__un.error());
}
return *this;
}
@@ -424,27 +405,27 @@ class expected {
template <class... _Args>
requires is_nothrow_constructible_v<_Tp, _Args...>
_LIBCPP_HIDE_FROM_ABI constexpr _Tp& emplace(_Args&&... __args) noexcept {
- if (__has_val_) {
- std::destroy_at(std::addressof(__union_.__val_));
+ if (__repr_.__has_val_) {
+ std::destroy_at(std::addressof(__repr_.__union_.__val_));
} else {
- std::destroy_at(std::addressof(__union_.__unex_));
+ std::destroy_at(std::addressof(__repr_.__union_.__unex_));
}
- std::construct_at(std::addressof(__union_.__val_), std::forward<_Args>(__args)...);
- __has_val_ = true;
- return __union_.__val_;
+ std::construct_at(std::addressof(__repr_.__union_.__val_), std::forward<_Args>(__args)...);
+ __repr_.__has_val_ = true;
+ return __repr_.__union_.__val_;
}
template <class _Up, class... _Args>
requires is_nothrow_constructible_v< _Tp, initializer_list<_Up>&, _Args... >
_LIBCPP_HIDE_FROM_ABI constexpr _Tp& emplace(initializer_list<_Up> __il, _Args&&... __args) noexcept {
- if (__has_val_) {
- std::destroy_at(std::addressof(__union_.__val_));
+ if (__repr_.__has_val_) {
+ std::destroy_at(std::addressof(__repr_.__union_.__val_));
} else {
- std::destroy_at(std::addressof(__union_.__unex_));
+ std::destroy_at(std::addressof(__repr_.__union_.__unex_));
}
- std::construct_at(std::addressof(__union_.__val_), __il, std::forward<_Args>(__args)...);
- __has_val_ = true;
- return __union_.__val_;
+ std::construct_at(std::addressof(__repr_.__union_.__val_), __il, std::forward<_Args>(__args)...);
+ __repr_.__has_val_ = true;
+ return __repr_.__union_.__val_;
}
@@ -464,46 +445,46 @@ class expected {
{
auto __swap_val_unex_impl = [&](expected& __with_val, expected& __with_err) {
if constexpr (is_nothrow_move_constructible_v<_Err>) {
- _Err __tmp(std::move(__with_err.__union_.__unex_));
- std::destroy_at(std::addressof(__with_err.__union_.__unex_));
+ _Err __tmp(std::move(__with_err.__repr_.__union_.__unex_));
+ std::destroy_at(std::addressof(__with_err.__repr_.__union_.__unex_));
auto __trans = std::__make_exception_guard([&] {
- std::construct_at(std::addressof(__with_err.__union_.__unex_), std::move(__tmp));
+ std::construct_at(std::addressof(__with_err.__repr_.__union_.__unex_), std::move(__tmp));
});
- std::construct_at(std::addressof(__with_err.__union_.__val_), std::move(__with_val.__union_.__val_));
+ std::construct_at(std::addressof(__with_err.__repr_.__union_.__val_), std::move(__with_val.__repr_.__union_.__val_));
__trans.__complete();
- std::destroy_at(std::addressof(__with_val.__union_.__val_));
- std::construct_at(std::addressof(__with_val.__union_.__unex_), std::move(__tmp));
+ std::destroy_at(std::addressof(__with_val.__repr_.__union_.__val_));
+ std::construct_at(std::addressof(__with_val.__repr_.__union_.__unex_), std::move(__tmp));
} else {
static_assert(is_nothrow_move_constructible_v<_Tp>,
"To provide strong exception guarantee, Tp has to satisfy `is_nothrow_move_constructible_v` so "
"that it can be reverted to the previous state in case an exception is thrown during swap.");
- _Tp __tmp(std::move(__with_val.__union_.__val_));
- std::destroy_at(std::addressof(__with_val.__union_.__val_));
+ _Tp __tmp(std::move(__with_val.__repr_.__union_.__val_));
+ std::destroy_at(std::addressof(__with_val.__repr_.__union_.__val_));
auto __trans = std::__make_exception_guard([&] {
- std::construct_at(std::addressof(__with_val.__union_.__val_), std::move(__tmp));
+ std::construct_at(std::addressof(__with_val.__repr_.__union_.__val_), std::move(__tmp));
});
- std::construct_at(std::addressof(__with_val.__union_.__unex_), std::move(__with_err.__union_.__unex_));
+ std::construct_at(std::addressof(__with_val.__repr_.__union_.__unex_), std::move(__with_err.__repr_.__union_.__unex_));
__trans.__complete();
- std::destroy_at(std::addressof(__with_err.__union_.__unex_));
- std::construct_at(std::addressof(__with_err.__union_.__val_), std::move(__tmp));
+ std::destroy_at(std::addressof(__with_err.__repr_.__union_.__unex_));
+ std::construct_at(std::addressof(__with_err.__repr_.__union_.__val_), std::move(__tmp));
}
- __with_val.__has_val_ = false;
- __with_err.__has_val_ = true;
+ __with_val.__repr_.__has_val_ = false;
+ __with_err.__repr_.__has_val_ = true;
};
- if (__has_val_) {
- if (__rhs.__has_val_) {
+ if (__repr_.__has_val_) {
+ if (__rhs.__repr_.__has_val_) {
using std::swap;
- swap(__union_.__val_, __rhs.__union_.__val_);
+ swap(__repr_.__union_.__val_, __rhs.__repr_.__union_.__val_);
} else {
__swap_val_unex_impl(*this, __rhs);
}
} else {
- if (__rhs.__has_val_) {
+ if (__rhs.__repr_.__has_val_) {
__swap_val_unex_impl(__rhs, *this);
} else {
using std::swap;
- swap(__union_.__unex_, __rhs.__union_.__unex_);
+ swap(__repr_.__union_.__unex_, __rhs.__repr_.__union_.__unex_);
}
}
}
@@ -517,105 +498,105 @@ class expected {
// [expected.object.obs], observers
_LIBCPP_HIDE_FROM_ABI constexpr const _Tp* operator->() const noexcept {
- _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__has_val_, "expected::operator-> requires the expected to contain a value");
- return std::addressof(__union_.__val_);
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__repr_.__has_val_, "expected::operator-> requires the expected to contain a value");
+ return std::addressof(__repr_.__union_.__val_);
}
_LIBCPP_HIDE_FROM_ABI constexpr _Tp* operator->() noexcept {
- _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__has_val_, "expected::operator-> requires the expected to contain a value");
- return std::addressof(__union_.__val_);
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__repr_.__has_val_, "expected::operator-> requires the expected to contain a value");
+ return std::addressof(__repr_.__union_.__val_);
}
_LIBCPP_HIDE_FROM_ABI constexpr const _Tp& operator*() const& noexcept {
- _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__has_val_, "expected::operator* requires the expected to contain a value");
- return __union_.__val_;
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__repr_.__has_val_, "expected::operator* requires the expected to contain a value");
+ return __repr_.__union_.__val_;
}
_LIBCPP_HIDE_FROM_ABI constexpr _Tp& operator*() & noexcept {
- _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__has_val_, "expected::operator* requires the expected to contain a value");
- return __union_.__val_;
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__repr_.__has_val_, "expected::operator* requires the expected to contain a value");
+ return __repr_.__union_.__val_;
}
_LIBCPP_HIDE_FROM_ABI constexpr const _Tp&& operator*() const&& noexcept {
- _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__has_val_, "expected::operator* requires the expected to contain a value");
- return std::move(__union_.__val_);
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__repr_.__has_val_, "expected::operator* requires the expected to contain a value");
+ return std::move(__repr_.__union_.__val_);
}
_LIBCPP_HIDE_FROM_ABI constexpr _Tp&& operator*() && noexcept {
- _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__has_val_, "expected::operator* requires the expected to contain a value");
- return std::move(__union_.__val_);
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__repr_.__has_val_, "expected::operator* requires the expected to contain a value");
+ return std::move(__repr_.__union_.__val_);
}
- _LIBCPP_HIDE_FROM_ABI constexpr explicit operator bool() const noexcept { return __has_val_; }
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit operator bool() const noexcept { return __repr_.__has_val_; }
- _LIBCPP_HIDE_FROM_ABI constexpr bool has_value() const noexcept { return __has_val_; }
+ _LIBCPP_HIDE_FROM_ABI constexpr bool has_value() const noexcept { return __repr_.__has_val_; }
_LIBCPP_HIDE_FROM_ABI constexpr const _Tp& value() const& {
static_assert(is_copy_constructible_v<_Err>, "error_type has to be copy constructible");
- if (!__has_val_) {
+ if (!__repr_.__has_val_) {
std::__throw_bad_expected_access<_Err>(std::as_const(error()));
}
- return __union_.__val_;
+ return __repr_.__union_.__val_;
}
_LIBCPP_HIDE_FROM_ABI constexpr _Tp& value() & {
static_assert(is_copy_constructible_v<_Err>, "error_type has to be copy constructible");
- if (!__has_val_) {
+ if (!__repr_.__has_val_) {
std::__throw_bad_expected_access<_Err>(std::as_const(error()));
}
- return __union_.__val_;
+ return __repr_.__union_.__val_;
}
_LIBCPP_HIDE_FROM_ABI constexpr const _Tp&& value() const&& {
static_assert(is_copy_constructible_v<_Err> && is_constructible_v<_Err, decltype(std::move(error()))>,
"error_type has to be both copy constructible and constructible from decltype(std::move(error()))");
- if (!__has_val_) {
+ if (!__repr_.__has_val_) {
std::__throw_bad_expected_access<_Err>(std::move(error()));
}
- return std::move(__union_.__val_);
+ return std::move(__repr_.__union_.__val_);
}
_LIBCPP_HIDE_FROM_ABI constexpr _Tp&& value() && {
static_assert(is_copy_constructible_v<_Err> && is_constructible_v<_Err, decltype(std::move(error()))>,
"error_type has to be both copy constructible and constructible from decltype(std::move(error()))");
- if (!__has_val_) {
+ if (!__repr_.__has_val_) {
std::__throw_bad_expected_access<_Err>(std::move(error()));
}
- return std::move(__union_.__val_);
+ return std::move(__repr_.__union_.__val_);
}
_LIBCPP_HIDE_FROM_ABI constexpr const _Err& error() const& noexcept {
- _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!__has_val_, "expected::error requires the expected to contain an error");
- return __union_.__unex_;
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!__repr_.__has_val_, "expected::error requires the expected to contain an error");
+ return __repr_.__union_.__unex_;
}
_LIBCPP_HIDE_FROM_ABI constexpr _Err& error() & noexcept {
- _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!__has_val_, "expected::error requires the expected to contain an error");
- return __union_.__unex_;
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!__repr_.__has_val_, "expected::error requires the expected to contain an error");
+ return __repr_.__union_.__unex_;
}
_LIBCPP_HIDE_FROM_ABI constexpr const _Err&& error() const&& noexcept {
- _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!__has_val_, "expected::error requires the expected to contain an error");
- return std::move(__union_.__unex_);
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!__repr_.__has_val_, "expected::error requires the expected to contain an error");
+ return std::move(__repr_.__union_.__unex_);
}
_LIBCPP_HIDE_FROM_ABI constexpr _Err&& error() && noexcept {
- _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!__has_val_, "expected::error requires the expected to contain an error");
- return std::move(__union_.__unex_);
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!__repr_.__has_val_, "expected::error requires the expected to contain an error");
+ return std::move(__repr_.__union_.__unex_);
}
template <class _Up>
_LIBCPP_HIDE_FROM_ABI constexpr _Tp value_or(_Up&& __v) const& {
static_assert(is_copy_constructible_v<_Tp>, "value_type has to be copy constructible");
static_assert(is_convertible_v<_Up, _Tp>, "argument has to be convertible to value_type");
- return __has_val_ ? __union_.__val_ : static_cast<_Tp>(std::forward<_Up>(__v));
+ return __repr_.__has_val_ ? __repr_.__union_.__val_ : static_cast<_Tp>(std::forward<_Up>(__v));
}
template <class _Up>
_LIBCPP_HIDE_FROM_ABI constexpr _Tp value_or(_Up&& __v) && {
static_assert(is_move_constructible_v<_Tp>, "value_type has to be move constructible");
static_assert(is_convertible_v<_Up, _Tp>, "argument has to be convertible to value_type");
- return __has_val_ ? std::move(__union_.__val_) : static_cast<_Tp>(std::forward<_Up>(__v));
+ return __repr_.__has_val_ ? std::move(__repr_.__union_.__val_) : static_cast<_Tp>(std::forward<_Up>(__v));
}
template <class _Up = _Err>
@@ -645,7 +626,7 @@ class expected {
static_assert(is_same_v<typename _Up::error_type, _Err>,
"The result of f(**this) must have the same error_type as this expected");
if (has_value()) {
- return std::invoke(std::forward<_Func>(__f), __union_.__val_);
+ return std::invoke(std::forward<_Func>(__f), __repr_.__union_.__val_);
}
return _Up(unexpect, error());
}
@@ -658,7 +639,7 @@ class expected {
static_assert(is_same_v<typename _Up::error_type, _Err>,
"The result of f(**this) must have the same error_type as this expected");
if (has_value()) {
- return std::invoke(std::forward<_Func>(__f), __union_.__val_);
+ return std::invoke(std::forward<_Func>(__f), __repr_.__union_.__val_);
}
return _Up(unexpect, error());
}
@@ -672,7 +653,7 @@ class expected {
static_assert(is_same_v<typename _Up::error_type, _Err>,
"The result of f(std::move(**this)) must have the same error_type as this expected");
if (has_value()) {
- return std::invoke(std::forward<_Func>(__f), std::move(__union_.__val_));
+ return std::invoke(std::forward<_Func>(__f), std::move(__repr_.__union_.__val_));
}
return _Up(unexpect, std::move(error()));
}
@@ -686,7 +667,7 @@ class expected {
static_assert(is_same_v<typename _Up::error_type, _Err>,
"The result of f(std::move(**this)) must have the same error_type as this expected");
if (has_value()) {
- return std::invoke(std::forward<_Func>(__f), std::move(__union_.__val_));
+ return std::invoke(std::forward<_Func>(__f), std::move(__repr_.__union_.__val_));
}
return _Up(unexpect, std::move(error()));
}
@@ -699,7 +680,7 @@ class expected {
static_assert(is_same_v<typename _Gp::value_type, _Tp>,
"The result of f(error()) must have the same value_type as this expected");
if (has_value()) {
- return _Gp(in_place, __union_.__val_);
+ return _Gp(in_place, __repr_.__union_.__val_);
}
return std::invoke(std::forward<_Func>(__f), error());
}
@@ -712,7 +693,7 @@ class expected {
static_assert(is_same_v<typename _Gp::value_type, _Tp>,
"The result of f(error()) must have the same value_type as this expected");
if (has_value()) {
- return _Gp(in_place, __union_.__val_);
+ return _Gp(in_place, __repr_.__union_.__val_);
}
return std::invoke(std::forward<_Func>(__f), error());
}
@@ -726,7 +707,7 @@ class expected {
static_assert(is_same_v<typename _Gp::value_type, _Tp>,
"The result of f(std::move(error())) must have the same value_type as this expected");
if (has_value()) {
- return _Gp(in_place, std::move(__union_.__val_));
+ return _Gp(in_place, std::move(__repr_.__union_.__val_));
}
return std::invoke(std::forward<_Func>(__f), std::move(error()));
}
@@ -740,7 +721,7 @@ class expected {
static_assert(is_same_v<typename _Gp::value_type, _Tp>,
"The result of f(std::move(error())) must have the same value_type as this expected");
if (has_value()) {
- return _Gp(in_place, std::move(__union_.__val_));
+ return _Gp(in_place, std::move(__repr_.__union_.__val_));
}
return std::invoke(std::forward<_Func>(__f), std::move(error()));
}
@@ -753,9 +734,9 @@ class expected {
return expected<_Up, _Err>(unexpect, error());
}
if constexpr (!is_void_v<_Up>) {
- return expected<_Up, _Err>(__expected_construct_in_place_from_invoke_tag{}, std::forward<_Func>(__f), __union_.__val_);
+ return expected<_Up, _Err>(__expected_construct_in_place_from_invoke_tag{}, std::forward<_Func>(__f), __repr_.__union_.__val_);
} else {
- std::invoke(std::forward<_Func>(__f), __union_.__val_);
+ std::invoke(std::forward<_Func>(__f), __repr_.__union_.__val_);
return expected<_Up, _Err>();
}
}
@@ -768,9 +749,9 @@ class expected {
return expected<_Up, _Err>(unexpect, error());
}
if constexpr (!is_void_v<_Up>) {
- return expected<_Up, _Err>(__expected_construct_in_place_from_invoke_tag{}, std::forward<_Func>(__f), __union_.__val_);
+ return expected<_Up, _Err>(__expected_construct_in_place_from_invoke_tag{}, std::forward<_Func>(__f), __repr_.__union_.__val_);
} else {
- std::invoke(std::forward<_Func>(__f), __union_.__val_);
+ std::invoke(std::forward<_Func>(__f), __repr_.__union_.__val_);
return expected<_Up, _Err>();
}
}
@@ -784,9 +765,9 @@ class expected {
}
if constexpr (!is_void_v<_Up>) {
return expected<_Up, _Err>(
- __expected_construct_in_place_from_invoke_tag{}, std::forward<_Func>(__f), std::move(__union_.__val_));
+ __expected_construct_in_place_from_invoke_tag{}, std::forward<_Func>(__f), std::move(__repr_.__union_.__val_));
} else {
- std::invoke(std::forward<_Func>(__f), std::move(__union_.__val_));
+ std::invoke(std::forward<_Func>(__f), std::move(__repr_.__union_.__val_));
return expected<_Up, _Err>();
}
}
@@ -800,9 +781,9 @@ class expected {
}
if constexpr (!is_void_v<_Up>) {
return expected<_Up, _Err>(
- __expected_construct_in_place_from_invoke_tag{}, std::forward<_Func>(__f), std::move(__union_.__val_));
+ __expected_construct_in_place_from_invoke_tag{}, std::forward<_Func>(__f), std::move(__repr_.__union_.__val_));
} else {
- std::invoke(std::forward<_Func>(__f), std::move(__union_.__val_));
+ std::invoke(std::forward<_Func>(__f), std::move(__repr_.__union_.__val_));
return expected<_Up, _Err>();
}
}
@@ -814,7 +795,7 @@ class expected {
static_assert(__valid_std_unexpected<_Gp>::value,
"The result of f(error()) must be a valid template argument for unexpected");
if (has_value()) {
- return expected<_Tp, _Gp>(in_place, __union_.__val_);
+ return expected<_Tp, _Gp>(in_place, __repr_.__union_.__val_);
}
return expected<_Tp, _Gp>(__expected_construct_unexpected_from_invoke_tag{}, std::forward<_Func>(__f), error());
}
@@ -826,7 +807,7 @@ class expected {
static_assert(__valid_std_unexpected<_Gp>::value,
"The result of f(error()) must be a valid template argument for unexpected");
if (has_value()) {
- return expected<_Tp, _Gp>(in_place, __union_.__val_);
+ return expected<_Tp, _Gp>(in_place, __repr_.__union_.__val_);
}
return expected<_Tp, _Gp>(__expected_construct_unexpected_from_invoke_tag{}, std::forward<_Func>(__f), error());
}
@@ -838,7 +819,7 @@ class expected {
static_assert(__valid_std_unexpected<_Gp>::value,
"The result of f(std::move(error())) must be a valid template argument for unexpected");
if (has_value()) {
- return expected<_Tp, _Gp>(in_place, std::move(__union_.__val_));
+ return expected<_Tp, _Gp>(in_place, std::move(__repr_.__union_.__val_));
}
return expected<_Tp, _Gp>(
__expected_construct_unexpected_from_invoke_tag{}, std::forward<_Func>(__f), std::move(error()));
@@ -851,7 +832,7 @@ class expected {
static_assert(__valid_std_unexpected<_Gp>::value,
"The result of f(std::move(error())) must be a valid template argument for unexpected");
if (has_value()) {
- return expected<_Tp, _Gp>(in_place, std::move(__union_.__val_));
+ return expected<_Tp, _Gp>(in_place, std::move(__repr_.__union_.__val_));
}
return expected<_Tp, _Gp>(
__expected_construct_unexpected_from_invoke_tag{}, std::forward<_Func>(__f), std::move(error()));
@@ -861,25 +842,25 @@ class expected {
template <class _T2, class _E2>
requires(!is_void_v<_T2>)
_LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const expected& __x, const expected<_T2, _E2>& __y) {
- if (__x.__has_val_ != __y.__has_val_) {
+ if (__x.__repr_.__has_val_ != __y.__repr_.__has_val_) {
return false;
} else {
- if (__x.__has_val_) {
- return __x.__union_.__val_ == __y.__union_.__val_;
+ if (__x.__repr_.__has_val_) {
+ return __x.__repr_.__union_.__val_ == __y.__repr_.__union_.__val_;
} else {
- return __x.__union_.__unex_ == __y.__union_.__unex_;
+ return __x.__repr_.__union_.__unex_ == __y.__repr_.__union_.__unex_;
}
}
}
template <class _T2>
_LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const expected& __x, const _T2& __v) {
- return __x.__has_val_ && static_cast<bool>(__x.__union_.__val_ == __v);
+ return __x.__repr_.__has_val_ && static_cast<bool>(__x.__repr_.__union_.__val_ == __v);
}
template <class _E2>
_LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const expected& __x, const unexpected<_E2>& __e) {
- return !__x.__has_val_ && static_cast<bool>(__x.__union_.__unex_ == __e.error());
+ return !__x.__repr_.__has_val_ && static_cast<bool>(__x.__repr_.__union_.__unex_ == __e.error());
}
private:
@@ -971,9 +952,7 @@ class expected {
_LIBCPP_NO_UNIQUE_ADDRESS _ErrorType __unex_;
};
- _LIBCPP_NO_UNIQUE_ADDRESS __union_t<_Tp, _Err> __union_;
- _LIBCPP_NO_UNIQUE_ADDRESS bool __has_val_;
- _LIBCPP_NO_UNIQUE_ADDRESS __expected_padding_t<__union_t<_Tp, _Err>> __padding_{};
+ __expected_repr<__union_t<_Tp, _Err>> __repr_;
};
template <class _Tp, class _Err>
@@ -1004,7 +983,7 @@ class expected<_Tp, _Err> {
using rebind = expected<_Up, error_type>;
// [expected.void.ctor], constructors
- _LIBCPP_HIDE_FROM_ABI constexpr expected() noexcept : __has_val_(true) {}
+ _LIBCPP_HIDE_FROM_ABI constexpr expected() noexcept : __repr_{.__union_{}, .__has_val_ = true} {}
_LIBCPP_HIDE_FROM_ABI constexpr expected(const expected&) = delete;
@@ -1015,7 +994,7 @@ class expected<_Tp, _Err> {
_LIBCPP_HIDE_FROM_ABI constexpr expected(const expected& __rhs)
noexcept(is_nothrow_copy_constructible_v<_Err>) // strengthened
requires(is_copy_constructible_v<_Err> && !is_trivially_copy_constructible_v<_Err>)
- : __union_(__rhs.__has_val_, __rhs.__union_), __has_val_(__rhs.__has_val_) {}
+ : __repr_{.__union_{__rhs.__repr_.__has_val_, __rhs.__repr_.__union_}, .__has_val_ = __rhs.__repr_.__has_val_} {}
_LIBCPP_HIDE_FROM_ABI constexpr expected(expected&&)
requires(is_move_constructible_v<_Err> && is_trivially_move_constructible_v<_Err>)
@@ -1024,61 +1003,61 @@ class expected<_Tp, _Err> {
_LIBCPP_HIDE_FROM_ABI constexpr expected(expected&& __rhs)
noexcept(is_nothrow_move_constructible_v<_Err>)
requires(is_move_constructible_v<_Err> && !is_trivially_move_constructible_v<_Err>)
- : __union_(__rhs.__has_val_, std::move(__rhs.__union_)), __has_val_(__rhs.__has_val_) {}
+ : __repr_{.__union_{__rhs.__repr_.__has_val_, std::move(__rhs.__repr_.__union_)}, .__has_val_ = __rhs.__repr_.__has_val_} {}
template <class _Up, class _OtherErr>
requires __can_convert<_Up, _OtherErr, const _OtherErr&>::value
_LIBCPP_HIDE_FROM_ABI constexpr explicit(!is_convertible_v<const _OtherErr&, _Err>)
expected(const expected<_Up, _OtherErr>& __rhs)
noexcept(is_nothrow_constructible_v<_Err, const _OtherErr&>) // strengthened
- : __union_(__rhs.__has_val_, __rhs.__union_), __has_val_(__rhs.__has_val_) {}
+ : __repr_{.__union_{__rhs.__repr_.__has_val_, __rhs.__repr_.__union_}, .__has_val_ = __rhs.__repr_.__has_val_} {}
template <class _Up, class _OtherErr>
requires __can_convert<_Up, _OtherErr, _OtherErr>::value
_LIBCPP_HIDE_FROM_ABI constexpr explicit(!is_convertible_v<_OtherErr, _Err>)
expected(expected<_Up, _OtherErr>&& __rhs)
noexcept(is_nothrow_constructible_v<_Err, _OtherErr>) // strengthened
- : __union_(__rhs.__has_val_, std::move(__rhs.__union_)), __has_val_(__rhs.__has_val_) {}
+ : __repr_{.__union_{__rhs.__repr_.__has_val_, std::move(__rhs.__repr_.__union_)}, .__has_val_ = __rhs.__repr_.__has_val_} {}
template <class _OtherErr>
requires is_constructible_v<_Err, const _OtherErr&>
_LIBCPP_HIDE_FROM_ABI constexpr explicit(!is_convertible_v<const _OtherErr&, _Err>)
expected(const unexpected<_OtherErr>& __unex)
noexcept(is_nothrow_constructible_v<_Err, const _OtherErr&>) // strengthened
- : __union_(std::unexpect, __unex.error()), __has_val_(false) {}
+ : __repr_{.__union_{std::unexpect, __unex.error()}, .__has_val_ = false} {}
template <class _OtherErr>
requires is_constructible_v<_Err, _OtherErr>
_LIBCPP_HIDE_FROM_ABI constexpr explicit(!is_convertible_v<_OtherErr, _Err>)
expected(unexpected<_OtherErr>&& __unex)
noexcept(is_nothrow_constructible_v<_Err, _OtherErr>) // strengthened
- : __union_(std::unexpect, std::move(__unex.error())), __has_val_(false) {}
+ : __repr_{.__union_{std::unexpect, std::move(__unex.error())}, .__has_val_ = false} {}
- _LIBCPP_HIDE_FROM_ABI constexpr explicit expected(in_place_t) noexcept : __has_val_(true) {}
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit expected(in_place_t) noexcept : __repr_{.__union_{}, .__has_val_ = true} {}
template <class... _Args>
requires is_constructible_v<_Err, _Args...>
_LIBCPP_HIDE_FROM_ABI constexpr explicit expected(unexpect_t, _Args&&... __args)
noexcept(is_nothrow_constructible_v<_Err, _Args...>) // strengthened
- : __union_(std::unexpect, std::forward<_Args>(__args)...), __has_val_(false) {}
+ : __repr_{.__union_{std::unexpect, std::forward<_Args>(__args)...}, .__has_val_ = false} {}
template <class _Up, class... _Args>
requires is_constructible_v< _Err, initializer_list<_Up>&, _Args... >
_LIBCPP_HIDE_FROM_ABI constexpr explicit expected(unexpect_t, initializer_list<_Up> __il, _Args&&... __args)
noexcept(is_nothrow_constructible_v<_Err, initializer_list<_Up>&, _Args...>) // strengthened
- : __union_(std::unexpect, __il, std::forward<_Args>(__args)...), __has_val_(false) {}
+ : __repr_{.__union_{std::unexpect, __il, std::forward<_Args>(__args)...}, .__has_val_ = false} {}
private:
template <class _Func>
_LIBCPP_HIDE_FROM_ABI constexpr explicit expected(__expected_construct_in_place_from_invoke_tag, _Func&& __f)
- : __has_val_(true) {
+ : __repr_{.__union_{}, .__has_val_ = true} {
std::invoke(std::forward<_Func>(__f));
}
template <class _Func, class... _Args>
_LIBCPP_HIDE_FROM_ABI constexpr explicit expected(
__expected_construct_unexpected_from_invoke_tag __tag, _Func&& __f, _Args&&... __args)
- : __union_(__tag, std::forward<_Func>(__f), std::forward<_Args>(__args)...), __has_val_(false) {}
+ : __repr_{.__union_{__tag, std::forward<_Func>(__f), std::forward<_Args>(__args)...}, .__has_val_ = false} {}
public:
// [expected.void.dtor], destructor
@@ -1090,8 +1069,8 @@ class expected<_Tp, _Err> {
_LIBCPP_HIDE_FROM_ABI constexpr ~expected()
requires(!is_trivially_destructible_v<_Err>)
{
- if (!__has_val_) {
- std::destroy_at(std::addressof(__union_.__unex_));
+ if (!__repr_.__has_val_) {
+ std::destroy_at(std::addressof(__repr_.__union_.__unex_));
}
}
@@ -1103,17 +1082,17 @@ class expected<_Tp, _Err> {
noexcept(is_nothrow_copy_assignable_v<_Err> && is_nothrow_copy_constructible_v<_Err>) // strengthened
requires(is_copy_assignable_v<_Err> && is_copy_constructible_v<_Err>)
{
- if (__has_val_) {
- if (!__rhs.__has_val_) {
- std::construct_at(std::addressof(__union_.__unex_), __rhs.__union_.__unex_);
- __has_val_ = false;
+ if (__repr_.__has_val_) {
+ if (!__rhs.__repr_.__has_val_) {
+ std::construct_at(std::addressof(__repr_.__union_.__unex_), __rhs.__repr_.__union_.__unex_);
+ __repr_.__has_val_ = false;
}
} else {
- if (__rhs.__has_val_) {
- std::destroy_at(std::addressof(__union_.__unex_));
- __has_val_ = true;
+ if (__rhs.__repr_.__has_val_) {
+ std::destroy_at(std::addressof(__repr_.__union_.__unex_));
+ __repr_.__has_val_ = true;
} else {
- __union_.__unex_ = __rhs.__union_.__unex_;
+ __repr_.__union_.__unex_ = __rhs.__repr_.__union_.__unex_;
}
}
return *this;
@@ -1127,17 +1106,17 @@ class expected<_Tp, _Err> {
requires(is_move_assignable_v<_Err> &&
is_move_constructible_v<_Err>)
{
- if (__has_val_) {
- if (!__rhs.__has_val_) {
- std::construct_at(std::addressof(__union_.__unex_), std::move(__rhs.__union_.__unex_));
- __has_val_ = false;
+ if (__repr_.__has_val_) {
+ if (!__rhs.__repr_.__has_val_) {
+ std::construct_at(std::addressof(__repr_.__union_.__unex_), std::move(__rhs.__repr_.__union_.__unex_));
+ __repr_.__has_val_ = false;
}
} else {
- if (__rhs.__has_val_) {
- std::destroy_at(std::addressof(__union_.__unex_));
- __has_val_ = true;
+ if (__rhs.__repr_.__has_val_) {
+ std::destroy_at(std::addressof(__repr_.__union_.__unex_));
+ __repr_.__has_val_ = true;
} else {
- __union_.__unex_ = std::move(__rhs.__union_.__unex_);
+ __repr_.__union_.__unex_ = std::move(__rhs.__repr_.__union_.__unex_);
}
}
return *this;
@@ -1146,11 +1125,11 @@ class expected<_Tp, _Err> {
template <class _OtherErr>
requires(is_constructible_v<_Err, const _OtherErr&> && is_assignable_v<_Err&, const _OtherErr&>)
_LIBCPP_HIDE_FROM_ABI constexpr expected& operator=(const unexpected<_OtherErr>& __un) {
- if (__has_val_) {
- std::construct_at(std::addressof(__union_.__unex_), __un.error());
- __has_val_ = false;
+ if (__repr_.__has_val_) {
+ std::construct_at(std::addressof(__repr_.__union_.__unex_), __un.error());
+ __repr_.__has_val_ = false;
} else {
- __union_.__unex_ = __un.error();
+ __repr_.__union_.__unex_ = __un.error();
}
return *this;
}
@@ -1158,19 +1137,19 @@ class expected<_Tp, _Err> {
template <class _OtherErr>
requires(is_constructible_v<_Err, _OtherErr> && is_assignable_v<_Err&, _OtherErr>)
_LIBCPP_HIDE_FROM_ABI constexpr expected& operator=(unexpected<_OtherErr>&& __un) {
- if (__has_val_) {
- std::construct_at(std::addressof(__union_.__unex_), std::move(__un.error()));
- __has_val_ = false;
+ if (__repr_.__has_val_) {
+ std::construct_at(std::addressof(__repr_.__union_.__unex_), std::move(__un.error()));
+ __repr_.__has_val_ = false;
} else {
- __union_.__unex_ = std::move(__un.error());
+ __repr_.__union_.__unex_ = std::move(__un.error());
}
return *this;
}
_LIBCPP_HIDE_FROM_ABI constexpr void emplace() noexcept {
- if (!__has_val_) {
- std::destroy_at(std::addressof(__union_.__unex_));
- __has_val_ = true;
+ if (!__repr_.__has_val_) {
+ std::destroy_at(std::addressof(__repr_.__union_.__unex_));
+ __repr_.__has_val_ = true;
}
}
@@ -1180,22 +1159,22 @@ class expected<_Tp, _Err> {
requires(is_swappable_v<_Err> && is_move_constructible_v<_Err>)
{
auto __swap_val_unex_impl = [&](expected& __with_val, expected& __with_err) {
- std::construct_at(std::addressof(__with_val.__union_.__unex_), std::move(__with_err.__union_.__unex_));
- std::destroy_at(std::addressof(__with_err.__union_.__unex_));
- __with_val.__has_val_ = false;
- __with_err.__has_val_ = true;
+ std::construct_at(std::addressof(__with_val.__repr_.__union_.__unex_), std::move(__with_err.__repr_.__union_.__unex_));
+ std::destroy_at(std::addressof(__with_err.__repr_.__union_.__unex_));
+ __with_val.__repr_.__has_val_ = false;
+ __with_err.__repr_.__has_val_ = true;
};
- if (__has_val_) {
- if (!__rhs.__has_val_) {
+ if (__repr_.__has_val_) {
+ if (!__rhs.__repr_.__has_val_) {
__swap_val_unex_impl(*this, __rhs);
}
} else {
- if (__rhs.__has_val_) {
+ if (__rhs.__repr_.__has_val_) {
__swap_val_unex_impl(__rhs, *this);
} else {
using std::swap;
- swap(__union_.__unex_, __rhs.__union_.__unex_);
+ swap(__repr_.__union_.__unex_, __rhs.__repr_.__union_.__unex_);
}
}
}
@@ -1208,44 +1187,44 @@ class expected<_Tp, _Err> {
}
// [expected.void.obs], observers
- _LIBCPP_HIDE_FROM_ABI constexpr explicit operator bool() const noexcept { return __has_val_; }
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit operator bool() const noexcept { return __repr_.__has_val_; }
- _LIBCPP_HIDE_FROM_ABI constexpr bool has_value() const noexcept { return __has_val_; }
+ _LIBCPP_HIDE_FROM_ABI constexpr bool has_value() const noexcept { return __repr_.__has_val_; }
_LIBCPP_HIDE_FROM_ABI constexpr void operator*() const noexcept {
- _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__has_val_, "expected::operator* requires the expected to contain a value");
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__repr_.__has_val_, "expected::operator* requires the expected to contain a value");
}
_LIBCPP_HIDE_FROM_ABI constexpr void value() const& {
- if (!__has_val_) {
- std::__throw_bad_expected_access<_Err>(__union_.__unex_);
+ if (!__repr_.__has_val_) {
+ std::__throw_bad_expected_access<_Err>(__repr_.__union_.__unex_);
}
}
_LIBCPP_HIDE_FROM_ABI constexpr void value() && {
- if (!__has_val_) {
- std::__throw_bad_expected_access<_Err>(std::move(__union_.__unex_));
+ if (!__repr_.__has_val_) {
+ std::__throw_bad_expected_access<_Err>(std::move(__repr_.__union_.__unex_));
}
}
_LIBCPP_HIDE_FROM_ABI constexpr const _Err& error() const& noexcept {
- _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!__has_val_, "expected::error requires the expected to contain an error");
- return __union_.__unex_;
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!__repr_.__has_val_, "expected::error requires the expected to contain an error");
+ return __repr_.__union_.__unex_;
}
_LIBCPP_HIDE_FROM_ABI constexpr _Err& error() & noexcept {
- _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!__has_val_, "expected::error requires the expected to contain an error");
- return __union_.__unex_;
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!__repr_.__has_val_, "expected::error requires the expected to contain an error");
+ return __repr_.__union_.__unex_;
}
_LIBCPP_HIDE_FROM_ABI constexpr const _Err&& error() const&& noexcept {
- _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!__has_val_, "expected::error requires the expected to contain an error");
- return std::move(__union_.__unex_);
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!__repr_.__has_val_, "expected::error requires the expected to contain an error");
+ return std::move(__repr_.__union_.__unex_);
}
_LIBCPP_HIDE_FROM_ABI constexpr _Err&& error() && noexcept {
- _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!__has_val_, "expected::error requires the expected to contain an error");
- return std::move(__union_.__unex_);
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!__repr_.__has_val_, "expected::error requires the expected to contain an error");
+ return std::move(__repr_.__union_.__unex_);
}
template <class _Up = _Err>
@@ -1481,16 +1460,16 @@ class expected<_Tp, _Err> {
template <class _T2, class _E2>
requires is_void_v<_T2>
_LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const expected& __x, const expected<_T2, _E2>& __y) {
- if (__x.__has_val_ != __y.__has_val_) {
+ if (__x.__repr_.__has_val_ != __y.__repr_.__has_val_) {
return false;
} else {
- return __x.__has_val_ || static_cast<bool>(__x.__union_.__unex_ == __y.__union_.__unex_);
+ return __x.__repr_.__has_val_ || static_cast<bool>(__x.__repr_.__union_.__unex_ == __y.__repr_.__union_.__unex_);
}
}
template <class _E2>
_LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const expected& __x, const unexpected<_E2>& __y) {
- return !__x.__has_val_ && static_cast<bool>(__x.__union_.__unex_ == __y.error());
+ return !__x.__repr_.__has_val_ && static_cast<bool>(__x.__repr_.__union_.__unex_ == __y.error());
}
private:
@@ -1569,9 +1548,7 @@ class expected<_Tp, _Err> {
_LIBCPP_NO_UNIQUE_ADDRESS _ErrorType __unex_;
};
- _LIBCPP_NO_UNIQUE_ADDRESS __union_t<_Err> __union_;
- _LIBCPP_NO_UNIQUE_ADDRESS bool __has_val_;
- _LIBCPP_NO_UNIQUE_ADDRESS __expected_padding_t<__union_t<_Err>> __padding_{};
+ __expected_repr<__union_t<_Err>> __repr_;
};
_LIBCPP_END_NAMESPACE_STD
diff --git a/libcxx/test/libcxx/utilities/expected/expected.expected/no_unique_address.compile.pass.cpp b/libcxx/test/libcxx/utilities/expected/expected.expected/no_unique_address.compile.pass.cpp
index 06f597d54871e..80209db9045b5 100644
--- a/libcxx/test/libcxx/utilities/expected/expected.expected/no_unique_address.compile.pass.cpp
+++ b/libcxx/test/libcxx/utilities/expected/expected.expected/no_unique_address.compile.pass.cpp
@@ -13,6 +13,7 @@
// test [[no_unique_address]] is applied to the union
#include <expected>
+#include <memory>
struct Empty {};
diff --git a/libcxx/test/libcxx/utilities/expected/expected.void/no_unique_address.compile.pass.cpp b/libcxx/test/libcxx/utilities/expected/expected.void/no_unique_address.compile.pass.cpp
index 29cf8dff0d2b2..db2e4259eb8c7 100644
--- a/libcxx/test/libcxx/utilities/expected/expected.void/no_unique_address.compile.pass.cpp
+++ b/libcxx/test/libcxx/utilities/expected/expected.void/no_unique_address.compile.pass.cpp
@@ -13,6 +13,7 @@
// test [[no_unique_address]] is applied to the union
#include <expected>
+#include <memory>
struct Empty {};
>From b8f12292072387059ce85b6845b5805a9d0e55f6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jan=20Kokem=C3=BCller?= <jan.kokemueller at gmail.com>
Date: Sat, 21 Oct 2023 10:52:00 +0200
Subject: [PATCH 06/37] transparently replace whole 'repr' struct on mutating
operations
---
libcxx/include/__expected/expected.h | 208 ++++++++++--------
.../no_unique_address.compile.pass.cpp | 3 +-
.../no_unique_address.compile.pass.cpp | 3 +-
3 files changed, 125 insertions(+), 89 deletions(-)
diff --git a/libcxx/include/__expected/expected.h b/libcxx/include/__expected/expected.h
index ab7cae1c1007f..cd5e2d64411b9 100644
--- a/libcxx/include/__expected/expected.h
+++ b/libcxx/include/__expected/expected.h
@@ -89,12 +89,6 @@ _LIBCPP_HIDE_FROM_ABI void __throw_bad_expected_access(_Arg&& __arg) {
# endif
}
-template <class _Union>
-struct __expected_repr {
- [[no_unique_address]] _Union __union_;
- [[no_unique_address]] bool __has_val_;
-};
-
template <class _Tp, class _Err>
class expected {
static_assert(
@@ -126,7 +120,7 @@ class expected {
_LIBCPP_HIDE_FROM_ABI constexpr expected()
noexcept(is_nothrow_default_constructible_v<_Tp>) // strengthened
requires is_default_constructible_v<_Tp>
- : __repr_{.__union_{std::in_place}, .__has_val_ = true} {}
+ : __repr_(std::in_place) {}
_LIBCPP_HIDE_FROM_ABI constexpr expected(const expected&) = delete;
@@ -141,7 +135,7 @@ class expected {
noexcept(is_nothrow_copy_constructible_v<_Tp> && is_nothrow_copy_constructible_v<_Err>) // strengthened
requires(is_copy_constructible_v<_Tp> && is_copy_constructible_v<_Err> &&
!(is_trivially_copy_constructible_v<_Tp> && is_trivially_copy_constructible_v<_Err>))
- : __repr_{.__union_{__other.__repr_.__has_val_, __other.__repr_.__union_}, .__has_val_ = __other.__repr_.__has_val_} { }
+ : __repr_(__other.__repr_.__has_val_, __other.__repr_.__union_) { }
_LIBCPP_HIDE_FROM_ABI constexpr expected(expected&&)
requires(is_move_constructible_v<_Tp> && is_move_constructible_v<_Err>
@@ -152,8 +146,7 @@ class expected {
noexcept(is_nothrow_move_constructible_v<_Tp> && is_nothrow_move_constructible_v<_Err>)
requires(is_move_constructible_v<_Tp> && is_move_constructible_v<_Err> &&
!(is_trivially_move_constructible_v<_Tp> && is_trivially_move_constructible_v<_Err>))
- : __repr_{.__union_{__other.__repr_.__has_val_, std::move(__other.__repr_.__union_)},
- .__has_val_ = __other.__repr_.__has_val_} { }
+ : __repr_(__other.__repr_.__has_val_, std::move(__other.__repr_.__union_)) { }
private:
template <class _Up, class _OtherErr, class _UfQual, class _OtherErrQual>
@@ -178,12 +171,12 @@ class expected {
template <class _Func, class... _Args>
_LIBCPP_HIDE_FROM_ABI constexpr explicit expected(
std::__expected_construct_in_place_from_invoke_tag __tag, _Func&& __f, _Args&&... __args)
- : __repr_{.__union_{__tag, std::forward<_Func>(__f), std::forward<_Args>(__args)...}, .__has_val_ = true} {}
+ : __repr_(__tag, std::forward<_Func>(__f), std::forward<_Args>(__args)...) {}
template <class _Func, class... _Args>
_LIBCPP_HIDE_FROM_ABI constexpr explicit expected(
std::__expected_construct_unexpected_from_invoke_tag __tag, _Func&& __f, _Args&&... __args)
- : __repr_{.__union_{__tag, std::forward<_Func>(__f), std::forward<_Args>(__args)...}, .__has_val_ = false} {}
+ : __repr_(__tag, std::forward<_Func>(__f), std::forward<_Args>(__args)...) {}
public:
template <class _Up, class _OtherErr>
@@ -193,16 +186,14 @@ class expected {
expected(const expected<_Up, _OtherErr>& __other)
noexcept(is_nothrow_constructible_v<_Tp, const _Up&> &&
is_nothrow_constructible_v<_Err, const _OtherErr&>) // strengthened
- : __repr_{.__union_{__other.__repr_.__has_val_, __other.__repr_.__union_},
- .__has_val_ = __other.__repr_.__has_val_} {}
+ : __repr_(__other.__repr_.__has_val_, __other.__repr_.__union_) {}
template <class _Up, class _OtherErr>
requires __can_convert<_Up, _OtherErr, _Up, _OtherErr>::value
_LIBCPP_HIDE_FROM_ABI constexpr explicit(!is_convertible_v<_Up, _Tp> || !is_convertible_v<_OtherErr, _Err>)
expected(expected<_Up, _OtherErr>&& __other)
noexcept(is_nothrow_constructible_v<_Tp, _Up> && is_nothrow_constructible_v<_Err, _OtherErr>) // strengthened
- : __repr_{.__union_{__other.__repr_.__has_val_, std::move(__other.__repr_.__union_)},
- .__has_val_ = __other.__repr_.__has_val_} {}
+ : __repr_(__other.__repr_.__has_val_, std::move(__other.__repr_.__union_)) {}
template <class _Up = _Tp>
requires(!is_same_v<remove_cvref_t<_Up>, in_place_t> && !is_same_v<expected, remove_cvref_t<_Up>> &&
@@ -210,84 +201,72 @@ class expected {
(!is_same_v<remove_cv_t<_Tp>, bool> || !__is_std_expected<remove_cvref_t<_Up>>::value))
_LIBCPP_HIDE_FROM_ABI constexpr explicit(!is_convertible_v<_Up, _Tp>)
expected(_Up&& __u) noexcept(is_nothrow_constructible_v<_Tp, _Up>) // strengthened
- : __repr_{.__union_{std::in_place, std::forward<_Up>(__u)}, .__has_val_ = true} {}
+ : __repr_(std::in_place, std::forward<_Up>(__u)) {}
template <class _OtherErr>
requires is_constructible_v<_Err, const _OtherErr&>
_LIBCPP_HIDE_FROM_ABI constexpr explicit(!is_convertible_v<const _OtherErr&, _Err>)
expected(const unexpected<_OtherErr>& __unex)
noexcept(is_nothrow_constructible_v<_Err, const _OtherErr&>) // strengthened
- : __repr_{.__union_{std::unexpect, __unex.error()}, .__has_val_ = false} {}
+ : __repr_(std::unexpect, __unex.error()) {}
template <class _OtherErr>
requires is_constructible_v<_Err, _OtherErr>
_LIBCPP_HIDE_FROM_ABI constexpr explicit(!is_convertible_v<_OtherErr, _Err>)
expected(unexpected<_OtherErr>&& __unex)
noexcept(is_nothrow_constructible_v<_Err, _OtherErr>) // strengthened
- : __repr_{.__union_{std::unexpect, std::move(__unex.error())}, .__has_val_ = false} {}
+ : __repr_(std::unexpect, std::move(__unex.error())) {}
template <class... _Args>
requires is_constructible_v<_Tp, _Args...>
_LIBCPP_HIDE_FROM_ABI constexpr explicit expected(in_place_t, _Args&&... __args)
noexcept(is_nothrow_constructible_v<_Tp, _Args...>) // strengthened
- : __repr_{.__union_{std::in_place, std::forward<_Args>(__args)...}, .__has_val_ = true} {}
+ : __repr_(std::in_place, std::forward<_Args>(__args)...) {}
template <class _Up, class... _Args>
requires is_constructible_v< _Tp, initializer_list<_Up>&, _Args... >
_LIBCPP_HIDE_FROM_ABI constexpr explicit
expected(in_place_t, initializer_list<_Up> __il, _Args&&... __args)
noexcept(is_nothrow_constructible_v<_Tp, initializer_list<_Up>&, _Args...>) // strengthened
- : __repr_{.__union_{std::in_place, __il, std::forward<_Args>(__args)...}, .__has_val_ = true} {}
+ : __repr_(std::in_place, __il, std::forward<_Args>(__args)...) {}
template <class... _Args>
requires is_constructible_v<_Err, _Args...>
_LIBCPP_HIDE_FROM_ABI constexpr explicit expected(unexpect_t, _Args&&... __args)
noexcept(is_nothrow_constructible_v<_Err, _Args...>) // strengthened
- : __repr_{.__union_{std::unexpect, std::forward<_Args>(__args)...}, .__has_val_ = false} {}
+ : __repr_(std::unexpect, std::forward<_Args>(__args)...) {}
template <class _Up, class... _Args>
requires is_constructible_v< _Err, initializer_list<_Up>&, _Args... >
_LIBCPP_HIDE_FROM_ABI constexpr explicit
expected(unexpect_t, initializer_list<_Up> __il, _Args&&... __args)
noexcept(is_nothrow_constructible_v<_Err, initializer_list<_Up>&, _Args...>) // strengthened
- : __repr_{.__union_{std::unexpect, __il, std::forward<_Args>(__args)...}, .__has_val_ = false} {}
+ : __repr_(std::unexpect, __il, std::forward<_Args>(__args)...) {}
// [expected.object.dtor], destructor
- _LIBCPP_HIDE_FROM_ABI constexpr ~expected()
- requires(is_trivially_destructible_v<_Tp> && is_trivially_destructible_v<_Err>)
- = default;
-
- _LIBCPP_HIDE_FROM_ABI constexpr ~expected()
- requires(!is_trivially_destructible_v<_Tp> || !is_trivially_destructible_v<_Err>)
- {
- if (__repr_.__has_val_) {
- std::destroy_at(std::addressof(__repr_.__union_.__val_));
- } else {
- std::destroy_at(std::addressof(__repr_.__union_.__unex_));
- }
- }
+ _LIBCPP_HIDE_FROM_ABI constexpr ~expected() = default;
private:
- template <class _T1, class _T2, class... _Args>
- _LIBCPP_HIDE_FROM_ABI static constexpr void __reinit_expected(_T1& __newval, _T2& __oldval, _Args&&... __args) {
+ template <class _Tag, class _OtherTag, class _T1, class _T2, class... _Args>
+ _LIBCPP_HIDE_FROM_ABI constexpr void __reinit_expected(_T2& __oldval, _Args&&... __args) {
if constexpr (is_nothrow_constructible_v<_T1, _Args...>) {
- std::destroy_at(std::addressof(__oldval));
- std::construct_at(std::addressof(__newval), std::forward<_Args>(__args)...);
+ std::destroy_at(&__repr_);
+ std::construct_at(&__repr_, _Tag{}, std::forward<_Args>(__args)...);
} else if constexpr (is_nothrow_move_constructible_v<_T1>) {
_T1 __tmp(std::forward<_Args>(__args)...);
- std::destroy_at(std::addressof(__oldval));
- std::construct_at(std::addressof(__newval), std::move(__tmp));
+ std::destroy_at(&__repr_);
+ std::construct_at(&__repr_, _Tag{}, std::move(__tmp));
} else {
static_assert(
is_nothrow_move_constructible_v<_T2>,
"To provide strong exception guarantee, T2 has to satisfy `is_nothrow_move_constructible_v` so that it can "
"be reverted to the previous state in case an exception is thrown during the assignment.");
_T2 __tmp(std::move(__oldval));
- std::destroy_at(std::addressof(__oldval));
+ std::destroy_at(&__repr_);
auto __trans =
- std::__make_exception_guard([&] { std::construct_at(std::addressof(__oldval), std::move(__tmp)); });
- std::construct_at(std::addressof(__newval), std::forward<_Args>(__args)...);
+ std::__make_exception_guard([&] { std::construct_at(&__repr_, _OtherTag{}, std::move(__tmp)); });
+ std::construct_at(&__repr_, _Tag{}, std::forward<_Args>(__args)...);
__trans.__complete();
}
}
@@ -311,14 +290,14 @@ class expected {
if (__repr_.__has_val_ && __rhs.__repr_.__has_val_) {
__repr_.__union_.__val_ = __rhs.__repr_.__union_.__val_;
} else if (__repr_.__has_val_) {
- __reinit_expected(__repr_.__union_.__unex_, __repr_.__union_.__val_, __rhs.__repr_.__union_.__unex_);
+ __reinit_expected<std::unexpect_t, std::in_place_t, _Err, _Tp>(
+ __repr_.__union_.__val_, __rhs.__repr_.__union_.__unex_);
} else if (__rhs.__repr_.__has_val_) {
- __reinit_expected(__repr_.__union_.__val_, __repr_.__union_.__unex_, __rhs.__repr_.__union_.__val_);
+ __reinit_expected<std::in_place_t, std::unexpect_t, _Tp, _Err>(
+ __repr_.__union_.__unex_, __rhs.__repr_.__union_.__val_);
} else {
__repr_.__union_.__unex_ = __rhs.__repr_.__union_.__unex_;
}
- // note: only reached if no exception+rollback was done inside __reinit_expected
- __repr_.__has_val_ = __rhs.__repr_.__has_val_;
return *this;
}
@@ -337,14 +316,14 @@ class expected {
if (__repr_.__has_val_ && __rhs.__repr_.__has_val_) {
__repr_.__union_.__val_ = std::move(__rhs.__repr_.__union_.__val_);
} else if (__repr_.__has_val_) {
- __reinit_expected(__repr_.__union_.__unex_, __repr_.__union_.__val_, std::move(__rhs.__repr_.__union_.__unex_));
+ __reinit_expected<std::unexpect_t, std::in_place_t, _Err, _Tp>(
+ __repr_.__union_.__val_, std::move(__rhs.__repr_.__union_.__unex_));
} else if (__rhs.__repr_.__has_val_) {
- __reinit_expected(__repr_.__union_.__val_, __repr_.__union_.__unex_, std::move(__rhs.__repr_.__union_.__val_));
+ __reinit_expected<std::in_place_t, std::unexpect_t, _Tp, _Err>(
+ __repr_.__union_.__unex_, std::move(__rhs.__repr_.__union_.__val_));
} else {
__repr_.__union_.__unex_ = std::move(__rhs.__repr_.__union_.__unex_);
}
- // note: only reached if no exception+rollback was done inside __reinit_expected
- __repr_.__has_val_ = __rhs.__repr_.__has_val_;
return *this;
}
@@ -361,8 +340,8 @@ class expected {
if (__repr_.__has_val_) {
__repr_.__union_.__val_ = std::forward<_Up>(__v);
} else {
- __reinit_expected(__repr_.__union_.__val_, __repr_.__union_.__unex_, std::forward<_Up>(__v));
- __repr_.__has_val_ = true;
+ __reinit_expected<std::in_place_t, std::unexpect_t, _Tp, _Err>(
+ __repr_.__union_.__unex_, std::forward<_Up>(__v));
}
return *this;
}
@@ -382,8 +361,8 @@ class expected {
requires(__can_assign_from_unexpected<const _OtherErr&>)
_LIBCPP_HIDE_FROM_ABI constexpr expected& operator=(const unexpected<_OtherErr>& __un) {
if (__repr_.__has_val_) {
- __reinit_expected(__repr_.__union_.__unex_, __repr_.__union_.__val_, __un.error());
- __repr_.__has_val_ = false;
+ __reinit_expected<std::unexpect_t, std::in_place_t, _Err, _Tp>(
+ __repr_.__union_.__val_, __un.error());
} else {
__repr_.__union_.__unex_ = __un.error();
}
@@ -394,8 +373,8 @@ class expected {
requires(__can_assign_from_unexpected<_OtherErr>)
_LIBCPP_HIDE_FROM_ABI constexpr expected& operator=(unexpected<_OtherErr>&& __un) {
if (__repr_.__has_val_) {
- __reinit_expected(__repr_.__union_.__unex_, __repr_.__union_.__val_, std::move(__un.error()));
- __repr_.__has_val_ = false;
+ __reinit_expected<std::unexpect_t, std::in_place_t, _Err, _Tp>(
+ __repr_.__union_.__val_, std::move(__un.error()));
} else {
__repr_.__union_.__unex_ = std::move(__un.error());
}
@@ -405,26 +384,16 @@ class expected {
template <class... _Args>
requires is_nothrow_constructible_v<_Tp, _Args...>
_LIBCPP_HIDE_FROM_ABI constexpr _Tp& emplace(_Args&&... __args) noexcept {
- if (__repr_.__has_val_) {
- std::destroy_at(std::addressof(__repr_.__union_.__val_));
- } else {
- std::destroy_at(std::addressof(__repr_.__union_.__unex_));
- }
- std::construct_at(std::addressof(__repr_.__union_.__val_), std::forward<_Args>(__args)...);
- __repr_.__has_val_ = true;
+ std::destroy_at(&__repr_);
+ std::construct_at(&__repr_, std::in_place, std::forward<_Args>(__args)...);
return __repr_.__union_.__val_;
}
template <class _Up, class... _Args>
requires is_nothrow_constructible_v< _Tp, initializer_list<_Up>&, _Args... >
_LIBCPP_HIDE_FROM_ABI constexpr _Tp& emplace(initializer_list<_Up> __il, _Args&&... __args) noexcept {
- if (__repr_.__has_val_) {
- std::destroy_at(std::addressof(__repr_.__union_.__val_));
- } else {
- std::destroy_at(std::addressof(__repr_.__union_.__unex_));
- }
- std::construct_at(std::addressof(__repr_.__union_.__val_), __il, std::forward<_Args>(__args)...);
- __repr_.__has_val_ = true;
+ std::destroy_at(&__repr_);
+ std::construct_at(&__repr_, std::in_place, __il, std::forward<_Args>(__args)...);
return __repr_.__union_.__val_;
}
@@ -443,33 +412,31 @@ class expected {
(is_nothrow_move_constructible_v<_Tp> ||
is_nothrow_move_constructible_v<_Err>))
{
- auto __swap_val_unex_impl = [&](expected& __with_val, expected& __with_err) {
+ auto __swap_val_unex_impl = [](expected& __with_val, expected& __with_err) {
if constexpr (is_nothrow_move_constructible_v<_Err>) {
_Err __tmp(std::move(__with_err.__repr_.__union_.__unex_));
- std::destroy_at(std::addressof(__with_err.__repr_.__union_.__unex_));
+ std::destroy_at(&__with_err.__repr_);
auto __trans = std::__make_exception_guard([&] {
- std::construct_at(std::addressof(__with_err.__repr_.__union_.__unex_), std::move(__tmp));
+ std::construct_at(&__with_err.__repr_, std::unexpect, std::move(__tmp));
});
- std::construct_at(std::addressof(__with_err.__repr_.__union_.__val_), std::move(__with_val.__repr_.__union_.__val_));
+ std::construct_at(&__with_err.__repr_, std::in_place, std::move(__with_val.__repr_.__union_.__val_));
__trans.__complete();
- std::destroy_at(std::addressof(__with_val.__repr_.__union_.__val_));
- std::construct_at(std::addressof(__with_val.__repr_.__union_.__unex_), std::move(__tmp));
+ std::destroy_at(&__with_val.__repr_);
+ std::construct_at(&__with_val.__repr_, std::unexpect, std::move(__tmp));
} else {
static_assert(is_nothrow_move_constructible_v<_Tp>,
"To provide strong exception guarantee, Tp has to satisfy `is_nothrow_move_constructible_v` so "
"that it can be reverted to the previous state in case an exception is thrown during swap.");
_Tp __tmp(std::move(__with_val.__repr_.__union_.__val_));
- std::destroy_at(std::addressof(__with_val.__repr_.__union_.__val_));
+ std::destroy_at(&__with_val.__repr_);
auto __trans = std::__make_exception_guard([&] {
- std::construct_at(std::addressof(__with_val.__repr_.__union_.__val_), std::move(__tmp));
+ std::construct_at(&__with_val.__repr_, std::in_place, std::move(__tmp));
});
- std::construct_at(std::addressof(__with_val.__repr_.__union_.__unex_), std::move(__with_err.__repr_.__union_.__unex_));
+ std::construct_at(&__with_val.__repr_, std::unexpect, std::move(__with_err.__repr_.__union_.__unex_));
__trans.__complete();
- std::destroy_at(std::addressof(__with_err.__repr_.__union_.__unex_));
- std::construct_at(std::addressof(__with_err.__repr_.__union_.__val_), std::move(__tmp));
+ std::destroy_at(&__with_err.__repr_);
+ std::construct_at(&__with_err.__repr_, std::in_place, std::move(__tmp));
}
- __with_val.__repr_.__has_val_ = false;
- __with_err.__repr_.__has_val_ = true;
};
if (__repr_.__has_val_) {
@@ -952,7 +919,74 @@ class expected {
_LIBCPP_NO_UNIQUE_ADDRESS _ErrorType __unex_;
};
- __expected_repr<__union_t<_Tp, _Err>> __repr_;
+ struct __expected_repr {
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_repr() = delete;
+
+ template <class... _Args>
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_repr(std::in_place_t __tag, _Args&&... __args)
+ : __union_(__tag, std::forward<_Args>(__args)...), __has_val_(true) {}
+
+ template <class... _Args>
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_repr(std::unexpect_t __tag, _Args&&... __args)
+ : __union_(__tag, std::forward<_Args>(__args)...), __has_val_(false) {}
+
+ template <class... _Args>
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_repr(
+ std::__expected_construct_in_place_from_invoke_tag __tag, _Args&&... __args)
+ : __union_(__tag, std::forward<_Args>(__args)...), __has_val_(true) {}
+
+ template <class... _Args>
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_repr(
+ std::__expected_construct_unexpected_from_invoke_tag __tag, _Args&&... __args)
+ : __union_(__tag, std::forward<_Args>(__args)...), __has_val_(false) {}
+
+ template <class... _Args>
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_repr(bool __has_val, _Args&&... __args)
+ : __union_(__has_val, std::forward<_Args>(__args)...), __has_val_(__has_val) {}
+
+ _LIBCPP_HIDE_FROM_ABI constexpr __expected_repr(const __expected_repr&) = delete;
+ _LIBCPP_HIDE_FROM_ABI constexpr __expected_repr(const __expected_repr&)
+ requires(is_copy_constructible_v<_Tp> &&
+ is_copy_constructible_v<_Err> &&
+ is_trivially_copy_constructible_v<_Tp> &&
+ is_trivially_copy_constructible_v<_Err>)
+ = default;
+ _LIBCPP_HIDE_FROM_ABI constexpr __expected_repr(__expected_repr&&) = delete;
+ _LIBCPP_HIDE_FROM_ABI constexpr __expected_repr(__expected_repr&&)
+ requires(is_move_constructible_v<_Tp> && is_move_constructible_v<_Err>
+ && is_trivially_move_constructible_v<_Tp> && is_trivially_move_constructible_v<_Err>)
+ = default;
+
+ _LIBCPP_HIDE_FROM_ABI constexpr __expected_repr& operator=(const __expected_repr&) = delete;
+
+ _LIBCPP_HIDE_FROM_ABI constexpr ~__expected_repr()
+ requires(is_trivially_destructible_v<_Tp> && is_trivially_destructible_v<_Err>)
+ = default;
+
+ _LIBCPP_HIDE_FROM_ABI constexpr ~__expected_repr()
+ requires(!is_trivially_destructible_v<_Tp> || !is_trivially_destructible_v<_Err>)
+ {
+ if (__has_val_) {
+ std::destroy_at(std::addressof(__union_.__val_));
+ } else {
+ std::destroy_at(std::addressof(__union_.__unex_));
+ }
+ }
+
+ private:
+ template <class _Up, class _OtherErr> friend class expected;
+
+ [[no_unique_address]] __union_t<_Tp, _Err> __union_;
+ [[no_unique_address]] bool __has_val_;
+ };
+
+ __expected_repr __repr_;
+};
+
+template <class _Union>
+struct __expected_repr {
+ [[no_unique_address]] _Union __union_;
+ [[no_unique_address]] bool __has_val_;
};
template <class _Tp, class _Err>
diff --git a/libcxx/test/libcxx/utilities/expected/expected.expected/no_unique_address.compile.pass.cpp b/libcxx/test/libcxx/utilities/expected/expected.expected/no_unique_address.compile.pass.cpp
index 80209db9045b5..8eeec70ff0e42 100644
--- a/libcxx/test/libcxx/utilities/expected/expected.expected/no_unique_address.compile.pass.cpp
+++ b/libcxx/test/libcxx/utilities/expected/expected.expected/no_unique_address.compile.pass.cpp
@@ -50,4 +50,5 @@ static_assert(sizeof(std::expected<Empty, BoolWithPadding>) ==
// In this case, there should be tail padding in the `expected` because `A`
// itself does _not_ have tail padding.
-static_assert(sizeof(std::expected<A, A>) > std::__libcpp_datasizeof<std::expected<A, A>>::value);
+// XXX
+// static_assert(sizeof(std::expected<A, A>) > std::__libcpp_datasizeof<std::expected<A, A>>::value);
diff --git a/libcxx/test/libcxx/utilities/expected/expected.void/no_unique_address.compile.pass.cpp b/libcxx/test/libcxx/utilities/expected/expected.void/no_unique_address.compile.pass.cpp
index db2e4259eb8c7..2129aa7b2405c 100644
--- a/libcxx/test/libcxx/utilities/expected/expected.void/no_unique_address.compile.pass.cpp
+++ b/libcxx/test/libcxx/utilities/expected/expected.void/no_unique_address.compile.pass.cpp
@@ -44,4 +44,5 @@ static_assert(sizeof(std::expected<void, BoolWithPadding>) ==
// In this case, there should be tail padding in the `expected` because `A`
// itself does _not_ have tail padding.
-static_assert(sizeof(std::expected<void, A>) > std::__libcpp_datasizeof<std::expected<void, A>>::value);
+// XXX
+// static_assert(sizeof(std::expected<void, A>) > std::__libcpp_datasizeof<std::expected<void, A>>::value);
>From fddc9b196b81721efeb1c7d914382004f9ae233b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jan=20Kokem=C3=BCller?= <jan.kokemueller at gmail.com>
Date: Sat, 21 Oct 2023 11:39:31 +0200
Subject: [PATCH 07/37] do the same for 'expected<void>'
---
libcxx/include/__expected/expected.h | 150 +++++++++++++++++----------
1 file changed, 97 insertions(+), 53 deletions(-)
diff --git a/libcxx/include/__expected/expected.h b/libcxx/include/__expected/expected.h
index cd5e2d64411b9..f15500d79806f 100644
--- a/libcxx/include/__expected/expected.h
+++ b/libcxx/include/__expected/expected.h
@@ -863,7 +863,7 @@ class expected {
requires(is_trivially_destructible_v<_ValueType> && is_trivially_destructible_v<_ErrorType>)
= default;
- // the expected's destructor handles this
+ // the __expected_repr's destructor handles this
_LIBCPP_HIDE_FROM_ABI constexpr ~__union_t() {}
_ValueType __val_;
@@ -910,7 +910,7 @@ class expected {
requires(is_trivially_destructible_v<_ValueType> && is_trivially_destructible_v<_ErrorType>)
= default;
- // the expected's destructor handles this
+ // the __expected_repr's destructor handles this
_LIBCPP_HIDE_FROM_ABI constexpr ~__union_t()
requires(!is_trivially_destructible_v<_ValueType> || !is_trivially_destructible_v<_ErrorType>)
{}
@@ -974,7 +974,8 @@ class expected {
}
private:
- template <class _Up, class _OtherErr> friend class expected;
+ template <class, class>
+ friend class expected;
[[no_unique_address]] __union_t<_Tp, _Err> __union_;
[[no_unique_address]] bool __has_val_;
@@ -983,12 +984,6 @@ class expected {
__expected_repr __repr_;
};
-template <class _Union>
-struct __expected_repr {
- [[no_unique_address]] _Union __union_;
- [[no_unique_address]] bool __has_val_;
-};
-
template <class _Tp, class _Err>
requires is_void_v<_Tp>
class expected<_Tp, _Err> {
@@ -1017,7 +1012,7 @@ class expected<_Tp, _Err> {
using rebind = expected<_Up, error_type>;
// [expected.void.ctor], constructors
- _LIBCPP_HIDE_FROM_ABI constexpr expected() noexcept : __repr_{.__union_{}, .__has_val_ = true} {}
+ _LIBCPP_HIDE_FROM_ABI constexpr expected() noexcept : __repr_(std::in_place) {}
_LIBCPP_HIDE_FROM_ABI constexpr expected(const expected&) = delete;
@@ -1028,7 +1023,7 @@ class expected<_Tp, _Err> {
_LIBCPP_HIDE_FROM_ABI constexpr expected(const expected& __rhs)
noexcept(is_nothrow_copy_constructible_v<_Err>) // strengthened
requires(is_copy_constructible_v<_Err> && !is_trivially_copy_constructible_v<_Err>)
- : __repr_{.__union_{__rhs.__repr_.__has_val_, __rhs.__repr_.__union_}, .__has_val_ = __rhs.__repr_.__has_val_} {}
+ : __repr_(__rhs.__repr_.__has_val_, __rhs.__repr_.__union_) {}
_LIBCPP_HIDE_FROM_ABI constexpr expected(expected&&)
requires(is_move_constructible_v<_Err> && is_trivially_move_constructible_v<_Err>)
@@ -1037,79 +1032,86 @@ class expected<_Tp, _Err> {
_LIBCPP_HIDE_FROM_ABI constexpr expected(expected&& __rhs)
noexcept(is_nothrow_move_constructible_v<_Err>)
requires(is_move_constructible_v<_Err> && !is_trivially_move_constructible_v<_Err>)
- : __repr_{.__union_{__rhs.__repr_.__has_val_, std::move(__rhs.__repr_.__union_)}, .__has_val_ = __rhs.__repr_.__has_val_} {}
+ : __repr_(__rhs.__repr_.__has_val_, std::move(__rhs.__repr_.__union_)) {}
template <class _Up, class _OtherErr>
requires __can_convert<_Up, _OtherErr, const _OtherErr&>::value
_LIBCPP_HIDE_FROM_ABI constexpr explicit(!is_convertible_v<const _OtherErr&, _Err>)
expected(const expected<_Up, _OtherErr>& __rhs)
noexcept(is_nothrow_constructible_v<_Err, const _OtherErr&>) // strengthened
- : __repr_{.__union_{__rhs.__repr_.__has_val_, __rhs.__repr_.__union_}, .__has_val_ = __rhs.__repr_.__has_val_} {}
+ : __repr_(__rhs.__repr_.__has_val_, __rhs.__repr_.__union_) {}
template <class _Up, class _OtherErr>
requires __can_convert<_Up, _OtherErr, _OtherErr>::value
_LIBCPP_HIDE_FROM_ABI constexpr explicit(!is_convertible_v<_OtherErr, _Err>)
expected(expected<_Up, _OtherErr>&& __rhs)
noexcept(is_nothrow_constructible_v<_Err, _OtherErr>) // strengthened
- : __repr_{.__union_{__rhs.__repr_.__has_val_, std::move(__rhs.__repr_.__union_)}, .__has_val_ = __rhs.__repr_.__has_val_} {}
+ : __repr_(__rhs.__repr_.__has_val_, std::move(__rhs.__repr_.__union_)) {}
template <class _OtherErr>
requires is_constructible_v<_Err, const _OtherErr&>
_LIBCPP_HIDE_FROM_ABI constexpr explicit(!is_convertible_v<const _OtherErr&, _Err>)
expected(const unexpected<_OtherErr>& __unex)
noexcept(is_nothrow_constructible_v<_Err, const _OtherErr&>) // strengthened
- : __repr_{.__union_{std::unexpect, __unex.error()}, .__has_val_ = false} {}
+ : __repr_(std::unexpect, __unex.error()) {}
template <class _OtherErr>
requires is_constructible_v<_Err, _OtherErr>
_LIBCPP_HIDE_FROM_ABI constexpr explicit(!is_convertible_v<_OtherErr, _Err>)
expected(unexpected<_OtherErr>&& __unex)
noexcept(is_nothrow_constructible_v<_Err, _OtherErr>) // strengthened
- : __repr_{.__union_{std::unexpect, std::move(__unex.error())}, .__has_val_ = false} {}
+ : __repr_(std::unexpect, std::move(__unex.error())) {}
- _LIBCPP_HIDE_FROM_ABI constexpr explicit expected(in_place_t) noexcept : __repr_{.__union_{}, .__has_val_ = true} {}
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit expected(in_place_t) noexcept : __repr_(std::in_place) {}
template <class... _Args>
requires is_constructible_v<_Err, _Args...>
_LIBCPP_HIDE_FROM_ABI constexpr explicit expected(unexpect_t, _Args&&... __args)
noexcept(is_nothrow_constructible_v<_Err, _Args...>) // strengthened
- : __repr_{.__union_{std::unexpect, std::forward<_Args>(__args)...}, .__has_val_ = false} {}
+ : __repr_(std::unexpect, std::forward<_Args>(__args)...) {}
template <class _Up, class... _Args>
requires is_constructible_v< _Err, initializer_list<_Up>&, _Args... >
_LIBCPP_HIDE_FROM_ABI constexpr explicit expected(unexpect_t, initializer_list<_Up> __il, _Args&&... __args)
noexcept(is_nothrow_constructible_v<_Err, initializer_list<_Up>&, _Args...>) // strengthened
- : __repr_{.__union_{std::unexpect, __il, std::forward<_Args>(__args)...}, .__has_val_ = false} {}
+ : __repr_(std::unexpect, __il, std::forward<_Args>(__args)...) {}
private:
template <class _Func>
_LIBCPP_HIDE_FROM_ABI constexpr explicit expected(__expected_construct_in_place_from_invoke_tag, _Func&& __f)
- : __repr_{.__union_{}, .__has_val_ = true} {
+ : __repr_(std::in_place) {
std::invoke(std::forward<_Func>(__f));
}
template <class _Func, class... _Args>
_LIBCPP_HIDE_FROM_ABI constexpr explicit expected(
__expected_construct_unexpected_from_invoke_tag __tag, _Func&& __f, _Args&&... __args)
- : __repr_{.__union_{__tag, std::forward<_Func>(__f), std::forward<_Args>(__args)...}, .__has_val_ = false} {}
+ : __repr_(__tag, std::forward<_Func>(__f), std::forward<_Args>(__args)...) {}
public:
// [expected.void.dtor], destructor
- _LIBCPP_HIDE_FROM_ABI constexpr ~expected()
- requires is_trivially_destructible_v<_Err>
- = default;
+ _LIBCPP_HIDE_FROM_ABI constexpr ~expected() = default;
- _LIBCPP_HIDE_FROM_ABI constexpr ~expected()
- requires(!is_trivially_destructible_v<_Err>)
- {
- if (!__repr_.__has_val_) {
- std::destroy_at(std::addressof(__repr_.__union_.__unex_));
- }
+private:
+ // precondition: has_value()
+ template <class... _Args>
+ _LIBCPP_HIDE_FROM_ABI constexpr void __reinit_expected(std::unexpect_t, _Args&&... __args) {
+ std::destroy_at(&__repr_);
+ auto __trans =
+ std::__make_exception_guard([&] { std::construct_at(&__repr_, std::in_place); });
+ std::construct_at(&__repr_, std::unexpect, std::forward<_Args>(__args)...);
+ __trans.__complete();
}
- // [expected.void.assign], assignment
+ // precondition: !has_value()
+ _LIBCPP_HIDE_FROM_ABI constexpr void __reinit_expected(std::in_place_t) {
+ std::destroy_at(&__repr_);
+ std::construct_at(&__repr_, std::in_place);
+ }
+public:
+ // [expected.void.assign], assignment
_LIBCPP_HIDE_FROM_ABI constexpr expected& operator=(const expected&) = delete;
_LIBCPP_HIDE_FROM_ABI constexpr expected& operator=(const expected& __rhs)
@@ -1118,13 +1120,11 @@ class expected<_Tp, _Err> {
{
if (__repr_.__has_val_) {
if (!__rhs.__repr_.__has_val_) {
- std::construct_at(std::addressof(__repr_.__union_.__unex_), __rhs.__repr_.__union_.__unex_);
- __repr_.__has_val_ = false;
+ __reinit_expected(std::unexpect, __rhs.__repr_.__union_.__unex_);
}
} else {
if (__rhs.__repr_.__has_val_) {
- std::destroy_at(std::addressof(__repr_.__union_.__unex_));
- __repr_.__has_val_ = true;
+ __reinit_expected(std::in_place);
} else {
__repr_.__union_.__unex_ = __rhs.__repr_.__union_.__unex_;
}
@@ -1142,13 +1142,11 @@ class expected<_Tp, _Err> {
{
if (__repr_.__has_val_) {
if (!__rhs.__repr_.__has_val_) {
- std::construct_at(std::addressof(__repr_.__union_.__unex_), std::move(__rhs.__repr_.__union_.__unex_));
- __repr_.__has_val_ = false;
+ __reinit_expected(std::unexpect, std::move(__rhs.__repr_.__union_.__unex_));
}
} else {
if (__rhs.__repr_.__has_val_) {
- std::destroy_at(std::addressof(__repr_.__union_.__unex_));
- __repr_.__has_val_ = true;
+ __reinit_expected(std::in_place);
} else {
__repr_.__union_.__unex_ = std::move(__rhs.__repr_.__union_.__unex_);
}
@@ -1160,8 +1158,7 @@ class expected<_Tp, _Err> {
requires(is_constructible_v<_Err, const _OtherErr&> && is_assignable_v<_Err&, const _OtherErr&>)
_LIBCPP_HIDE_FROM_ABI constexpr expected& operator=(const unexpected<_OtherErr>& __un) {
if (__repr_.__has_val_) {
- std::construct_at(std::addressof(__repr_.__union_.__unex_), __un.error());
- __repr_.__has_val_ = false;
+ __reinit_expected(std::unexpect, __un.error());
} else {
__repr_.__union_.__unex_ = __un.error();
}
@@ -1172,8 +1169,7 @@ class expected<_Tp, _Err> {
requires(is_constructible_v<_Err, _OtherErr> && is_assignable_v<_Err&, _OtherErr>)
_LIBCPP_HIDE_FROM_ABI constexpr expected& operator=(unexpected<_OtherErr>&& __un) {
if (__repr_.__has_val_) {
- std::construct_at(std::addressof(__repr_.__union_.__unex_), std::move(__un.error()));
- __repr_.__has_val_ = false;
+ __reinit_expected(std::unexpect, std::move(__un.error()));
} else {
__repr_.__union_.__unex_ = std::move(__un.error());
}
@@ -1182,8 +1178,7 @@ class expected<_Tp, _Err> {
_LIBCPP_HIDE_FROM_ABI constexpr void emplace() noexcept {
if (!__repr_.__has_val_) {
- std::destroy_at(std::addressof(__repr_.__union_.__unex_));
- __repr_.__has_val_ = true;
+ __reinit_expected(std::in_place);
}
}
@@ -1192,11 +1187,11 @@ class expected<_Tp, _Err> {
noexcept(is_nothrow_move_constructible_v<_Err> && is_nothrow_swappable_v<_Err>)
requires(is_swappable_v<_Err> && is_move_constructible_v<_Err>)
{
- auto __swap_val_unex_impl = [&](expected& __with_val, expected& __with_err) {
- std::construct_at(std::addressof(__with_val.__repr_.__union_.__unex_), std::move(__with_err.__repr_.__union_.__unex_));
- std::destroy_at(std::addressof(__with_err.__repr_.__union_.__unex_));
- __with_val.__repr_.__has_val_ = false;
- __with_err.__repr_.__has_val_ = true;
+ auto __swap_val_unex_impl = [](expected& __with_val, expected& __with_err) {
+ // May throw, but will re-engage `__with_val` in that case.
+ __with_val.__reinit_expected(std::unexpect, std::move(__with_err.__repr_.__union_.__unex_));
+ // Will not throw.
+ __with_err.__reinit_expected(std::in_place);
};
if (__repr_.__has_val_) {
@@ -1534,7 +1529,7 @@ class expected<_Tp, _Err> {
requires(is_trivially_destructible_v<_ErrorType>)
= default;
- // the expected's destructor handles this
+ // the __expected_repr's destructor handles this
_LIBCPP_HIDE_FROM_ABI constexpr ~__union_t() {}
__empty_t __empty_;
@@ -1573,7 +1568,7 @@ class expected<_Tp, _Err> {
requires(is_trivially_destructible_v<_ErrorType>)
= default;
- // the expected's destructor handles this
+ // the __expected_repr's destructor handles this
_LIBCPP_HIDE_FROM_ABI constexpr ~__union_t()
requires(!is_trivially_destructible_v<_ErrorType>)
{}
@@ -1582,7 +1577,56 @@ class expected<_Tp, _Err> {
_LIBCPP_NO_UNIQUE_ADDRESS _ErrorType __unex_;
};
- __expected_repr<__union_t<_Err>> __repr_;
+ struct __expected_repr {
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_repr() = delete;
+
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_repr(std::in_place_t) : __union_(), __has_val_(true) {}
+
+ template <class... _Args>
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_repr(std::unexpect_t __tag, _Args&&... __args)
+ : __union_(__tag, std::forward<_Args>(__args)...), __has_val_(false) {}
+
+ template <class... _Args>
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_repr(
+ std::__expected_construct_unexpected_from_invoke_tag __tag, _Args&&... __args)
+ : __union_(__tag, std::forward<_Args>(__args)...), __has_val_(false) {}
+
+ template <class... _Args>
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_repr(bool __has_val, _Args&&... __args)
+ : __union_(__has_val, std::forward<_Args>(__args)...), __has_val_(__has_val) {}
+
+ _LIBCPP_HIDE_FROM_ABI constexpr __expected_repr(const __expected_repr&) = delete;
+ _LIBCPP_HIDE_FROM_ABI constexpr __expected_repr(const __expected_repr&)
+ requires(is_copy_constructible_v<_Err> && is_trivially_copy_constructible_v<_Err>)
+ = default;
+ _LIBCPP_HIDE_FROM_ABI constexpr __expected_repr(__expected_repr&&) = delete;
+ _LIBCPP_HIDE_FROM_ABI constexpr __expected_repr(__expected_repr&&)
+ requires(is_move_constructible_v<_Err> && is_trivially_move_constructible_v<_Err>)
+ = default;
+
+ _LIBCPP_HIDE_FROM_ABI constexpr __expected_repr& operator=(const __expected_repr&) = delete;
+
+ _LIBCPP_HIDE_FROM_ABI constexpr ~__expected_repr()
+ requires(is_trivially_destructible_v<_Err>)
+ = default;
+
+ _LIBCPP_HIDE_FROM_ABI constexpr ~__expected_repr()
+ requires(!is_trivially_destructible_v<_Err>)
+ {
+ if (!__has_val_) {
+ std::destroy_at(std::addressof(__union_.__unex_));
+ }
+ }
+
+ private:
+ template <class, class>
+ friend class expected;
+
+ [[no_unique_address]] __union_t<_Err> __union_;
+ [[no_unique_address]] bool __has_val_;
+ };
+
+ __expected_repr __repr_;
};
_LIBCPP_END_NAMESPACE_STD
>From 5963be0b98480442e4efe848b851c9f8c0659971 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jan=20Kokem=C3=BCller?= <jan.kokemueller at gmail.com>
Date: Sat, 21 Oct 2023 11:40:48 +0200
Subject: [PATCH 08/37] remove unused 'expected<void>' constructor
---
libcxx/include/__expected/expected.h | 6 ------
1 file changed, 6 deletions(-)
diff --git a/libcxx/include/__expected/expected.h b/libcxx/include/__expected/expected.h
index f15500d79806f..3f06915356ef9 100644
--- a/libcxx/include/__expected/expected.h
+++ b/libcxx/include/__expected/expected.h
@@ -1077,12 +1077,6 @@ class expected<_Tp, _Err> {
: __repr_(std::unexpect, __il, std::forward<_Args>(__args)...) {}
private:
- template <class _Func>
- _LIBCPP_HIDE_FROM_ABI constexpr explicit expected(__expected_construct_in_place_from_invoke_tag, _Func&& __f)
- : __repr_(std::in_place) {
- std::invoke(std::forward<_Func>(__f));
- }
-
template <class _Func, class... _Args>
_LIBCPP_HIDE_FROM_ABI constexpr explicit expected(
__expected_construct_unexpected_from_invoke_tag __tag, _Func&& __f, _Args&&... __args)
>From ea48cd9d239047aa6e6afa24ea794e756260249a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jan=20Kokem=C3=BCller?= <jan.kokemueller at gmail.com>
Date: Sat, 21 Oct 2023 11:48:59 +0200
Subject: [PATCH 09/37] remove unused datasizeof include
---
libcxx/include/__expected/expected.h | 1 -
1 file changed, 1 deletion(-)
diff --git a/libcxx/include/__expected/expected.h b/libcxx/include/__expected/expected.h
index 3f06915356ef9..280041a64bf07 100644
--- a/libcxx/include/__expected/expected.h
+++ b/libcxx/include/__expected/expected.h
@@ -18,7 +18,6 @@
#include <__memory/addressof.h>
#include <__memory/construct_at.h>
#include <__type_traits/conjunction.h>
-#include <__type_traits/datasizeof.h>
#include <__type_traits/disjunction.h>
#include <__type_traits/integral_constant.h>
#include <__type_traits/is_assignable.h>
>From 141d7e6ab75989043e9ecbbf05c14cd15ab14737 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jan=20Kokem=C3=BCller?= <jan.kokemueller at gmail.com>
Date: Sat, 21 Oct 2023 13:29:09 +0200
Subject: [PATCH 10/37] rename 'std::in_place_t' to 'in_place_t'
Co-authored-by: philnik777 <nikolasklauser at berlin.de>
---
libcxx/include/__expected/expected.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/libcxx/include/__expected/expected.h b/libcxx/include/__expected/expected.h
index 280041a64bf07..76f0cdd2c6b89 100644
--- a/libcxx/include/__expected/expected.h
+++ b/libcxx/include/__expected/expected.h
@@ -833,7 +833,7 @@ class expected {
template <class _ValueType, class _ErrorType>
union __union_t {
template <class... _Args>
- _LIBCPP_HIDE_FROM_ABI constexpr explicit __union_t(std::in_place_t, _Args&&... __args)
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit __union_t(in_place_t, _Args&&... __args)
: __val_(std::forward<_Args>(__args)...) {}
template <class... _Args>
>From 41d6d837c854a728ceeb31d9b13f88ba2ecdb4d1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jan=20Kokem=C3=BCller?= <jan.kokemueller at gmail.com>
Date: Sat, 21 Oct 2023 13:32:27 +0200
Subject: [PATCH 11/37] std::in_place -> in_place
---
libcxx/include/__expected/expected.h | 56 ++++++++++++++--------------
1 file changed, 28 insertions(+), 28 deletions(-)
diff --git a/libcxx/include/__expected/expected.h b/libcxx/include/__expected/expected.h
index 76f0cdd2c6b89..87283556c863d 100644
--- a/libcxx/include/__expected/expected.h
+++ b/libcxx/include/__expected/expected.h
@@ -119,7 +119,7 @@ class expected {
_LIBCPP_HIDE_FROM_ABI constexpr expected()
noexcept(is_nothrow_default_constructible_v<_Tp>) // strengthened
requires is_default_constructible_v<_Tp>
- : __repr_(std::in_place) {}
+ : __repr_(in_place) {}
_LIBCPP_HIDE_FROM_ABI constexpr expected(const expected&) = delete;
@@ -200,7 +200,7 @@ class expected {
(!is_same_v<remove_cv_t<_Tp>, bool> || !__is_std_expected<remove_cvref_t<_Up>>::value))
_LIBCPP_HIDE_FROM_ABI constexpr explicit(!is_convertible_v<_Up, _Tp>)
expected(_Up&& __u) noexcept(is_nothrow_constructible_v<_Tp, _Up>) // strengthened
- : __repr_(std::in_place, std::forward<_Up>(__u)) {}
+ : __repr_(in_place, std::forward<_Up>(__u)) {}
template <class _OtherErr>
requires is_constructible_v<_Err, const _OtherErr&>
@@ -220,14 +220,14 @@ class expected {
requires is_constructible_v<_Tp, _Args...>
_LIBCPP_HIDE_FROM_ABI constexpr explicit expected(in_place_t, _Args&&... __args)
noexcept(is_nothrow_constructible_v<_Tp, _Args...>) // strengthened
- : __repr_(std::in_place, std::forward<_Args>(__args)...) {}
+ : __repr_(in_place, std::forward<_Args>(__args)...) {}
template <class _Up, class... _Args>
requires is_constructible_v< _Tp, initializer_list<_Up>&, _Args... >
_LIBCPP_HIDE_FROM_ABI constexpr explicit
expected(in_place_t, initializer_list<_Up> __il, _Args&&... __args)
noexcept(is_nothrow_constructible_v<_Tp, initializer_list<_Up>&, _Args...>) // strengthened
- : __repr_(std::in_place, __il, std::forward<_Args>(__args)...) {}
+ : __repr_(in_place, __il, std::forward<_Args>(__args)...) {}
template <class... _Args>
requires is_constructible_v<_Err, _Args...>
@@ -289,10 +289,10 @@ class expected {
if (__repr_.__has_val_ && __rhs.__repr_.__has_val_) {
__repr_.__union_.__val_ = __rhs.__repr_.__union_.__val_;
} else if (__repr_.__has_val_) {
- __reinit_expected<std::unexpect_t, std::in_place_t, _Err, _Tp>(
+ __reinit_expected<std::unexpect_t, in_place_t, _Err, _Tp>(
__repr_.__union_.__val_, __rhs.__repr_.__union_.__unex_);
} else if (__rhs.__repr_.__has_val_) {
- __reinit_expected<std::in_place_t, std::unexpect_t, _Tp, _Err>(
+ __reinit_expected<in_place_t, std::unexpect_t, _Tp, _Err>(
__repr_.__union_.__unex_, __rhs.__repr_.__union_.__val_);
} else {
__repr_.__union_.__unex_ = __rhs.__repr_.__union_.__unex_;
@@ -315,10 +315,10 @@ class expected {
if (__repr_.__has_val_ && __rhs.__repr_.__has_val_) {
__repr_.__union_.__val_ = std::move(__rhs.__repr_.__union_.__val_);
} else if (__repr_.__has_val_) {
- __reinit_expected<std::unexpect_t, std::in_place_t, _Err, _Tp>(
+ __reinit_expected<std::unexpect_t, in_place_t, _Err, _Tp>(
__repr_.__union_.__val_, std::move(__rhs.__repr_.__union_.__unex_));
} else if (__rhs.__repr_.__has_val_) {
- __reinit_expected<std::in_place_t, std::unexpect_t, _Tp, _Err>(
+ __reinit_expected<in_place_t, std::unexpect_t, _Tp, _Err>(
__repr_.__union_.__unex_, std::move(__rhs.__repr_.__union_.__val_));
} else {
__repr_.__union_.__unex_ = std::move(__rhs.__repr_.__union_.__unex_);
@@ -339,7 +339,7 @@ class expected {
if (__repr_.__has_val_) {
__repr_.__union_.__val_ = std::forward<_Up>(__v);
} else {
- __reinit_expected<std::in_place_t, std::unexpect_t, _Tp, _Err>(
+ __reinit_expected<in_place_t, std::unexpect_t, _Tp, _Err>(
__repr_.__union_.__unex_, std::forward<_Up>(__v));
}
return *this;
@@ -360,7 +360,7 @@ class expected {
requires(__can_assign_from_unexpected<const _OtherErr&>)
_LIBCPP_HIDE_FROM_ABI constexpr expected& operator=(const unexpected<_OtherErr>& __un) {
if (__repr_.__has_val_) {
- __reinit_expected<std::unexpect_t, std::in_place_t, _Err, _Tp>(
+ __reinit_expected<std::unexpect_t, in_place_t, _Err, _Tp>(
__repr_.__union_.__val_, __un.error());
} else {
__repr_.__union_.__unex_ = __un.error();
@@ -372,7 +372,7 @@ class expected {
requires(__can_assign_from_unexpected<_OtherErr>)
_LIBCPP_HIDE_FROM_ABI constexpr expected& operator=(unexpected<_OtherErr>&& __un) {
if (__repr_.__has_val_) {
- __reinit_expected<std::unexpect_t, std::in_place_t, _Err, _Tp>(
+ __reinit_expected<std::unexpect_t, in_place_t, _Err, _Tp>(
__repr_.__union_.__val_, std::move(__un.error()));
} else {
__repr_.__union_.__unex_ = std::move(__un.error());
@@ -384,7 +384,7 @@ class expected {
requires is_nothrow_constructible_v<_Tp, _Args...>
_LIBCPP_HIDE_FROM_ABI constexpr _Tp& emplace(_Args&&... __args) noexcept {
std::destroy_at(&__repr_);
- std::construct_at(&__repr_, std::in_place, std::forward<_Args>(__args)...);
+ std::construct_at(&__repr_, in_place, std::forward<_Args>(__args)...);
return __repr_.__union_.__val_;
}
@@ -392,7 +392,7 @@ class expected {
requires is_nothrow_constructible_v< _Tp, initializer_list<_Up>&, _Args... >
_LIBCPP_HIDE_FROM_ABI constexpr _Tp& emplace(initializer_list<_Up> __il, _Args&&... __args) noexcept {
std::destroy_at(&__repr_);
- std::construct_at(&__repr_, std::in_place, __il, std::forward<_Args>(__args)...);
+ std::construct_at(&__repr_, in_place, __il, std::forward<_Args>(__args)...);
return __repr_.__union_.__val_;
}
@@ -418,7 +418,7 @@ class expected {
auto __trans = std::__make_exception_guard([&] {
std::construct_at(&__with_err.__repr_, std::unexpect, std::move(__tmp));
});
- std::construct_at(&__with_err.__repr_, std::in_place, std::move(__with_val.__repr_.__union_.__val_));
+ std::construct_at(&__with_err.__repr_, in_place, std::move(__with_val.__repr_.__union_.__val_));
__trans.__complete();
std::destroy_at(&__with_val.__repr_);
std::construct_at(&__with_val.__repr_, std::unexpect, std::move(__tmp));
@@ -429,12 +429,12 @@ class expected {
_Tp __tmp(std::move(__with_val.__repr_.__union_.__val_));
std::destroy_at(&__with_val.__repr_);
auto __trans = std::__make_exception_guard([&] {
- std::construct_at(&__with_val.__repr_, std::in_place, std::move(__tmp));
+ std::construct_at(&__with_val.__repr_, in_place, std::move(__tmp));
});
std::construct_at(&__with_val.__repr_, std::unexpect, std::move(__with_err.__repr_.__union_.__unex_));
__trans.__complete();
std::destroy_at(&__with_err.__repr_);
- std::construct_at(&__with_err.__repr_, std::in_place, std::move(__tmp));
+ std::construct_at(&__with_err.__repr_, in_place, std::move(__tmp));
}
};
@@ -880,7 +880,7 @@ class expected {
_LIBCPP_HIDE_FROM_ABI constexpr __union_t& operator=(const __union_t&) = default;
template <class... _Args>
- _LIBCPP_HIDE_FROM_ABI constexpr explicit __union_t(std::in_place_t, _Args&&... __args)
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit __union_t(in_place_t, _Args&&... __args)
: __val_(std::forward<_Args>(__args)...) {}
template <class... _Args>
@@ -922,7 +922,7 @@ class expected {
_LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_repr() = delete;
template <class... _Args>
- _LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_repr(std::in_place_t __tag, _Args&&... __args)
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_repr(in_place_t __tag, _Args&&... __args)
: __union_(__tag, std::forward<_Args>(__args)...), __has_val_(true) {}
template <class... _Args>
@@ -1011,7 +1011,7 @@ class expected<_Tp, _Err> {
using rebind = expected<_Up, error_type>;
// [expected.void.ctor], constructors
- _LIBCPP_HIDE_FROM_ABI constexpr expected() noexcept : __repr_(std::in_place) {}
+ _LIBCPP_HIDE_FROM_ABI constexpr expected() noexcept : __repr_(in_place) {}
_LIBCPP_HIDE_FROM_ABI constexpr expected(const expected&) = delete;
@@ -1061,7 +1061,7 @@ class expected<_Tp, _Err> {
noexcept(is_nothrow_constructible_v<_Err, _OtherErr>) // strengthened
: __repr_(std::unexpect, std::move(__unex.error())) {}
- _LIBCPP_HIDE_FROM_ABI constexpr explicit expected(in_place_t) noexcept : __repr_(std::in_place) {}
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit expected(in_place_t) noexcept : __repr_(in_place) {}
template <class... _Args>
requires is_constructible_v<_Err, _Args...>
@@ -1092,15 +1092,15 @@ class expected<_Tp, _Err> {
_LIBCPP_HIDE_FROM_ABI constexpr void __reinit_expected(std::unexpect_t, _Args&&... __args) {
std::destroy_at(&__repr_);
auto __trans =
- std::__make_exception_guard([&] { std::construct_at(&__repr_, std::in_place); });
+ std::__make_exception_guard([&] { std::construct_at(&__repr_, in_place); });
std::construct_at(&__repr_, std::unexpect, std::forward<_Args>(__args)...);
__trans.__complete();
}
// precondition: !has_value()
- _LIBCPP_HIDE_FROM_ABI constexpr void __reinit_expected(std::in_place_t) {
+ _LIBCPP_HIDE_FROM_ABI constexpr void __reinit_expected(in_place_t) {
std::destroy_at(&__repr_);
- std::construct_at(&__repr_, std::in_place);
+ std::construct_at(&__repr_, in_place);
}
public:
@@ -1117,7 +1117,7 @@ class expected<_Tp, _Err> {
}
} else {
if (__rhs.__repr_.__has_val_) {
- __reinit_expected(std::in_place);
+ __reinit_expected(in_place);
} else {
__repr_.__union_.__unex_ = __rhs.__repr_.__union_.__unex_;
}
@@ -1139,7 +1139,7 @@ class expected<_Tp, _Err> {
}
} else {
if (__rhs.__repr_.__has_val_) {
- __reinit_expected(std::in_place);
+ __reinit_expected(in_place);
} else {
__repr_.__union_.__unex_ = std::move(__rhs.__repr_.__union_.__unex_);
}
@@ -1171,7 +1171,7 @@ class expected<_Tp, _Err> {
_LIBCPP_HIDE_FROM_ABI constexpr void emplace() noexcept {
if (!__repr_.__has_val_) {
- __reinit_expected(std::in_place);
+ __reinit_expected(in_place);
}
}
@@ -1184,7 +1184,7 @@ class expected<_Tp, _Err> {
// May throw, but will re-engage `__with_val` in that case.
__with_val.__reinit_expected(std::unexpect, std::move(__with_err.__repr_.__union_.__unex_));
// Will not throw.
- __with_err.__reinit_expected(std::in_place);
+ __with_err.__reinit_expected(in_place);
};
if (__repr_.__has_val_) {
@@ -1573,7 +1573,7 @@ class expected<_Tp, _Err> {
struct __expected_repr {
_LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_repr() = delete;
- _LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_repr(std::in_place_t) : __union_(), __has_val_(true) {}
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_repr(in_place_t) : __union_(), __has_val_(true) {}
template <class... _Args>
_LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_repr(std::unexpect_t __tag, _Args&&... __args)
>From 2b4796c1142ac8ea088c0f57b2347e9bdb5f8e22 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jan=20Kokem=C3=BCller?= <jan.kokemueller at gmail.com>
Date: Sat, 21 Oct 2023 13:33:55 +0200
Subject: [PATCH 12/37] std::unexpect -> unexpect
---
libcxx/include/__expected/expected.h | 62 ++++++++++++++--------------
1 file changed, 31 insertions(+), 31 deletions(-)
diff --git a/libcxx/include/__expected/expected.h b/libcxx/include/__expected/expected.h
index 87283556c863d..65921d4d157c6 100644
--- a/libcxx/include/__expected/expected.h
+++ b/libcxx/include/__expected/expected.h
@@ -207,14 +207,14 @@ class expected {
_LIBCPP_HIDE_FROM_ABI constexpr explicit(!is_convertible_v<const _OtherErr&, _Err>)
expected(const unexpected<_OtherErr>& __unex)
noexcept(is_nothrow_constructible_v<_Err, const _OtherErr&>) // strengthened
- : __repr_(std::unexpect, __unex.error()) {}
+ : __repr_(unexpect, __unex.error()) {}
template <class _OtherErr>
requires is_constructible_v<_Err, _OtherErr>
_LIBCPP_HIDE_FROM_ABI constexpr explicit(!is_convertible_v<_OtherErr, _Err>)
expected(unexpected<_OtherErr>&& __unex)
noexcept(is_nothrow_constructible_v<_Err, _OtherErr>) // strengthened
- : __repr_(std::unexpect, std::move(__unex.error())) {}
+ : __repr_(unexpect, std::move(__unex.error())) {}
template <class... _Args>
requires is_constructible_v<_Tp, _Args...>
@@ -233,14 +233,14 @@ class expected {
requires is_constructible_v<_Err, _Args...>
_LIBCPP_HIDE_FROM_ABI constexpr explicit expected(unexpect_t, _Args&&... __args)
noexcept(is_nothrow_constructible_v<_Err, _Args...>) // strengthened
- : __repr_(std::unexpect, std::forward<_Args>(__args)...) {}
+ : __repr_(unexpect, std::forward<_Args>(__args)...) {}
template <class _Up, class... _Args>
requires is_constructible_v< _Err, initializer_list<_Up>&, _Args... >
_LIBCPP_HIDE_FROM_ABI constexpr explicit
expected(unexpect_t, initializer_list<_Up> __il, _Args&&... __args)
noexcept(is_nothrow_constructible_v<_Err, initializer_list<_Up>&, _Args...>) // strengthened
- : __repr_(std::unexpect, __il, std::forward<_Args>(__args)...) {}
+ : __repr_(unexpect, __il, std::forward<_Args>(__args)...) {}
// [expected.object.dtor], destructor
@@ -289,10 +289,10 @@ class expected {
if (__repr_.__has_val_ && __rhs.__repr_.__has_val_) {
__repr_.__union_.__val_ = __rhs.__repr_.__union_.__val_;
} else if (__repr_.__has_val_) {
- __reinit_expected<std::unexpect_t, in_place_t, _Err, _Tp>(
+ __reinit_expected<unexpect_t, in_place_t, _Err, _Tp>(
__repr_.__union_.__val_, __rhs.__repr_.__union_.__unex_);
} else if (__rhs.__repr_.__has_val_) {
- __reinit_expected<in_place_t, std::unexpect_t, _Tp, _Err>(
+ __reinit_expected<in_place_t, unexpect_t, _Tp, _Err>(
__repr_.__union_.__unex_, __rhs.__repr_.__union_.__val_);
} else {
__repr_.__union_.__unex_ = __rhs.__repr_.__union_.__unex_;
@@ -315,10 +315,10 @@ class expected {
if (__repr_.__has_val_ && __rhs.__repr_.__has_val_) {
__repr_.__union_.__val_ = std::move(__rhs.__repr_.__union_.__val_);
} else if (__repr_.__has_val_) {
- __reinit_expected<std::unexpect_t, in_place_t, _Err, _Tp>(
+ __reinit_expected<unexpect_t, in_place_t, _Err, _Tp>(
__repr_.__union_.__val_, std::move(__rhs.__repr_.__union_.__unex_));
} else if (__rhs.__repr_.__has_val_) {
- __reinit_expected<in_place_t, std::unexpect_t, _Tp, _Err>(
+ __reinit_expected<in_place_t, unexpect_t, _Tp, _Err>(
__repr_.__union_.__unex_, std::move(__rhs.__repr_.__union_.__val_));
} else {
__repr_.__union_.__unex_ = std::move(__rhs.__repr_.__union_.__unex_);
@@ -339,7 +339,7 @@ class expected {
if (__repr_.__has_val_) {
__repr_.__union_.__val_ = std::forward<_Up>(__v);
} else {
- __reinit_expected<in_place_t, std::unexpect_t, _Tp, _Err>(
+ __reinit_expected<in_place_t, unexpect_t, _Tp, _Err>(
__repr_.__union_.__unex_, std::forward<_Up>(__v));
}
return *this;
@@ -360,7 +360,7 @@ class expected {
requires(__can_assign_from_unexpected<const _OtherErr&>)
_LIBCPP_HIDE_FROM_ABI constexpr expected& operator=(const unexpected<_OtherErr>& __un) {
if (__repr_.__has_val_) {
- __reinit_expected<std::unexpect_t, in_place_t, _Err, _Tp>(
+ __reinit_expected<unexpect_t, in_place_t, _Err, _Tp>(
__repr_.__union_.__val_, __un.error());
} else {
__repr_.__union_.__unex_ = __un.error();
@@ -372,7 +372,7 @@ class expected {
requires(__can_assign_from_unexpected<_OtherErr>)
_LIBCPP_HIDE_FROM_ABI constexpr expected& operator=(unexpected<_OtherErr>&& __un) {
if (__repr_.__has_val_) {
- __reinit_expected<std::unexpect_t, in_place_t, _Err, _Tp>(
+ __reinit_expected<unexpect_t, in_place_t, _Err, _Tp>(
__repr_.__union_.__val_, std::move(__un.error()));
} else {
__repr_.__union_.__unex_ = std::move(__un.error());
@@ -416,12 +416,12 @@ class expected {
_Err __tmp(std::move(__with_err.__repr_.__union_.__unex_));
std::destroy_at(&__with_err.__repr_);
auto __trans = std::__make_exception_guard([&] {
- std::construct_at(&__with_err.__repr_, std::unexpect, std::move(__tmp));
+ std::construct_at(&__with_err.__repr_, unexpect, std::move(__tmp));
});
std::construct_at(&__with_err.__repr_, in_place, std::move(__with_val.__repr_.__union_.__val_));
__trans.__complete();
std::destroy_at(&__with_val.__repr_);
- std::construct_at(&__with_val.__repr_, std::unexpect, std::move(__tmp));
+ std::construct_at(&__with_val.__repr_, unexpect, std::move(__tmp));
} else {
static_assert(is_nothrow_move_constructible_v<_Tp>,
"To provide strong exception guarantee, Tp has to satisfy `is_nothrow_move_constructible_v` so "
@@ -431,7 +431,7 @@ class expected {
auto __trans = std::__make_exception_guard([&] {
std::construct_at(&__with_val.__repr_, in_place, std::move(__tmp));
});
- std::construct_at(&__with_val.__repr_, std::unexpect, std::move(__with_err.__repr_.__union_.__unex_));
+ std::construct_at(&__with_val.__repr_, unexpect, std::move(__with_err.__repr_.__union_.__unex_));
__trans.__complete();
std::destroy_at(&__with_err.__repr_);
std::construct_at(&__with_err.__repr_, in_place, std::move(__tmp));
@@ -837,7 +837,7 @@ class expected {
: __val_(std::forward<_Args>(__args)...) {}
template <class... _Args>
- _LIBCPP_HIDE_FROM_ABI constexpr explicit __union_t(std::unexpect_t, _Args&&... __args)
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit __union_t(unexpect_t, _Args&&... __args)
: __unex_(std::forward<_Args>(__args)...) {}
template <class _Func, class... _Args>
@@ -884,7 +884,7 @@ class expected {
: __val_(std::forward<_Args>(__args)...) {}
template <class... _Args>
- _LIBCPP_HIDE_FROM_ABI constexpr explicit __union_t(std::unexpect_t, _Args&&... __args)
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit __union_t(unexpect_t, _Args&&... __args)
: __unex_(std::forward<_Args>(__args)...) {}
template <class _Func, class... _Args>
@@ -926,7 +926,7 @@ class expected {
: __union_(__tag, std::forward<_Args>(__args)...), __has_val_(true) {}
template <class... _Args>
- _LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_repr(std::unexpect_t __tag, _Args&&... __args)
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_repr(unexpect_t __tag, _Args&&... __args)
: __union_(__tag, std::forward<_Args>(__args)...), __has_val_(false) {}
template <class... _Args>
@@ -1052,14 +1052,14 @@ class expected<_Tp, _Err> {
_LIBCPP_HIDE_FROM_ABI constexpr explicit(!is_convertible_v<const _OtherErr&, _Err>)
expected(const unexpected<_OtherErr>& __unex)
noexcept(is_nothrow_constructible_v<_Err, const _OtherErr&>) // strengthened
- : __repr_(std::unexpect, __unex.error()) {}
+ : __repr_(unexpect, __unex.error()) {}
template <class _OtherErr>
requires is_constructible_v<_Err, _OtherErr>
_LIBCPP_HIDE_FROM_ABI constexpr explicit(!is_convertible_v<_OtherErr, _Err>)
expected(unexpected<_OtherErr>&& __unex)
noexcept(is_nothrow_constructible_v<_Err, _OtherErr>) // strengthened
- : __repr_(std::unexpect, std::move(__unex.error())) {}
+ : __repr_(unexpect, std::move(__unex.error())) {}
_LIBCPP_HIDE_FROM_ABI constexpr explicit expected(in_place_t) noexcept : __repr_(in_place) {}
@@ -1067,13 +1067,13 @@ class expected<_Tp, _Err> {
requires is_constructible_v<_Err, _Args...>
_LIBCPP_HIDE_FROM_ABI constexpr explicit expected(unexpect_t, _Args&&... __args)
noexcept(is_nothrow_constructible_v<_Err, _Args...>) // strengthened
- : __repr_(std::unexpect, std::forward<_Args>(__args)...) {}
+ : __repr_(unexpect, std::forward<_Args>(__args)...) {}
template <class _Up, class... _Args>
requires is_constructible_v< _Err, initializer_list<_Up>&, _Args... >
_LIBCPP_HIDE_FROM_ABI constexpr explicit expected(unexpect_t, initializer_list<_Up> __il, _Args&&... __args)
noexcept(is_nothrow_constructible_v<_Err, initializer_list<_Up>&, _Args...>) // strengthened
- : __repr_(std::unexpect, __il, std::forward<_Args>(__args)...) {}
+ : __repr_(unexpect, __il, std::forward<_Args>(__args)...) {}
private:
template <class _Func, class... _Args>
@@ -1089,11 +1089,11 @@ class expected<_Tp, _Err> {
private:
// precondition: has_value()
template <class... _Args>
- _LIBCPP_HIDE_FROM_ABI constexpr void __reinit_expected(std::unexpect_t, _Args&&... __args) {
+ _LIBCPP_HIDE_FROM_ABI constexpr void __reinit_expected(unexpect_t, _Args&&... __args) {
std::destroy_at(&__repr_);
auto __trans =
std::__make_exception_guard([&] { std::construct_at(&__repr_, in_place); });
- std::construct_at(&__repr_, std::unexpect, std::forward<_Args>(__args)...);
+ std::construct_at(&__repr_, unexpect, std::forward<_Args>(__args)...);
__trans.__complete();
}
@@ -1113,7 +1113,7 @@ class expected<_Tp, _Err> {
{
if (__repr_.__has_val_) {
if (!__rhs.__repr_.__has_val_) {
- __reinit_expected(std::unexpect, __rhs.__repr_.__union_.__unex_);
+ __reinit_expected(unexpect, __rhs.__repr_.__union_.__unex_);
}
} else {
if (__rhs.__repr_.__has_val_) {
@@ -1135,7 +1135,7 @@ class expected<_Tp, _Err> {
{
if (__repr_.__has_val_) {
if (!__rhs.__repr_.__has_val_) {
- __reinit_expected(std::unexpect, std::move(__rhs.__repr_.__union_.__unex_));
+ __reinit_expected(unexpect, std::move(__rhs.__repr_.__union_.__unex_));
}
} else {
if (__rhs.__repr_.__has_val_) {
@@ -1151,7 +1151,7 @@ class expected<_Tp, _Err> {
requires(is_constructible_v<_Err, const _OtherErr&> && is_assignable_v<_Err&, const _OtherErr&>)
_LIBCPP_HIDE_FROM_ABI constexpr expected& operator=(const unexpected<_OtherErr>& __un) {
if (__repr_.__has_val_) {
- __reinit_expected(std::unexpect, __un.error());
+ __reinit_expected(unexpect, __un.error());
} else {
__repr_.__union_.__unex_ = __un.error();
}
@@ -1162,7 +1162,7 @@ class expected<_Tp, _Err> {
requires(is_constructible_v<_Err, _OtherErr> && is_assignable_v<_Err&, _OtherErr>)
_LIBCPP_HIDE_FROM_ABI constexpr expected& operator=(unexpected<_OtherErr>&& __un) {
if (__repr_.__has_val_) {
- __reinit_expected(std::unexpect, std::move(__un.error()));
+ __reinit_expected(unexpect, std::move(__un.error()));
} else {
__repr_.__union_.__unex_ = std::move(__un.error());
}
@@ -1182,7 +1182,7 @@ class expected<_Tp, _Err> {
{
auto __swap_val_unex_impl = [](expected& __with_val, expected& __with_err) {
// May throw, but will re-engage `__with_val` in that case.
- __with_val.__reinit_expected(std::unexpect, std::move(__with_err.__repr_.__union_.__unex_));
+ __with_val.__reinit_expected(unexpect, std::move(__with_err.__repr_.__union_.__unex_));
// Will not throw.
__with_err.__reinit_expected(in_place);
};
@@ -1502,7 +1502,7 @@ class expected<_Tp, _Err> {
_LIBCPP_HIDE_FROM_ABI constexpr __union_t() : __empty_() {}
template <class... _Args>
- _LIBCPP_HIDE_FROM_ABI constexpr explicit __union_t(std::unexpect_t, _Args&&... __args)
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit __union_t(unexpect_t, _Args&&... __args)
: __unex_(std::forward<_Args>(__args)...) {}
template <class _Func, class... _Args>
@@ -1541,7 +1541,7 @@ class expected<_Tp, _Err> {
_LIBCPP_HIDE_FROM_ABI constexpr __union_t& operator=(const __union_t&) = default;
template <class... _Args>
- _LIBCPP_HIDE_FROM_ABI constexpr explicit __union_t(std::unexpect_t, _Args&&... __args)
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit __union_t(unexpect_t, _Args&&... __args)
: __unex_(std::forward<_Args>(__args)...) {}
template <class _Func, class... _Args>
@@ -1576,7 +1576,7 @@ class expected<_Tp, _Err> {
_LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_repr(in_place_t) : __union_(), __has_val_(true) {}
template <class... _Args>
- _LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_repr(std::unexpect_t __tag, _Args&&... __args)
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_repr(unexpect_t __tag, _Args&&... __args)
: __union_(__tag, std::forward<_Args>(__args)...), __has_val_(false) {}
template <class... _Args>
>From d84a3ca9396aa5334e1aa9b6ae64975e41f28389 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jan=20Kokem=C3=BCller?= <jan.kokemueller at gmail.com>
Date: Sat, 21 Oct 2023 13:37:54 +0200
Subject: [PATCH 13/37] use _LIBCPP_NO_UNIQUE_ADDRESS
Co-authored-by: philnik777 <nikolasklauser at berlin.de>
---
libcxx/include/__expected/expected.h | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/libcxx/include/__expected/expected.h b/libcxx/include/__expected/expected.h
index 65921d4d157c6..a579dc7675607 100644
--- a/libcxx/include/__expected/expected.h
+++ b/libcxx/include/__expected/expected.h
@@ -976,8 +976,8 @@ class expected {
template <class, class>
friend class expected;
- [[no_unique_address]] __union_t<_Tp, _Err> __union_;
- [[no_unique_address]] bool __has_val_;
+ _LIBCPP_NO_UNIQUE_ADDRESS __union_t<_Tp, _Err> __union_;
+ _LIBCPP_NO_UNIQUE_ADDRESS bool __has_val_;
};
__expected_repr __repr_;
>From c97c58d2d07fd8046c2ba2de292dd481334e4c76 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jan=20Kokem=C3=BCller?= <jan.kokemueller at gmail.com>
Date: Sat, 21 Oct 2023 13:39:00 +0200
Subject: [PATCH 14/37] use _LIBCPP_NO_UNIQUE_ADDRESS
---
libcxx/include/__expected/expected.h | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/libcxx/include/__expected/expected.h b/libcxx/include/__expected/expected.h
index a579dc7675607..d8f0c97c5f9ff 100644
--- a/libcxx/include/__expected/expected.h
+++ b/libcxx/include/__expected/expected.h
@@ -1615,8 +1615,8 @@ class expected<_Tp, _Err> {
template <class, class>
friend class expected;
- [[no_unique_address]] __union_t<_Err> __union_;
- [[no_unique_address]] bool __has_val_;
+ _LIBCPP_NO_UNIQUE_ADDRESS __union_t<_Err> __union_;
+ _LIBCPP_NO_UNIQUE_ADDRESS bool __has_val_;
};
__expected_repr __repr_;
>From dda6105e3b94f991a48327982d8e69ec5cd6535c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jan=20Kokem=C3=BCller?= <jan.kokemueller at gmail.com>
Date: Sat, 21 Oct 2023 13:43:23 +0200
Subject: [PATCH 15/37] remove _LIBCPP_GCC_DIAGNOSTIC_IGNORED (should be
separate issue)
---
libcxx/include/__type_traits/datasizeof.h | 1 -
1 file changed, 1 deletion(-)
diff --git a/libcxx/include/__type_traits/datasizeof.h b/libcxx/include/__type_traits/datasizeof.h
index 96404ad15a733..5688e3293a69e 100644
--- a/libcxx/include/__type_traits/datasizeof.h
+++ b/libcxx/include/__type_traits/datasizeof.h
@@ -51,7 +51,6 @@ struct __libcpp_datasizeof {
// the use as an extension.
_LIBCPP_DIAGNOSTIC_PUSH
_LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Winvalid-offsetof")
- _LIBCPP_GCC_DIAGNOSTIC_IGNORED("-Winvalid-offsetof")
static const size_t value = offsetof(_FirstPaddingByte<>, __first_padding_byte_);
_LIBCPP_DIAGNOSTIC_POP
};
>From 057a1548bb917222f85dad5acf08ef377bb26b02 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jan=20Kokem=C3=BCller?= <jan.kokemueller at gmail.com>
Date: Sat, 21 Oct 2023 14:10:41 +0200
Subject: [PATCH 16/37] rename __expected_repr to __repr
---
libcxx/include/__expected/expected.h | 66 ++++++++++++++--------------
1 file changed, 33 insertions(+), 33 deletions(-)
diff --git a/libcxx/include/__expected/expected.h b/libcxx/include/__expected/expected.h
index d8f0c97c5f9ff..6be4617f07c8b 100644
--- a/libcxx/include/__expected/expected.h
+++ b/libcxx/include/__expected/expected.h
@@ -862,7 +862,7 @@ class expected {
requires(is_trivially_destructible_v<_ValueType> && is_trivially_destructible_v<_ErrorType>)
= default;
- // the __expected_repr's destructor handles this
+ // __repr's destructor handles this
_LIBCPP_HIDE_FROM_ABI constexpr ~__union_t() {}
_ValueType __val_;
@@ -909,7 +909,7 @@ class expected {
requires(is_trivially_destructible_v<_ValueType> && is_trivially_destructible_v<_ErrorType>)
= default;
- // the __expected_repr's destructor handles this
+ // __repr's destructor handles this
_LIBCPP_HIDE_FROM_ABI constexpr ~__union_t()
requires(!is_trivially_destructible_v<_ValueType> || !is_trivially_destructible_v<_ErrorType>)
{}
@@ -918,51 +918,51 @@ class expected {
_LIBCPP_NO_UNIQUE_ADDRESS _ErrorType __unex_;
};
- struct __expected_repr {
- _LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_repr() = delete;
+ struct __repr {
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit __repr() = delete;
template <class... _Args>
- _LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_repr(in_place_t __tag, _Args&&... __args)
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit __repr(in_place_t __tag, _Args&&... __args)
: __union_(__tag, std::forward<_Args>(__args)...), __has_val_(true) {}
template <class... _Args>
- _LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_repr(unexpect_t __tag, _Args&&... __args)
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit __repr(unexpect_t __tag, _Args&&... __args)
: __union_(__tag, std::forward<_Args>(__args)...), __has_val_(false) {}
template <class... _Args>
- _LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_repr(
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit __repr(
std::__expected_construct_in_place_from_invoke_tag __tag, _Args&&... __args)
: __union_(__tag, std::forward<_Args>(__args)...), __has_val_(true) {}
template <class... _Args>
- _LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_repr(
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit __repr(
std::__expected_construct_unexpected_from_invoke_tag __tag, _Args&&... __args)
: __union_(__tag, std::forward<_Args>(__args)...), __has_val_(false) {}
template <class... _Args>
- _LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_repr(bool __has_val, _Args&&... __args)
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit __repr(bool __has_val, _Args&&... __args)
: __union_(__has_val, std::forward<_Args>(__args)...), __has_val_(__has_val) {}
- _LIBCPP_HIDE_FROM_ABI constexpr __expected_repr(const __expected_repr&) = delete;
- _LIBCPP_HIDE_FROM_ABI constexpr __expected_repr(const __expected_repr&)
+ _LIBCPP_HIDE_FROM_ABI constexpr __repr(const __repr&) = delete;
+ _LIBCPP_HIDE_FROM_ABI constexpr __repr(const __repr&)
requires(is_copy_constructible_v<_Tp> &&
is_copy_constructible_v<_Err> &&
is_trivially_copy_constructible_v<_Tp> &&
is_trivially_copy_constructible_v<_Err>)
= default;
- _LIBCPP_HIDE_FROM_ABI constexpr __expected_repr(__expected_repr&&) = delete;
- _LIBCPP_HIDE_FROM_ABI constexpr __expected_repr(__expected_repr&&)
+ _LIBCPP_HIDE_FROM_ABI constexpr __repr(__repr&&) = delete;
+ _LIBCPP_HIDE_FROM_ABI constexpr __repr(__repr&&)
requires(is_move_constructible_v<_Tp> && is_move_constructible_v<_Err>
&& is_trivially_move_constructible_v<_Tp> && is_trivially_move_constructible_v<_Err>)
= default;
- _LIBCPP_HIDE_FROM_ABI constexpr __expected_repr& operator=(const __expected_repr&) = delete;
+ _LIBCPP_HIDE_FROM_ABI constexpr __repr& operator=(const __repr&) = delete;
- _LIBCPP_HIDE_FROM_ABI constexpr ~__expected_repr()
+ _LIBCPP_HIDE_FROM_ABI constexpr ~__repr()
requires(is_trivially_destructible_v<_Tp> && is_trivially_destructible_v<_Err>)
= default;
- _LIBCPP_HIDE_FROM_ABI constexpr ~__expected_repr()
+ _LIBCPP_HIDE_FROM_ABI constexpr ~__repr()
requires(!is_trivially_destructible_v<_Tp> || !is_trivially_destructible_v<_Err>)
{
if (__has_val_) {
@@ -980,7 +980,7 @@ class expected {
_LIBCPP_NO_UNIQUE_ADDRESS bool __has_val_;
};
- __expected_repr __repr_;
+ __repr __repr_;
};
template <class _Tp, class _Err>
@@ -1522,7 +1522,7 @@ class expected<_Tp, _Err> {
requires(is_trivially_destructible_v<_ErrorType>)
= default;
- // the __expected_repr's destructor handles this
+ // __repr's destructor handles this
_LIBCPP_HIDE_FROM_ABI constexpr ~__union_t() {}
__empty_t __empty_;
@@ -1561,7 +1561,7 @@ class expected<_Tp, _Err> {
requires(is_trivially_destructible_v<_ErrorType>)
= default;
- // the __expected_repr's destructor handles this
+ // __repr's destructor handles this
_LIBCPP_HIDE_FROM_ABI constexpr ~__union_t()
requires(!is_trivially_destructible_v<_ErrorType>)
{}
@@ -1570,40 +1570,40 @@ class expected<_Tp, _Err> {
_LIBCPP_NO_UNIQUE_ADDRESS _ErrorType __unex_;
};
- struct __expected_repr {
- _LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_repr() = delete;
+ struct __repr {
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit __repr() = delete;
- _LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_repr(in_place_t) : __union_(), __has_val_(true) {}
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit __repr(in_place_t) : __union_(), __has_val_(true) {}
template <class... _Args>
- _LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_repr(unexpect_t __tag, _Args&&... __args)
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit __repr(unexpect_t __tag, _Args&&... __args)
: __union_(__tag, std::forward<_Args>(__args)...), __has_val_(false) {}
template <class... _Args>
- _LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_repr(
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit __repr(
std::__expected_construct_unexpected_from_invoke_tag __tag, _Args&&... __args)
: __union_(__tag, std::forward<_Args>(__args)...), __has_val_(false) {}
template <class... _Args>
- _LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_repr(bool __has_val, _Args&&... __args)
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit __repr(bool __has_val, _Args&&... __args)
: __union_(__has_val, std::forward<_Args>(__args)...), __has_val_(__has_val) {}
- _LIBCPP_HIDE_FROM_ABI constexpr __expected_repr(const __expected_repr&) = delete;
- _LIBCPP_HIDE_FROM_ABI constexpr __expected_repr(const __expected_repr&)
+ _LIBCPP_HIDE_FROM_ABI constexpr __repr(const __repr&) = delete;
+ _LIBCPP_HIDE_FROM_ABI constexpr __repr(const __repr&)
requires(is_copy_constructible_v<_Err> && is_trivially_copy_constructible_v<_Err>)
= default;
- _LIBCPP_HIDE_FROM_ABI constexpr __expected_repr(__expected_repr&&) = delete;
- _LIBCPP_HIDE_FROM_ABI constexpr __expected_repr(__expected_repr&&)
+ _LIBCPP_HIDE_FROM_ABI constexpr __repr(__repr&&) = delete;
+ _LIBCPP_HIDE_FROM_ABI constexpr __repr(__repr&&)
requires(is_move_constructible_v<_Err> && is_trivially_move_constructible_v<_Err>)
= default;
- _LIBCPP_HIDE_FROM_ABI constexpr __expected_repr& operator=(const __expected_repr&) = delete;
+ _LIBCPP_HIDE_FROM_ABI constexpr __repr& operator=(const __repr&) = delete;
- _LIBCPP_HIDE_FROM_ABI constexpr ~__expected_repr()
+ _LIBCPP_HIDE_FROM_ABI constexpr ~__repr()
requires(is_trivially_destructible_v<_Err>)
= default;
- _LIBCPP_HIDE_FROM_ABI constexpr ~__expected_repr()
+ _LIBCPP_HIDE_FROM_ABI constexpr ~__repr()
requires(!is_trivially_destructible_v<_Err>)
{
if (!__has_val_) {
@@ -1619,7 +1619,7 @@ class expected<_Tp, _Err> {
_LIBCPP_NO_UNIQUE_ADDRESS bool __has_val_;
};
- __expected_repr __repr_;
+ __repr __repr_;
};
_LIBCPP_END_NAMESPACE_STD
>From a476f2cd882ecdbdda559d3b9be20267c2dc3027 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jan=20Kokem=C3=BCller?= <jan.kokemueller at gmail.com>
Date: Tue, 24 Oct 2023 16:52:35 +0200
Subject: [PATCH 17/37] implement optimized layout for types without tail
padding
---
libcxx/include/__expected/expected.h | 1120 ++++++++++-------
.../no_unique_address.compile.pass.cpp | 22 +-
.../transform_error.mandates.verify.cpp | 1 +
.../no_unique_address.compile.pass.cpp | 19 +-
.../transform_error.mandates.verify.cpp | 2 +
5 files changed, 724 insertions(+), 440 deletions(-)
diff --git a/libcxx/include/__expected/expected.h b/libcxx/include/__expected/expected.h
index 6be4617f07c8b..acc68f9546548 100644
--- a/libcxx/include/__expected/expected.h
+++ b/libcxx/include/__expected/expected.h
@@ -88,8 +88,288 @@ _LIBCPP_HIDE_FROM_ABI void __throw_bad_expected_access(_Arg&& __arg) {
# endif
}
+template <class _Union, class _OtherUnion>
+_LIBCPP_HIDE_FROM_ABI constexpr _Union __make_expected_union(bool __has_val, _OtherUnion&& __other)
+{
+ if (__has_val)
+ return _Union(in_place, std::forward<_OtherUnion>(__other).__val_);
+ else
+ return _Union(unexpect, std::forward<_OtherUnion>(__other).__unex_);
+}
+
+template <class _ValueType, class _ErrorType>
+union __expected_union_t {
+ template <class... _Args>
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_union_t(in_place_t, _Args&&... __args)
+ : __val_(std::forward<_Args>(__args)...) {}
+
+ template <class... _Args>
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_union_t(unexpect_t, _Args&&... __args)
+ : __unex_(std::forward<_Args>(__args)...) {}
+
+ template <class _Func, class... _Args>
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_union_t(
+ std::__expected_construct_in_place_from_invoke_tag, _Func&& __f, _Args&&... __args)
+ : __val_(std::invoke(std::forward<_Func>(__f), std::forward<_Args>(__args)...)) {}
+
+ template <class _Func, class... _Args>
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_union_t(
+ std::__expected_construct_unexpected_from_invoke_tag, _Func&& __f, _Args&&... __args)
+ : __unex_(std::invoke(std::forward<_Func>(__f), std::forward<_Args>(__args)...)) {}
+
+ _LIBCPP_HIDE_FROM_ABI constexpr ~__expected_union_t()
+ requires(is_trivially_destructible_v<_ValueType> && is_trivially_destructible_v<_ErrorType>)
+ = default;
+
+ // __expected_repr's destructor handles this
+ _LIBCPP_HIDE_FROM_ABI constexpr ~__expected_union_t() {}
+
+ // XXX Why are those not [[no_unique_address]]?
+ _ValueType __val_;
+ _ErrorType __unex_;
+};
+
+// use named union because [[no_unique_address]] cannot be applied to an unnamed union,
+// also guaranteed elision into a potentially-overlapping subobject is unsettled (and
+// it's not clear that it's implementable, given that the function is allowed to clobber
+// the tail padding) - see https://github.com/itanium-cxx-abi/cxx-abi/issues/107.
+template <class _ValueType, class _ErrorType>
+ requires(is_trivially_move_constructible_v<_ValueType> && is_trivially_move_constructible_v<_ErrorType>)
+union __expected_union_t<_ValueType, _ErrorType> {
+ _LIBCPP_HIDE_FROM_ABI constexpr __expected_union_t(const __expected_union_t&) = default;
+ _LIBCPP_HIDE_FROM_ABI constexpr __expected_union_t& operator=(const __expected_union_t&) = default;
+
+ template <class... _Args>
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_union_t(in_place_t, _Args&&... __args)
+ : __val_(std::forward<_Args>(__args)...) {}
+
+ template <class... _Args>
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_union_t(unexpect_t, _Args&&... __args)
+ : __unex_(std::forward<_Args>(__args)...) {}
+
+ template <class _Func, class... _Args>
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_union_t(
+ std::__expected_construct_in_place_from_invoke_tag, _Func&& __f, _Args&&... __args)
+ : __val_(std::invoke(std::forward<_Func>(__f), std::forward<_Args>(__args)...)) {}
+
+ template <class _Func, class... _Args>
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_union_t(
+ std::__expected_construct_unexpected_from_invoke_tag, _Func&& __f, _Args&&... __args)
+ : __unex_(std::invoke(std::forward<_Func>(__f), std::forward<_Args>(__args)...)) {}
+
+ _LIBCPP_HIDE_FROM_ABI constexpr ~__expected_union_t()
+ requires(is_trivially_destructible_v<_ValueType> && is_trivially_destructible_v<_ErrorType>)
+ = default;
+
+ // __expected_repr's destructor handles this
+ _LIBCPP_HIDE_FROM_ABI constexpr ~__expected_union_t() {}
+
+ _LIBCPP_NO_UNIQUE_ADDRESS _ValueType __val_;
+ _LIBCPP_NO_UNIQUE_ADDRESS _ErrorType __unex_;
+};
+
+template <class _Tp, class _Err, bool _StuffTail = false>
+struct __expected_repr {
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_repr() = delete;
+
+ template <class... _Args>
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_repr(in_place_t __tag, _Args&&... __args)
+ : __union_(__tag, std::forward<_Args>(__args)...), __has_val_(true) {}
+
+ template <class... _Args>
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_repr(unexpect_t __tag, _Args&&... __args)
+ : __union_(__tag, std::forward<_Args>(__args)...), __has_val_(false) {}
+
+ template <class... _Args>
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_repr(
+ std::__expected_construct_in_place_from_invoke_tag __tag, _Args&&... __args)
+ : __union_(__tag, std::forward<_Args>(__args)...), __has_val_(true) {}
+
+ template <class... _Args>
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_repr(
+ std::__expected_construct_unexpected_from_invoke_tag __tag, _Args&&... __args)
+ : __union_(__tag, std::forward<_Args>(__args)...), __has_val_(false) {}
+
+ template <class _OtherUnion>
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_repr(bool __has_val, _OtherUnion&& __other)
+ : __union_(__make_expected_union<__expected_union_t<_Tp, _Err>>(__has_val,
+ std::forward<_OtherUnion>(__other))),
+ __has_val_(__has_val) {}
+
+ _LIBCPP_HIDE_FROM_ABI constexpr __expected_repr(const __expected_repr&) = delete;
+ _LIBCPP_HIDE_FROM_ABI constexpr __expected_repr(const __expected_repr&)
+ requires(is_copy_constructible_v<_Tp> && is_copy_constructible_v<_Err> &&
+ is_trivially_copy_constructible_v<_Tp> && is_trivially_copy_constructible_v<_Err>)
+ = default;
+ _LIBCPP_HIDE_FROM_ABI constexpr __expected_repr(__expected_repr&&) = delete;
+ _LIBCPP_HIDE_FROM_ABI constexpr __expected_repr(__expected_repr&&)
+ requires(is_move_constructible_v<_Tp> && is_move_constructible_v<_Err> &&
+ is_trivially_move_constructible_v<_Tp> && is_trivially_move_constructible_v<_Err>)
+ = default;
+
+ _LIBCPP_HIDE_FROM_ABI constexpr __expected_repr& operator=(const __expected_repr&) = delete;
+
+ _LIBCPP_HIDE_FROM_ABI constexpr ~__expected_repr()
+ requires(is_trivially_destructible_v<_Tp> && is_trivially_destructible_v<_Err>)
+ = default;
+
+ _LIBCPP_HIDE_FROM_ABI constexpr ~__expected_repr()
+ requires(!is_trivially_destructible_v<_Tp> || !is_trivially_destructible_v<_Err>)
+ {
+ __destroy_union_member();
+ }
+
+ _LIBCPP_HIDE_FROM_ABI constexpr void __destroy_union()
+ requires(is_trivially_destructible_v<_Tp> && is_trivially_destructible_v<_Err>)
+ {
+ std::destroy_at(&__union_);
+ }
+
+ _LIBCPP_HIDE_FROM_ABI constexpr void __destroy_union()
+ requires(!is_trivially_destructible_v<_Tp> || !is_trivially_destructible_v<_Err>)
+ {
+ __destroy_union_member();
+ std::destroy_at(&__union_);
+ }
+
+ template <class... _Args>
+ _LIBCPP_HIDE_FROM_ABI constexpr void __construct_union(in_place_t, _Args&&... __args)
+ {
+ std::construct_at(&__union_, in_place, std::forward<_Args>(__args)...);
+ __has_val_ = true;
+ }
+
+ template <class... _Args>
+ _LIBCPP_HIDE_FROM_ABI constexpr void __construct_union(unexpect_t, _Args&&... __args)
+ {
+ std::construct_at(&__union_, unexpect, std::forward<_Args>(__args)...);
+ __has_val_ = false;
+ }
+
+private:
+ template <class, class>
+ friend class expected;
+
+ _LIBCPP_HIDE_FROM_ABI constexpr void __destroy_union_member()
+ requires(!is_trivially_destructible_v<_Tp> || !is_trivially_destructible_v<_Err>)
+ {
+ if (__has_val_) {
+ std::destroy_at(std::addressof(__union_.__val_));
+ } else {
+ std::destroy_at(std::addressof(__union_.__unex_));
+ }
+ }
+
+ __expected_union_t<_Tp, _Err> __union_;
+ _LIBCPP_NO_UNIQUE_ADDRESS bool __has_val_;
+};
+
+template <class _Tp, class _Err>
+struct __expected_repr<_Tp, _Err, true> {
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_repr() = delete;
+
+ template <class... _Args>
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_repr(in_place_t __tag, _Args&&... __args)
+ : __union_(__tag, std::forward<_Args>(__args)...), __has_val_(true) {}
+
+ template <class... _Args>
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_repr(unexpect_t __tag, _Args&&... __args)
+ : __union_(__tag, std::forward<_Args>(__args)...), __has_val_(false) {}
+
+ template <class... _Args>
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_repr(
+ std::__expected_construct_in_place_from_invoke_tag __tag, _Args&&... __args)
+ : __union_(__tag, std::forward<_Args>(__args)...), __has_val_(true) {}
+
+ template <class... _Args>
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_repr(
+ std::__expected_construct_unexpected_from_invoke_tag __tag, _Args&&... __args)
+ : __union_(__tag, std::forward<_Args>(__args)...), __has_val_(false) {}
+
+ template <class _OtherUnion>
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_repr(bool __has_val, _OtherUnion&& __other)
+ : __union_(__make_expected_union<__expected_union_t<_Tp, _Err>>(__has_val,
+ std::forward<_OtherUnion>(__other))),
+ __has_val_(__has_val) {}
+
+ _LIBCPP_HIDE_FROM_ABI constexpr __expected_repr(const __expected_repr&) = delete;
+ _LIBCPP_HIDE_FROM_ABI constexpr __expected_repr(const __expected_repr&)
+ requires(is_copy_constructible_v<_Tp> && is_copy_constructible_v<_Err> &&
+ is_trivially_copy_constructible_v<_Tp> && is_trivially_copy_constructible_v<_Err>)
+ = default;
+ _LIBCPP_HIDE_FROM_ABI constexpr __expected_repr(__expected_repr&&) = delete;
+ _LIBCPP_HIDE_FROM_ABI constexpr __expected_repr(__expected_repr&&)
+ requires(is_move_constructible_v<_Tp> && is_move_constructible_v<_Err> &&
+ is_trivially_move_constructible_v<_Tp> && is_trivially_move_constructible_v<_Err>)
+ = default;
+
+ _LIBCPP_HIDE_FROM_ABI constexpr __expected_repr& operator=(const __expected_repr&) = delete;
+
+ _LIBCPP_HIDE_FROM_ABI constexpr ~__expected_repr()
+ requires(is_trivially_destructible_v<_Tp> && is_trivially_destructible_v<_Err>)
+ = default;
+
+ _LIBCPP_HIDE_FROM_ABI constexpr ~__expected_repr()
+ requires(!is_trivially_destructible_v<_Tp> || !is_trivially_destructible_v<_Err>)
+ {
+ if (__has_val_) {
+ std::destroy_at(std::addressof(__union_.__val_));
+ } else {
+ std::destroy_at(std::addressof(__union_.__unex_));
+ }
+ }
+
+private:
+ template <class, class>
+ friend class expected;
+
+ _LIBCPP_NO_UNIQUE_ADDRESS __expected_union_t<_Tp, _Err> __union_;
+ _LIBCPP_NO_UNIQUE_ADDRESS bool __has_val_;
+};
+
+template <class _Tp, class _Err>
+struct __expected_base {
+protected:
+ template <class... _Args>
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_base(_Args&&... __args)
+ : __repr_(std::forward<_Args>(__args)...) {}
+
+ _LIBCPP_HIDE_FROM_ABI constexpr void __destroy() {
+ __repr_.__destroy_union();
+ }
+
+ template <class _Tag, class... _Args>
+ _LIBCPP_HIDE_FROM_ABI constexpr void __construct(_Tag __tag, _Args&&... __args)
+ {
+ __repr_.__construct_union(__tag, std::forward<_Args>(__args)...);
+ }
+
+ _LIBCPP_NO_UNIQUE_ADDRESS __expected_repr<_Tp, _Err, false> __repr_;
+};
+
+template <class _Tp, class _Err>
+ requires (sizeof(__expected_repr<_Tp, _Err, true>) == sizeof(__expected_union_t<_Tp, _Err>))
+struct __expected_base<_Tp, _Err> {
+protected:
+ template <class... _Args>
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_base(_Args&&... __args)
+ : __repr_(std::forward<_Args>(__args)...) {}
+
+ _LIBCPP_HIDE_FROM_ABI constexpr void __destroy() {
+ std::destroy_at(&__repr_);
+ }
+
+ template <class _Tag, class... _Args>
+ _LIBCPP_HIDE_FROM_ABI constexpr void __construct(_Tag __tag, _Args&&... __args)
+ {
+ std::construct_at(&__repr_, __tag, std::forward<_Args>(__args)...);
+ }
+
+ __expected_repr<_Tp, _Err, true> __repr_;
+};
+
template <class _Tp, class _Err>
-class expected {
+class expected : private __expected_base<_Tp, _Err> {
static_assert(
!is_reference_v<_Tp> &&
!is_function_v<_Tp> &&
@@ -107,6 +387,8 @@ class expected {
template <class _Up, class _OtherErr>
friend class expected;
+ using __base = __expected_base<_Tp, _Err>;
+
public:
using value_type = _Tp;
using error_type = _Err;
@@ -119,22 +401,20 @@ class expected {
_LIBCPP_HIDE_FROM_ABI constexpr expected()
noexcept(is_nothrow_default_constructible_v<_Tp>) // strengthened
requires is_default_constructible_v<_Tp>
- : __repr_(in_place) {}
+ : __base(in_place) {}
_LIBCPP_HIDE_FROM_ABI constexpr expected(const expected&) = delete;
_LIBCPP_HIDE_FROM_ABI constexpr expected(const expected&)
- requires(is_copy_constructible_v<_Tp> &&
- is_copy_constructible_v<_Err> &&
- is_trivially_copy_constructible_v<_Tp> &&
- is_trivially_copy_constructible_v<_Err>)
+ requires(is_copy_constructible_v<_Tp> && is_copy_constructible_v<_Err> &&
+ is_trivially_copy_constructible_v<_Tp> && is_trivially_copy_constructible_v<_Err>)
= default;
_LIBCPP_HIDE_FROM_ABI constexpr expected(const expected& __other)
noexcept(is_nothrow_copy_constructible_v<_Tp> && is_nothrow_copy_constructible_v<_Err>) // strengthened
requires(is_copy_constructible_v<_Tp> && is_copy_constructible_v<_Err> &&
!(is_trivially_copy_constructible_v<_Tp> && is_trivially_copy_constructible_v<_Err>))
- : __repr_(__other.__repr_.__has_val_, __other.__repr_.__union_) { }
+ : __base(__other.__repr_.__has_val_, __other.__repr_.__union_) { }
_LIBCPP_HIDE_FROM_ABI constexpr expected(expected&&)
requires(is_move_constructible_v<_Tp> && is_move_constructible_v<_Err>
@@ -145,7 +425,7 @@ class expected {
noexcept(is_nothrow_move_constructible_v<_Tp> && is_nothrow_move_constructible_v<_Err>)
requires(is_move_constructible_v<_Tp> && is_move_constructible_v<_Err> &&
!(is_trivially_move_constructible_v<_Tp> && is_trivially_move_constructible_v<_Err>))
- : __repr_(__other.__repr_.__has_val_, std::move(__other.__repr_.__union_)) { }
+ : __base(__other.__repr_.__has_val_, std::move(__other.__repr_.__union_)) { }
private:
template <class _Up, class _OtherErr, class _UfQual, class _OtherErrQual>
@@ -170,12 +450,12 @@ class expected {
template <class _Func, class... _Args>
_LIBCPP_HIDE_FROM_ABI constexpr explicit expected(
std::__expected_construct_in_place_from_invoke_tag __tag, _Func&& __f, _Args&&... __args)
- : __repr_(__tag, std::forward<_Func>(__f), std::forward<_Args>(__args)...) {}
+ : __base(__tag, std::forward<_Func>(__f), std::forward<_Args>(__args)...) {}
template <class _Func, class... _Args>
_LIBCPP_HIDE_FROM_ABI constexpr explicit expected(
std::__expected_construct_unexpected_from_invoke_tag __tag, _Func&& __f, _Args&&... __args)
- : __repr_(__tag, std::forward<_Func>(__f), std::forward<_Args>(__args)...) {}
+ : __base(__tag, std::forward<_Func>(__f), std::forward<_Args>(__args)...) {}
public:
template <class _Up, class _OtherErr>
@@ -185,14 +465,14 @@ class expected {
expected(const expected<_Up, _OtherErr>& __other)
noexcept(is_nothrow_constructible_v<_Tp, const _Up&> &&
is_nothrow_constructible_v<_Err, const _OtherErr&>) // strengthened
- : __repr_(__other.__repr_.__has_val_, __other.__repr_.__union_) {}
+ : __base(__other.__repr_.__has_val_, __other.__repr_.__union_) {}
template <class _Up, class _OtherErr>
requires __can_convert<_Up, _OtherErr, _Up, _OtherErr>::value
_LIBCPP_HIDE_FROM_ABI constexpr explicit(!is_convertible_v<_Up, _Tp> || !is_convertible_v<_OtherErr, _Err>)
expected(expected<_Up, _OtherErr>&& __other)
noexcept(is_nothrow_constructible_v<_Tp, _Up> && is_nothrow_constructible_v<_Err, _OtherErr>) // strengthened
- : __repr_(__other.__repr_.__has_val_, std::move(__other.__repr_.__union_)) {}
+ : __base(__other.__repr_.__has_val_, std::move(__other.__repr_.__union_)) {}
template <class _Up = _Tp>
requires(!is_same_v<remove_cvref_t<_Up>, in_place_t> && !is_same_v<expected, remove_cvref_t<_Up>> &&
@@ -200,47 +480,47 @@ class expected {
(!is_same_v<remove_cv_t<_Tp>, bool> || !__is_std_expected<remove_cvref_t<_Up>>::value))
_LIBCPP_HIDE_FROM_ABI constexpr explicit(!is_convertible_v<_Up, _Tp>)
expected(_Up&& __u) noexcept(is_nothrow_constructible_v<_Tp, _Up>) // strengthened
- : __repr_(in_place, std::forward<_Up>(__u)) {}
+ : __base(in_place, std::forward<_Up>(__u)) {}
template <class _OtherErr>
requires is_constructible_v<_Err, const _OtherErr&>
_LIBCPP_HIDE_FROM_ABI constexpr explicit(!is_convertible_v<const _OtherErr&, _Err>)
expected(const unexpected<_OtherErr>& __unex)
noexcept(is_nothrow_constructible_v<_Err, const _OtherErr&>) // strengthened
- : __repr_(unexpect, __unex.error()) {}
+ : __base(unexpect, __unex.error()) {}
template <class _OtherErr>
requires is_constructible_v<_Err, _OtherErr>
_LIBCPP_HIDE_FROM_ABI constexpr explicit(!is_convertible_v<_OtherErr, _Err>)
expected(unexpected<_OtherErr>&& __unex)
noexcept(is_nothrow_constructible_v<_Err, _OtherErr>) // strengthened
- : __repr_(unexpect, std::move(__unex.error())) {}
+ : __base(unexpect, std::move(__unex.error())) {}
template <class... _Args>
requires is_constructible_v<_Tp, _Args...>
_LIBCPP_HIDE_FROM_ABI constexpr explicit expected(in_place_t, _Args&&... __args)
noexcept(is_nothrow_constructible_v<_Tp, _Args...>) // strengthened
- : __repr_(in_place, std::forward<_Args>(__args)...) {}
+ : __base(in_place, std::forward<_Args>(__args)...) {}
template <class _Up, class... _Args>
requires is_constructible_v< _Tp, initializer_list<_Up>&, _Args... >
_LIBCPP_HIDE_FROM_ABI constexpr explicit
expected(in_place_t, initializer_list<_Up> __il, _Args&&... __args)
noexcept(is_nothrow_constructible_v<_Tp, initializer_list<_Up>&, _Args...>) // strengthened
- : __repr_(in_place, __il, std::forward<_Args>(__args)...) {}
+ : __base(in_place, __il, std::forward<_Args>(__args)...) {}
template <class... _Args>
requires is_constructible_v<_Err, _Args...>
_LIBCPP_HIDE_FROM_ABI constexpr explicit expected(unexpect_t, _Args&&... __args)
noexcept(is_nothrow_constructible_v<_Err, _Args...>) // strengthened
- : __repr_(unexpect, std::forward<_Args>(__args)...) {}
+ : __base(unexpect, std::forward<_Args>(__args)...) {}
template <class _Up, class... _Args>
requires is_constructible_v< _Err, initializer_list<_Up>&, _Args... >
_LIBCPP_HIDE_FROM_ABI constexpr explicit
expected(unexpect_t, initializer_list<_Up> __il, _Args&&... __args)
noexcept(is_nothrow_constructible_v<_Err, initializer_list<_Up>&, _Args...>) // strengthened
- : __repr_(unexpect, __il, std::forward<_Args>(__args)...) {}
+ : __base(unexpect, __il, std::forward<_Args>(__args)...) {}
// [expected.object.dtor], destructor
@@ -250,22 +530,21 @@ class expected {
template <class _Tag, class _OtherTag, class _T1, class _T2, class... _Args>
_LIBCPP_HIDE_FROM_ABI constexpr void __reinit_expected(_T2& __oldval, _Args&&... __args) {
if constexpr (is_nothrow_constructible_v<_T1, _Args...>) {
- std::destroy_at(&__repr_);
- std::construct_at(&__repr_, _Tag{}, std::forward<_Args>(__args)...);
+ this->__destroy();
+ this->__construct(_Tag{}, std::forward<_Args>(__args)...);
} else if constexpr (is_nothrow_move_constructible_v<_T1>) {
_T1 __tmp(std::forward<_Args>(__args)...);
- std::destroy_at(&__repr_);
- std::construct_at(&__repr_, _Tag{}, std::move(__tmp));
+ this->__destroy();
+ this->__construct(_Tag{}, std::move(__tmp));
} else {
static_assert(
is_nothrow_move_constructible_v<_T2>,
"To provide strong exception guarantee, T2 has to satisfy `is_nothrow_move_constructible_v` so that it can "
"be reverted to the previous state in case an exception is thrown during the assignment.");
_T2 __tmp(std::move(__oldval));
- std::destroy_at(&__repr_);
- auto __trans =
- std::__make_exception_guard([&] { std::construct_at(&__repr_, _OtherTag{}, std::move(__tmp)); });
- std::construct_at(&__repr_, _Tag{}, std::forward<_Args>(__args)...);
+ this->__destroy();
+ auto __trans = std::__make_exception_guard([&] { this->__construct(_OtherTag{}, std::move(__tmp)); });
+ this->__construct(_Tag{}, std::forward<_Args>(__args)...);
__trans.__complete();
}
}
@@ -286,16 +565,16 @@ class expected {
(is_nothrow_move_constructible_v<_Tp> ||
is_nothrow_move_constructible_v<_Err>))
{
- if (__repr_.__has_val_ && __rhs.__repr_.__has_val_) {
- __repr_.__union_.__val_ = __rhs.__repr_.__union_.__val_;
- } else if (__repr_.__has_val_) {
+ if (this->__repr_.__has_val_ && __rhs.__repr_.__has_val_) {
+ this->__repr_.__union_.__val_ = __rhs.__repr_.__union_.__val_;
+ } else if (this->__repr_.__has_val_) {
__reinit_expected<unexpect_t, in_place_t, _Err, _Tp>(
- __repr_.__union_.__val_, __rhs.__repr_.__union_.__unex_);
+ this->__repr_.__union_.__val_, __rhs.__repr_.__union_.__unex_);
} else if (__rhs.__repr_.__has_val_) {
__reinit_expected<in_place_t, unexpect_t, _Tp, _Err>(
- __repr_.__union_.__unex_, __rhs.__repr_.__union_.__val_);
+ this->__repr_.__union_.__unex_, __rhs.__repr_.__union_.__val_);
} else {
- __repr_.__union_.__unex_ = __rhs.__repr_.__union_.__unex_;
+ this->__repr_.__union_.__unex_ = __rhs.__repr_.__union_.__unex_;
}
return *this;
}
@@ -312,16 +591,16 @@ class expected {
(is_nothrow_move_constructible_v<_Tp> ||
is_nothrow_move_constructible_v<_Err>))
{
- if (__repr_.__has_val_ && __rhs.__repr_.__has_val_) {
- __repr_.__union_.__val_ = std::move(__rhs.__repr_.__union_.__val_);
- } else if (__repr_.__has_val_) {
+ if (this->__repr_.__has_val_ && __rhs.__repr_.__has_val_) {
+ this->__repr_.__union_.__val_ = std::move(__rhs.__repr_.__union_.__val_);
+ } else if (this->__repr_.__has_val_) {
__reinit_expected<unexpect_t, in_place_t, _Err, _Tp>(
- __repr_.__union_.__val_, std::move(__rhs.__repr_.__union_.__unex_));
+ this->__repr_.__union_.__val_, std::move(__rhs.__repr_.__union_.__unex_));
} else if (__rhs.__repr_.__has_val_) {
__reinit_expected<in_place_t, unexpect_t, _Tp, _Err>(
- __repr_.__union_.__unex_, std::move(__rhs.__repr_.__union_.__val_));
+ this->__repr_.__union_.__unex_, std::move(__rhs.__repr_.__union_.__val_));
} else {
- __repr_.__union_.__unex_ = std::move(__rhs.__repr_.__union_.__unex_);
+ this->__repr_.__union_.__unex_ = std::move(__rhs.__repr_.__union_.__unex_);
}
return *this;
}
@@ -336,11 +615,11 @@ class expected {
is_nothrow_move_constructible_v<_Tp> ||
is_nothrow_move_constructible_v<_Err>))
{
- if (__repr_.__has_val_) {
- __repr_.__union_.__val_ = std::forward<_Up>(__v);
+ if (this->__repr_.__has_val_) {
+ this->__repr_.__union_.__val_ = std::forward<_Up>(__v);
} else {
__reinit_expected<in_place_t, unexpect_t, _Tp, _Err>(
- __repr_.__union_.__unex_, std::forward<_Up>(__v));
+ this->__repr_.__union_.__unex_, std::forward<_Up>(__v));
}
return *this;
}
@@ -359,11 +638,11 @@ class expected {
template <class _OtherErr>
requires(__can_assign_from_unexpected<const _OtherErr&>)
_LIBCPP_HIDE_FROM_ABI constexpr expected& operator=(const unexpected<_OtherErr>& __un) {
- if (__repr_.__has_val_) {
+ if (this->__repr_.__has_val_) {
__reinit_expected<unexpect_t, in_place_t, _Err, _Tp>(
- __repr_.__union_.__val_, __un.error());
+ this->__repr_.__union_.__val_, __un.error());
} else {
- __repr_.__union_.__unex_ = __un.error();
+ this->__repr_.__union_.__unex_ = __un.error();
}
return *this;
}
@@ -371,11 +650,11 @@ class expected {
template <class _OtherErr>
requires(__can_assign_from_unexpected<_OtherErr>)
_LIBCPP_HIDE_FROM_ABI constexpr expected& operator=(unexpected<_OtherErr>&& __un) {
- if (__repr_.__has_val_) {
+ if (this->__repr_.__has_val_) {
__reinit_expected<unexpect_t, in_place_t, _Err, _Tp>(
- __repr_.__union_.__val_, std::move(__un.error()));
+ this->__repr_.__union_.__val_, std::move(__un.error()));
} else {
- __repr_.__union_.__unex_ = std::move(__un.error());
+ this->__repr_.__union_.__unex_ = std::move(__un.error());
}
return *this;
}
@@ -383,20 +662,19 @@ class expected {
template <class... _Args>
requires is_nothrow_constructible_v<_Tp, _Args...>
_LIBCPP_HIDE_FROM_ABI constexpr _Tp& emplace(_Args&&... __args) noexcept {
- std::destroy_at(&__repr_);
- std::construct_at(&__repr_, in_place, std::forward<_Args>(__args)...);
+ this->__destroy();
+ this->__construct(in_place, std::forward<_Args>(__args)...);
return __repr_.__union_.__val_;
}
template <class _Up, class... _Args>
requires is_nothrow_constructible_v< _Tp, initializer_list<_Up>&, _Args... >
_LIBCPP_HIDE_FROM_ABI constexpr _Tp& emplace(initializer_list<_Up> __il, _Args&&... __args) noexcept {
- std::destroy_at(&__repr_);
- std::construct_at(&__repr_, in_place, __il, std::forward<_Args>(__args)...);
+ this->__destroy();
+ this->__construct(in_place, __il, std::forward<_Args>(__args)...);
return __repr_.__union_.__val_;
}
-
public:
// [expected.object.swap], swap
_LIBCPP_HIDE_FROM_ABI constexpr void swap(expected& __rhs)
@@ -414,34 +692,34 @@ class expected {
auto __swap_val_unex_impl = [](expected& __with_val, expected& __with_err) {
if constexpr (is_nothrow_move_constructible_v<_Err>) {
_Err __tmp(std::move(__with_err.__repr_.__union_.__unex_));
- std::destroy_at(&__with_err.__repr_);
+ __with_err.__destroy();
auto __trans = std::__make_exception_guard([&] {
- std::construct_at(&__with_err.__repr_, unexpect, std::move(__tmp));
+ __with_err.__construct(unexpect, std::move(__tmp));
});
- std::construct_at(&__with_err.__repr_, in_place, std::move(__with_val.__repr_.__union_.__val_));
+ __with_err.__construct(in_place, std::move(__with_val.__repr_.__union_.__val_));
__trans.__complete();
- std::destroy_at(&__with_val.__repr_);
- std::construct_at(&__with_val.__repr_, unexpect, std::move(__tmp));
+ __with_val.__destroy();
+ __with_val.__construct(unexpect, std::move(__tmp));
} else {
static_assert(is_nothrow_move_constructible_v<_Tp>,
"To provide strong exception guarantee, Tp has to satisfy `is_nothrow_move_constructible_v` so "
"that it can be reverted to the previous state in case an exception is thrown during swap.");
_Tp __tmp(std::move(__with_val.__repr_.__union_.__val_));
- std::destroy_at(&__with_val.__repr_);
+ __with_val.__destroy();
auto __trans = std::__make_exception_guard([&] {
- std::construct_at(&__with_val.__repr_, in_place, std::move(__tmp));
+ __with_val.__construct(in_place, std::move(__tmp));
});
- std::construct_at(&__with_val.__repr_, unexpect, std::move(__with_err.__repr_.__union_.__unex_));
+ __with_val.__construct(unexpect, std::move(__with_err.__repr_.__union_.__unex_));
__trans.__complete();
- std::destroy_at(&__with_err.__repr_);
- std::construct_at(&__with_err.__repr_, in_place, std::move(__tmp));
+ __with_err.__destroy();
+ __with_err.__construct(in_place, std::move(__tmp));
}
};
- if (__repr_.__has_val_) {
+ if (this->__repr_.__has_val_) {
if (__rhs.__repr_.__has_val_) {
using std::swap;
- swap(__repr_.__union_.__val_, __rhs.__repr_.__union_.__val_);
+ swap(this->__repr_.__union_.__val_, __rhs.__repr_.__union_.__val_);
} else {
__swap_val_unex_impl(*this, __rhs);
}
@@ -450,7 +728,7 @@ class expected {
__swap_val_unex_impl(__rhs, *this);
} else {
using std::swap;
- swap(__repr_.__union_.__unex_, __rhs.__repr_.__union_.__unex_);
+ swap(this->__repr_.__union_.__unex_, __rhs.__repr_.__union_.__unex_);
}
}
}
@@ -464,105 +742,105 @@ class expected {
// [expected.object.obs], observers
_LIBCPP_HIDE_FROM_ABI constexpr const _Tp* operator->() const noexcept {
- _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__repr_.__has_val_, "expected::operator-> requires the expected to contain a value");
- return std::addressof(__repr_.__union_.__val_);
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(this->__repr_.__has_val_, "expected::operator-> requires the expected to contain a value");
+ return std::addressof(this->__repr_.__union_.__val_);
}
_LIBCPP_HIDE_FROM_ABI constexpr _Tp* operator->() noexcept {
- _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__repr_.__has_val_, "expected::operator-> requires the expected to contain a value");
- return std::addressof(__repr_.__union_.__val_);
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(this->__repr_.__has_val_, "expected::operator-> requires the expected to contain a value");
+ return std::addressof(this->__repr_.__union_.__val_);
}
_LIBCPP_HIDE_FROM_ABI constexpr const _Tp& operator*() const& noexcept {
- _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__repr_.__has_val_, "expected::operator* requires the expected to contain a value");
- return __repr_.__union_.__val_;
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(this->__repr_.__has_val_, "expected::operator* requires the expected to contain a value");
+ return this->__repr_.__union_.__val_;
}
_LIBCPP_HIDE_FROM_ABI constexpr _Tp& operator*() & noexcept {
- _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__repr_.__has_val_, "expected::operator* requires the expected to contain a value");
- return __repr_.__union_.__val_;
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(this->__repr_.__has_val_, "expected::operator* requires the expected to contain a value");
+ return this->__repr_.__union_.__val_;
}
_LIBCPP_HIDE_FROM_ABI constexpr const _Tp&& operator*() const&& noexcept {
- _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__repr_.__has_val_, "expected::operator* requires the expected to contain a value");
- return std::move(__repr_.__union_.__val_);
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(this->__repr_.__has_val_, "expected::operator* requires the expected to contain a value");
+ return std::move(this->__repr_.__union_.__val_);
}
_LIBCPP_HIDE_FROM_ABI constexpr _Tp&& operator*() && noexcept {
- _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__repr_.__has_val_, "expected::operator* requires the expected to contain a value");
- return std::move(__repr_.__union_.__val_);
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(this->__repr_.__has_val_, "expected::operator* requires the expected to contain a value");
+ return std::move(this->__repr_.__union_.__val_);
}
- _LIBCPP_HIDE_FROM_ABI constexpr explicit operator bool() const noexcept { return __repr_.__has_val_; }
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit operator bool() const noexcept { return this->__repr_.__has_val_; }
- _LIBCPP_HIDE_FROM_ABI constexpr bool has_value() const noexcept { return __repr_.__has_val_; }
+ _LIBCPP_HIDE_FROM_ABI constexpr bool has_value() const noexcept { return this->__repr_.__has_val_; }
_LIBCPP_HIDE_FROM_ABI constexpr const _Tp& value() const& {
static_assert(is_copy_constructible_v<_Err>, "error_type has to be copy constructible");
- if (!__repr_.__has_val_) {
+ if (!this->__repr_.__has_val_) {
std::__throw_bad_expected_access<_Err>(std::as_const(error()));
}
- return __repr_.__union_.__val_;
+ return this->__repr_.__union_.__val_;
}
_LIBCPP_HIDE_FROM_ABI constexpr _Tp& value() & {
static_assert(is_copy_constructible_v<_Err>, "error_type has to be copy constructible");
- if (!__repr_.__has_val_) {
+ if (!this->__repr_.__has_val_) {
std::__throw_bad_expected_access<_Err>(std::as_const(error()));
}
- return __repr_.__union_.__val_;
+ return this->__repr_.__union_.__val_;
}
_LIBCPP_HIDE_FROM_ABI constexpr const _Tp&& value() const&& {
static_assert(is_copy_constructible_v<_Err> && is_constructible_v<_Err, decltype(std::move(error()))>,
"error_type has to be both copy constructible and constructible from decltype(std::move(error()))");
- if (!__repr_.__has_val_) {
+ if (!this->__repr_.__has_val_) {
std::__throw_bad_expected_access<_Err>(std::move(error()));
}
- return std::move(__repr_.__union_.__val_);
+ return std::move(this->__repr_.__union_.__val_);
}
_LIBCPP_HIDE_FROM_ABI constexpr _Tp&& value() && {
static_assert(is_copy_constructible_v<_Err> && is_constructible_v<_Err, decltype(std::move(error()))>,
"error_type has to be both copy constructible and constructible from decltype(std::move(error()))");
- if (!__repr_.__has_val_) {
+ if (!this->__repr_.__has_val_) {
std::__throw_bad_expected_access<_Err>(std::move(error()));
}
- return std::move(__repr_.__union_.__val_);
+ return std::move(this->__repr_.__union_.__val_);
}
_LIBCPP_HIDE_FROM_ABI constexpr const _Err& error() const& noexcept {
- _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!__repr_.__has_val_, "expected::error requires the expected to contain an error");
- return __repr_.__union_.__unex_;
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!this->__repr_.__has_val_, "expected::error requires the expected to contain an error");
+ return this->__repr_.__union_.__unex_;
}
_LIBCPP_HIDE_FROM_ABI constexpr _Err& error() & noexcept {
- _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!__repr_.__has_val_, "expected::error requires the expected to contain an error");
- return __repr_.__union_.__unex_;
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!this->__repr_.__has_val_, "expected::error requires the expected to contain an error");
+ return this->__repr_.__union_.__unex_;
}
_LIBCPP_HIDE_FROM_ABI constexpr const _Err&& error() const&& noexcept {
- _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!__repr_.__has_val_, "expected::error requires the expected to contain an error");
- return std::move(__repr_.__union_.__unex_);
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!this->__repr_.__has_val_, "expected::error requires the expected to contain an error");
+ return std::move(this->__repr_.__union_.__unex_);
}
_LIBCPP_HIDE_FROM_ABI constexpr _Err&& error() && noexcept {
- _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!__repr_.__has_val_, "expected::error requires the expected to contain an error");
- return std::move(__repr_.__union_.__unex_);
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!this->__repr_.__has_val_, "expected::error requires the expected to contain an error");
+ return std::move(this->__repr_.__union_.__unex_);
}
template <class _Up>
_LIBCPP_HIDE_FROM_ABI constexpr _Tp value_or(_Up&& __v) const& {
static_assert(is_copy_constructible_v<_Tp>, "value_type has to be copy constructible");
static_assert(is_convertible_v<_Up, _Tp>, "argument has to be convertible to value_type");
- return __repr_.__has_val_ ? __repr_.__union_.__val_ : static_cast<_Tp>(std::forward<_Up>(__v));
+ return this->__repr_.__has_val_ ? this->__repr_.__union_.__val_ : static_cast<_Tp>(std::forward<_Up>(__v));
}
template <class _Up>
_LIBCPP_HIDE_FROM_ABI constexpr _Tp value_or(_Up&& __v) && {
static_assert(is_move_constructible_v<_Tp>, "value_type has to be move constructible");
static_assert(is_convertible_v<_Up, _Tp>, "argument has to be convertible to value_type");
- return __repr_.__has_val_ ? std::move(__repr_.__union_.__val_) : static_cast<_Tp>(std::forward<_Up>(__v));
+ return this->__repr_.__has_val_ ? std::move(this->__repr_.__union_.__val_) : static_cast<_Tp>(std::forward<_Up>(__v));
}
template <class _Up = _Err>
@@ -592,7 +870,7 @@ class expected {
static_assert(is_same_v<typename _Up::error_type, _Err>,
"The result of f(**this) must have the same error_type as this expected");
if (has_value()) {
- return std::invoke(std::forward<_Func>(__f), __repr_.__union_.__val_);
+ return std::invoke(std::forward<_Func>(__f), this->__repr_.__union_.__val_);
}
return _Up(unexpect, error());
}
@@ -605,7 +883,7 @@ class expected {
static_assert(is_same_v<typename _Up::error_type, _Err>,
"The result of f(**this) must have the same error_type as this expected");
if (has_value()) {
- return std::invoke(std::forward<_Func>(__f), __repr_.__union_.__val_);
+ return std::invoke(std::forward<_Func>(__f), this->__repr_.__union_.__val_);
}
return _Up(unexpect, error());
}
@@ -619,7 +897,7 @@ class expected {
static_assert(is_same_v<typename _Up::error_type, _Err>,
"The result of f(std::move(**this)) must have the same error_type as this expected");
if (has_value()) {
- return std::invoke(std::forward<_Func>(__f), std::move(__repr_.__union_.__val_));
+ return std::invoke(std::forward<_Func>(__f), std::move(this->__repr_.__union_.__val_));
}
return _Up(unexpect, std::move(error()));
}
@@ -633,7 +911,7 @@ class expected {
static_assert(is_same_v<typename _Up::error_type, _Err>,
"The result of f(std::move(**this)) must have the same error_type as this expected");
if (has_value()) {
- return std::invoke(std::forward<_Func>(__f), std::move(__repr_.__union_.__val_));
+ return std::invoke(std::forward<_Func>(__f), std::move(this->__repr_.__union_.__val_));
}
return _Up(unexpect, std::move(error()));
}
@@ -646,7 +924,7 @@ class expected {
static_assert(is_same_v<typename _Gp::value_type, _Tp>,
"The result of f(error()) must have the same value_type as this expected");
if (has_value()) {
- return _Gp(in_place, __repr_.__union_.__val_);
+ return _Gp(in_place, this->__repr_.__union_.__val_);
}
return std::invoke(std::forward<_Func>(__f), error());
}
@@ -659,7 +937,7 @@ class expected {
static_assert(is_same_v<typename _Gp::value_type, _Tp>,
"The result of f(error()) must have the same value_type as this expected");
if (has_value()) {
- return _Gp(in_place, __repr_.__union_.__val_);
+ return _Gp(in_place, this->__repr_.__union_.__val_);
}
return std::invoke(std::forward<_Func>(__f), error());
}
@@ -673,7 +951,7 @@ class expected {
static_assert(is_same_v<typename _Gp::value_type, _Tp>,
"The result of f(std::move(error())) must have the same value_type as this expected");
if (has_value()) {
- return _Gp(in_place, std::move(__repr_.__union_.__val_));
+ return _Gp(in_place, std::move(this->__repr_.__union_.__val_));
}
return std::invoke(std::forward<_Func>(__f), std::move(error()));
}
@@ -687,7 +965,7 @@ class expected {
static_assert(is_same_v<typename _Gp::value_type, _Tp>,
"The result of f(std::move(error())) must have the same value_type as this expected");
if (has_value()) {
- return _Gp(in_place, std::move(__repr_.__union_.__val_));
+ return _Gp(in_place, std::move(this->__repr_.__union_.__val_));
}
return std::invoke(std::forward<_Func>(__f), std::move(error()));
}
@@ -700,9 +978,9 @@ class expected {
return expected<_Up, _Err>(unexpect, error());
}
if constexpr (!is_void_v<_Up>) {
- return expected<_Up, _Err>(__expected_construct_in_place_from_invoke_tag{}, std::forward<_Func>(__f), __repr_.__union_.__val_);
+ return expected<_Up, _Err>(__expected_construct_in_place_from_invoke_tag{}, std::forward<_Func>(__f), this->__repr_.__union_.__val_);
} else {
- std::invoke(std::forward<_Func>(__f), __repr_.__union_.__val_);
+ std::invoke(std::forward<_Func>(__f), this->__repr_.__union_.__val_);
return expected<_Up, _Err>();
}
}
@@ -715,9 +993,9 @@ class expected {
return expected<_Up, _Err>(unexpect, error());
}
if constexpr (!is_void_v<_Up>) {
- return expected<_Up, _Err>(__expected_construct_in_place_from_invoke_tag{}, std::forward<_Func>(__f), __repr_.__union_.__val_);
+ return expected<_Up, _Err>(__expected_construct_in_place_from_invoke_tag{}, std::forward<_Func>(__f), this->__repr_.__union_.__val_);
} else {
- std::invoke(std::forward<_Func>(__f), __repr_.__union_.__val_);
+ std::invoke(std::forward<_Func>(__f), this->__repr_.__union_.__val_);
return expected<_Up, _Err>();
}
}
@@ -731,9 +1009,9 @@ class expected {
}
if constexpr (!is_void_v<_Up>) {
return expected<_Up, _Err>(
- __expected_construct_in_place_from_invoke_tag{}, std::forward<_Func>(__f), std::move(__repr_.__union_.__val_));
+ __expected_construct_in_place_from_invoke_tag{}, std::forward<_Func>(__f), std::move(this->__repr_.__union_.__val_));
} else {
- std::invoke(std::forward<_Func>(__f), std::move(__repr_.__union_.__val_));
+ std::invoke(std::forward<_Func>(__f), std::move(this->__repr_.__union_.__val_));
return expected<_Up, _Err>();
}
}
@@ -747,9 +1025,9 @@ class expected {
}
if constexpr (!is_void_v<_Up>) {
return expected<_Up, _Err>(
- __expected_construct_in_place_from_invoke_tag{}, std::forward<_Func>(__f), std::move(__repr_.__union_.__val_));
+ __expected_construct_in_place_from_invoke_tag{}, std::forward<_Func>(__f), std::move(this->__repr_.__union_.__val_));
} else {
- std::invoke(std::forward<_Func>(__f), std::move(__repr_.__union_.__val_));
+ std::invoke(std::forward<_Func>(__f), std::move(this->__repr_.__union_.__val_));
return expected<_Up, _Err>();
}
}
@@ -761,7 +1039,7 @@ class expected {
static_assert(__valid_std_unexpected<_Gp>::value,
"The result of f(error()) must be a valid template argument for unexpected");
if (has_value()) {
- return expected<_Tp, _Gp>(in_place, __repr_.__union_.__val_);
+ return expected<_Tp, _Gp>(in_place, this->__repr_.__union_.__val_);
}
return expected<_Tp, _Gp>(__expected_construct_unexpected_from_invoke_tag{}, std::forward<_Func>(__f), error());
}
@@ -773,7 +1051,7 @@ class expected {
static_assert(__valid_std_unexpected<_Gp>::value,
"The result of f(error()) must be a valid template argument for unexpected");
if (has_value()) {
- return expected<_Tp, _Gp>(in_place, __repr_.__union_.__val_);
+ return expected<_Tp, _Gp>(in_place, this->__repr_.__union_.__val_);
}
return expected<_Tp, _Gp>(__expected_construct_unexpected_from_invoke_tag{}, std::forward<_Func>(__f), error());
}
@@ -785,7 +1063,7 @@ class expected {
static_assert(__valid_std_unexpected<_Gp>::value,
"The result of f(std::move(error())) must be a valid template argument for unexpected");
if (has_value()) {
- return expected<_Tp, _Gp>(in_place, std::move(__repr_.__union_.__val_));
+ return expected<_Tp, _Gp>(in_place, std::move(this->__repr_.__union_.__val_));
}
return expected<_Tp, _Gp>(
__expected_construct_unexpected_from_invoke_tag{}, std::forward<_Func>(__f), std::move(error()));
@@ -798,7 +1076,7 @@ class expected {
static_assert(__valid_std_unexpected<_Gp>::value,
"The result of f(std::move(error())) must be a valid template argument for unexpected");
if (has_value()) {
- return expected<_Tp, _Gp>(in_place, std::move(__repr_.__union_.__val_));
+ return expected<_Tp, _Gp>(in_place, std::move(this->__repr_.__union_.__val_));
}
return expected<_Tp, _Gp>(
__expected_construct_unexpected_from_invoke_tag{}, std::forward<_Func>(__f), std::move(error()));
@@ -828,164 +1106,260 @@ class expected {
_LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const expected& __x, const unexpected<_E2>& __e) {
return !__x.__repr_.__has_val_ && static_cast<bool>(__x.__repr_.__union_.__unex_ == __e.error());
}
+};
+
+struct __expected_empty_t {};
+
+template <class _Union, class _OtherUnion>
+_LIBCPP_HIDE_FROM_ABI constexpr _Union __make_expected_void_union(bool __has_val, _OtherUnion&& __other)
+{
+ if (__has_val)
+ return _Union(in_place);
+ else
+ return _Union(unexpect, std::forward<_OtherUnion>(__other).__unex_);
+}
+
+template <class _ErrorType>
+union __expected_void_union_t {
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_void_union_t(in_place_t) : __empty_() {}
+
+ template <class... _Args>
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_void_union_t(unexpect_t, _Args&&... __args)
+ : __unex_(std::forward<_Args>(__args)...) {}
+
+ template <class _Func, class... _Args>
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_void_union_t(
+ __expected_construct_unexpected_from_invoke_tag, _Func&& __f, _Args&&... __args)
+ : __unex_(std::invoke(std::forward<_Func>(__f), std::forward<_Args>(__args)...)) {}
+
+ _LIBCPP_HIDE_FROM_ABI constexpr ~__expected_void_union_t()
+ requires(is_trivially_destructible_v<_ErrorType>)
+ = default;
+
+ // __expected_repr's destructor handles this
+ _LIBCPP_HIDE_FROM_ABI constexpr ~__expected_void_union_t() {}
+
+ // XXX: Why are those not [[no_unique_address]]?
+ __expected_empty_t __empty_;
+ _ErrorType __unex_;
+};
+
+// use named union because [[no_unique_address]] cannot be applied to an unnamed union,
+// also guaranteed elision into a potentially-overlapping subobject is unsettled (and
+// it's not clear that it's implementable, given that the function is allowed to clobber
+// the tail padding) - see https://github.com/itanium-cxx-abi/cxx-abi/issues/107.
+template <class _ErrorType>
+ requires is_trivially_move_constructible_v<_ErrorType>
+union __expected_void_union_t<_ErrorType> {
+ _LIBCPP_HIDE_FROM_ABI constexpr __expected_void_union_t(const __expected_void_union_t&) = default;
+ _LIBCPP_HIDE_FROM_ABI constexpr __expected_void_union_t& operator=(const __expected_void_union_t&) = default;
+
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_void_union_t(in_place_t) : __empty_() {}
+
+ template <class... _Args>
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_void_union_t(unexpect_t, _Args&&... __args)
+ : __unex_(std::forward<_Args>(__args)...) {}
+
+ template <class _Func, class... _Args>
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_void_union_t(
+ __expected_construct_unexpected_from_invoke_tag, _Func&& __f, _Args&&... __args)
+ : __unex_(std::invoke(std::forward<_Func>(__f), std::forward<_Args>(__args)...)) {}
+
+ _LIBCPP_HIDE_FROM_ABI constexpr ~__expected_void_union_t()
+ requires(is_trivially_destructible_v<_ErrorType>)
+ = default;
+
+ // __expected_repr's destructor handles this
+ _LIBCPP_HIDE_FROM_ABI constexpr ~__expected_void_union_t()
+ requires(!is_trivially_destructible_v<_ErrorType>)
+ {}
+
+ _LIBCPP_NO_UNIQUE_ADDRESS __expected_empty_t __empty_;
+ _LIBCPP_NO_UNIQUE_ADDRESS _ErrorType __unex_;
+};
+
+template <class _Err, bool _StuffTail = false>
+struct __expected_void_repr {
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_void_repr() = delete;
+
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_void_repr(in_place_t __tag)
+ : __union_(__tag), __has_val_(true) {}
+
+ template <class... _Args>
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_void_repr(unexpect_t __tag, _Args&&... __args)
+ : __union_(__tag, std::forward<_Args>(__args)...), __has_val_(false) {}
+
+ template <class... _Args>
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_void_repr(
+ std::__expected_construct_unexpected_from_invoke_tag __tag, _Args&&... __args)
+ : __union_(__tag, std::forward<_Args>(__args)...), __has_val_(false) {}
+
+ template <class _OtherUnion>
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_void_repr(bool __has_val, _OtherUnion&& __other)
+ : __union_(__make_expected_void_union<__expected_void_union_t<_Err>>(__has_val,
+ std::forward<_OtherUnion>(__other))),
+ __has_val_(__has_val) {}
+
+ _LIBCPP_HIDE_FROM_ABI constexpr __expected_void_repr(const __expected_void_repr&) = delete;
+ _LIBCPP_HIDE_FROM_ABI constexpr __expected_void_repr(const __expected_void_repr&)
+ requires(is_copy_constructible_v<_Err> && is_trivially_copy_constructible_v<_Err>)
+ = default;
+ _LIBCPP_HIDE_FROM_ABI constexpr __expected_void_repr(__expected_void_repr&&) = delete;
+ _LIBCPP_HIDE_FROM_ABI constexpr __expected_void_repr(__expected_void_repr&&)
+ requires(is_move_constructible_v<_Err> && is_trivially_move_constructible_v<_Err>)
+ = default;
+
+ _LIBCPP_HIDE_FROM_ABI constexpr __expected_void_repr& operator=(const __expected_void_repr&) = delete;
+
+ _LIBCPP_HIDE_FROM_ABI constexpr ~__expected_void_repr()
+ requires(is_trivially_destructible_v<_Err>)
+ = default;
+
+ _LIBCPP_HIDE_FROM_ABI constexpr ~__expected_void_repr()
+ requires(!is_trivially_destructible_v<_Err>)
+ {
+ __destroy_union_member();
+ }
+
+ _LIBCPP_HIDE_FROM_ABI constexpr void __destroy_union()
+ requires(is_trivially_destructible_v<_Err>)
+ {
+ std::destroy_at(&__union_);
+ }
+
+ _LIBCPP_HIDE_FROM_ABI constexpr void __destroy_union()
+ requires(!is_trivially_destructible_v<_Err>)
+ {
+ __destroy_union_member();
+ std::destroy_at(&__union_);
+ }
+
+ _LIBCPP_HIDE_FROM_ABI constexpr void __construct_union(in_place_t)
+ {
+ std::construct_at(&__union_, in_place);
+ __has_val_ = true;
+ }
+
+ template <class... _Args>
+ _LIBCPP_HIDE_FROM_ABI constexpr void __construct_union(unexpect_t, _Args&&... __args)
+ {
+ std::construct_at(&__union_, unexpect, std::forward<_Args>(__args)...);
+ __has_val_ = false;
+ }
private:
- template <class _ValueType, class _ErrorType>
- union __union_t {
- template <class... _Args>
- _LIBCPP_HIDE_FROM_ABI constexpr explicit __union_t(in_place_t, _Args&&... __args)
- : __val_(std::forward<_Args>(__args)...) {}
-
- template <class... _Args>
- _LIBCPP_HIDE_FROM_ABI constexpr explicit __union_t(unexpect_t, _Args&&... __args)
- : __unex_(std::forward<_Args>(__args)...) {}
-
- template <class _Func, class... _Args>
- _LIBCPP_HIDE_FROM_ABI constexpr explicit __union_t(
- std::__expected_construct_in_place_from_invoke_tag, _Func&& __f, _Args&&... __args)
- : __val_(std::invoke(std::forward<_Func>(__f), std::forward<_Args>(__args)...)) {}
-
- template <class _Func, class... _Args>
- _LIBCPP_HIDE_FROM_ABI constexpr explicit __union_t(
- std::__expected_construct_unexpected_from_invoke_tag, _Func&& __f, _Args&&... __args)
- : __unex_(std::invoke(std::forward<_Func>(__f), std::forward<_Args>(__args)...)) {}
-
- template <class _Union>
- _LIBCPP_HIDE_FROM_ABI constexpr explicit __union_t(bool __has_val, _Union&& __other) {
- if (__has_val)
- std::construct_at(std::addressof(__val_), std::forward<_Union>(__other).__val_);
- else
- std::construct_at(std::addressof(__unex_), std::forward<_Union>(__other).__unex_);
- }
-
- _LIBCPP_HIDE_FROM_ABI constexpr ~__union_t()
- requires(is_trivially_destructible_v<_ValueType> && is_trivially_destructible_v<_ErrorType>)
- = default;
-
- // __repr's destructor handles this
- _LIBCPP_HIDE_FROM_ABI constexpr ~__union_t() {}
-
- _ValueType __val_;
- _ErrorType __unex_;
- };
-
- // use named union because [[no_unique_address]] cannot be applied to an unnamed union,
- // also guaranteed elision into a potentially-overlapping subobject is unsettled (and
- // it's not clear that it's implementable, given that the function is allowed to clobber
- // the tail padding) - see https://github.com/itanium-cxx-abi/cxx-abi/issues/107.
- template <class _ValueType, class _ErrorType>
- requires(is_trivially_move_constructible_v<_ValueType> && is_trivially_move_constructible_v<_ErrorType>)
- union __union_t<_ValueType, _ErrorType> {
- _LIBCPP_HIDE_FROM_ABI constexpr __union_t(const __union_t&) = default;
- _LIBCPP_HIDE_FROM_ABI constexpr __union_t& operator=(const __union_t&) = default;
-
- template <class... _Args>
- _LIBCPP_HIDE_FROM_ABI constexpr explicit __union_t(in_place_t, _Args&&... __args)
- : __val_(std::forward<_Args>(__args)...) {}
-
- template <class... _Args>
- _LIBCPP_HIDE_FROM_ABI constexpr explicit __union_t(unexpect_t, _Args&&... __args)
- : __unex_(std::forward<_Args>(__args)...) {}
-
- template <class _Func, class... _Args>
- _LIBCPP_HIDE_FROM_ABI constexpr explicit __union_t(
- std::__expected_construct_in_place_from_invoke_tag, _Func&& __f, _Args&&... __args)
- : __val_(std::invoke(std::forward<_Func>(__f), std::forward<_Args>(__args)...)) {}
-
- template <class _Func, class... _Args>
- _LIBCPP_HIDE_FROM_ABI constexpr explicit __union_t(
- std::__expected_construct_unexpected_from_invoke_tag, _Func&& __f, _Args&&... __args)
- : __unex_(std::invoke(std::forward<_Func>(__f), std::forward<_Args>(__args)...)) {}
-
- template <class _Union>
- _LIBCPP_HIDE_FROM_ABI constexpr explicit __union_t(bool __has_val, _Union&& __other) {
- if (__has_val)
- std::construct_at(std::addressof(__val_), std::forward<_Union>(__other).__val_);
- else
- std::construct_at(std::addressof(__unex_), std::forward<_Union>(__other).__unex_);
- }
-
- _LIBCPP_HIDE_FROM_ABI constexpr ~__union_t()
- requires(is_trivially_destructible_v<_ValueType> && is_trivially_destructible_v<_ErrorType>)
- = default;
-
- // __repr's destructor handles this
- _LIBCPP_HIDE_FROM_ABI constexpr ~__union_t()
- requires(!is_trivially_destructible_v<_ValueType> || !is_trivially_destructible_v<_ErrorType>)
- {}
-
- _LIBCPP_NO_UNIQUE_ADDRESS _ValueType __val_;
- _LIBCPP_NO_UNIQUE_ADDRESS _ErrorType __unex_;
- };
-
- struct __repr {
- _LIBCPP_HIDE_FROM_ABI constexpr explicit __repr() = delete;
-
- template <class... _Args>
- _LIBCPP_HIDE_FROM_ABI constexpr explicit __repr(in_place_t __tag, _Args&&... __args)
- : __union_(__tag, std::forward<_Args>(__args)...), __has_val_(true) {}
-
- template <class... _Args>
- _LIBCPP_HIDE_FROM_ABI constexpr explicit __repr(unexpect_t __tag, _Args&&... __args)
- : __union_(__tag, std::forward<_Args>(__args)...), __has_val_(false) {}
-
- template <class... _Args>
- _LIBCPP_HIDE_FROM_ABI constexpr explicit __repr(
- std::__expected_construct_in_place_from_invoke_tag __tag, _Args&&... __args)
- : __union_(__tag, std::forward<_Args>(__args)...), __has_val_(true) {}
-
- template <class... _Args>
- _LIBCPP_HIDE_FROM_ABI constexpr explicit __repr(
- std::__expected_construct_unexpected_from_invoke_tag __tag, _Args&&... __args)
- : __union_(__tag, std::forward<_Args>(__args)...), __has_val_(false) {}
-
- template <class... _Args>
- _LIBCPP_HIDE_FROM_ABI constexpr explicit __repr(bool __has_val, _Args&&... __args)
- : __union_(__has_val, std::forward<_Args>(__args)...), __has_val_(__has_val) {}
-
- _LIBCPP_HIDE_FROM_ABI constexpr __repr(const __repr&) = delete;
- _LIBCPP_HIDE_FROM_ABI constexpr __repr(const __repr&)
- requires(is_copy_constructible_v<_Tp> &&
- is_copy_constructible_v<_Err> &&
- is_trivially_copy_constructible_v<_Tp> &&
- is_trivially_copy_constructible_v<_Err>)
- = default;
- _LIBCPP_HIDE_FROM_ABI constexpr __repr(__repr&&) = delete;
- _LIBCPP_HIDE_FROM_ABI constexpr __repr(__repr&&)
- requires(is_move_constructible_v<_Tp> && is_move_constructible_v<_Err>
- && is_trivially_move_constructible_v<_Tp> && is_trivially_move_constructible_v<_Err>)
- = default;
-
- _LIBCPP_HIDE_FROM_ABI constexpr __repr& operator=(const __repr&) = delete;
-
- _LIBCPP_HIDE_FROM_ABI constexpr ~__repr()
- requires(is_trivially_destructible_v<_Tp> && is_trivially_destructible_v<_Err>)
- = default;
-
- _LIBCPP_HIDE_FROM_ABI constexpr ~__repr()
- requires(!is_trivially_destructible_v<_Tp> || !is_trivially_destructible_v<_Err>)
- {
- if (__has_val_) {
- std::destroy_at(std::addressof(__union_.__val_));
- } else {
- std::destroy_at(std::addressof(__union_.__unex_));
- }
+ template <class, class>
+ friend class expected;
+
+ _LIBCPP_HIDE_FROM_ABI constexpr void __destroy_union_member()
+ requires(!is_trivially_destructible_v<_Err>)
+ {
+ if (!__has_val_) {
+ std::destroy_at(std::addressof(__union_.__unex_));
+ }
+ }
+
+ __expected_void_union_t<_Err> __union_;
+ _LIBCPP_NO_UNIQUE_ADDRESS bool __has_val_;
+};
+
+template <class _Err>
+struct __expected_void_repr<_Err, true> {
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_void_repr() = delete;
+
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_void_repr(in_place_t __tag)
+ : __union_(__tag), __has_val_(true) {}
+
+ template <class... _Args>
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_void_repr(unexpect_t __tag, _Args&&... __args)
+ : __union_(__tag, std::forward<_Args>(__args)...), __has_val_(false) {}
+
+ template <class... _Args>
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_void_repr(
+ std::__expected_construct_unexpected_from_invoke_tag __tag, _Args&&... __args)
+ : __union_(__tag, std::forward<_Args>(__args)...), __has_val_(false) {}
+
+ template <class _OtherUnion>
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_void_repr(bool __has_val, _OtherUnion&& __other)
+ : __union_(__make_expected_void_union<__expected_void_union_t<_Err>>(__has_val,
+ std::forward<_OtherUnion>(__other))),
+ __has_val_(__has_val) {}
+
+ _LIBCPP_HIDE_FROM_ABI constexpr __expected_void_repr(const __expected_void_repr&) = delete;
+ _LIBCPP_HIDE_FROM_ABI constexpr __expected_void_repr(const __expected_void_repr&)
+ requires(is_copy_constructible_v<_Err> && is_trivially_copy_constructible_v<_Err>)
+ = default;
+ _LIBCPP_HIDE_FROM_ABI constexpr __expected_void_repr(__expected_void_repr&&) = delete;
+ _LIBCPP_HIDE_FROM_ABI constexpr __expected_void_repr(__expected_void_repr&&)
+ requires(is_move_constructible_v<_Err> && is_trivially_move_constructible_v<_Err>)
+ = default;
+
+ _LIBCPP_HIDE_FROM_ABI constexpr __expected_void_repr& operator=(const __expected_void_repr&) = delete;
+
+ _LIBCPP_HIDE_FROM_ABI constexpr ~__expected_void_repr()
+ requires(is_trivially_destructible_v<_Err>)
+ = default;
+
+ _LIBCPP_HIDE_FROM_ABI constexpr ~__expected_void_repr()
+ requires(!is_trivially_destructible_v<_Err>)
+ {
+ if (!__has_val_) {
+ std::destroy_at(std::addressof(__union_.__unex_));
}
+ }
+
+private:
+ template <class, class>
+ friend class expected;
+
+ _LIBCPP_NO_UNIQUE_ADDRESS __expected_void_union_t<_Err> __union_;
+ _LIBCPP_NO_UNIQUE_ADDRESS bool __has_val_;
+};
+
+template <class _Err>
+struct __expected_void_base {
+protected:
+ template <class... _Args>
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_void_base(_Args&&... __args)
+ : __repr_(std::forward<_Args>(__args)...) {}
+
+ _LIBCPP_HIDE_FROM_ABI constexpr void __destroy() {
+ __repr_.__destroy_union();
+ }
+
+ template <class _Tag, class... _Args>
+ _LIBCPP_HIDE_FROM_ABI constexpr void __construct(_Tag __tag, _Args&&... __args)
+ {
+ __repr_.__construct_union(__tag, std::forward<_Args>(__args)...);
+ }
+
+ _LIBCPP_NO_UNIQUE_ADDRESS __expected_void_repr<_Err, false> __repr_;
+};
+
+template <class _Err>
+ requires (sizeof(__expected_void_repr<_Err, true>) == sizeof(__expected_void_union_t<_Err>))
+struct __expected_void_base<_Err> {
+protected:
+ template <class... _Args>
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_void_base(_Args&&... __args)
+ : __repr_(std::forward<_Args>(__args)...) {}
- private:
- template <class, class>
- friend class expected;
+ _LIBCPP_HIDE_FROM_ABI constexpr void __destroy() {
+ std::destroy_at(&__repr_);
+ }
- _LIBCPP_NO_UNIQUE_ADDRESS __union_t<_Tp, _Err> __union_;
- _LIBCPP_NO_UNIQUE_ADDRESS bool __has_val_;
- };
+ template <class _Tag, class... _Args>
+ _LIBCPP_HIDE_FROM_ABI constexpr void __construct(_Tag __tag, _Args&&... __args)
+ {
+ std::construct_at(&__repr_, __tag, std::forward<_Args>(__args)...);
+ }
- __repr __repr_;
+ __expected_void_repr<_Err, true> __repr_;
};
template <class _Tp, class _Err>
requires is_void_v<_Tp>
-class expected<_Tp, _Err> {
+class expected<_Tp, _Err> : private __expected_void_base<_Err> {
static_assert(__valid_std_unexpected<_Err>::value,
"[expected.void.general] A program that instantiates expected<T, E> with a E that is not a "
"valid argument for unexpected<E> is ill-formed");
@@ -1002,6 +1376,8 @@ class expected<_Tp, _Err> {
_Not<is_constructible<unexpected<_Err>, const expected<_Up, _OtherErr>&>>,
_Not<is_constructible<unexpected<_Err>, const expected<_Up, _OtherErr>>>>;
+ using __base = __expected_void_base<_Err>;
+
public:
using value_type = _Tp;
using error_type = _Err;
@@ -1011,7 +1387,7 @@ class expected<_Tp, _Err> {
using rebind = expected<_Up, error_type>;
// [expected.void.ctor], constructors
- _LIBCPP_HIDE_FROM_ABI constexpr expected() noexcept : __repr_(in_place) {}
+ _LIBCPP_HIDE_FROM_ABI constexpr expected() noexcept : __base(in_place) {}
_LIBCPP_HIDE_FROM_ABI constexpr expected(const expected&) = delete;
@@ -1022,7 +1398,7 @@ class expected<_Tp, _Err> {
_LIBCPP_HIDE_FROM_ABI constexpr expected(const expected& __rhs)
noexcept(is_nothrow_copy_constructible_v<_Err>) // strengthened
requires(is_copy_constructible_v<_Err> && !is_trivially_copy_constructible_v<_Err>)
- : __repr_(__rhs.__repr_.__has_val_, __rhs.__repr_.__union_) {}
+ : __base(__rhs.__repr_.__has_val_, __rhs.__repr_.__union_) {}
_LIBCPP_HIDE_FROM_ABI constexpr expected(expected&&)
requires(is_move_constructible_v<_Err> && is_trivially_move_constructible_v<_Err>)
@@ -1031,55 +1407,55 @@ class expected<_Tp, _Err> {
_LIBCPP_HIDE_FROM_ABI constexpr expected(expected&& __rhs)
noexcept(is_nothrow_move_constructible_v<_Err>)
requires(is_move_constructible_v<_Err> && !is_trivially_move_constructible_v<_Err>)
- : __repr_(__rhs.__repr_.__has_val_, std::move(__rhs.__repr_.__union_)) {}
+ : __base(__rhs.__repr_.__has_val_, std::move(__rhs.__repr_.__union_)) {}
template <class _Up, class _OtherErr>
requires __can_convert<_Up, _OtherErr, const _OtherErr&>::value
_LIBCPP_HIDE_FROM_ABI constexpr explicit(!is_convertible_v<const _OtherErr&, _Err>)
expected(const expected<_Up, _OtherErr>& __rhs)
noexcept(is_nothrow_constructible_v<_Err, const _OtherErr&>) // strengthened
- : __repr_(__rhs.__repr_.__has_val_, __rhs.__repr_.__union_) {}
+ : __base(__rhs.__repr_.__has_val_, __rhs.__repr_.__union_) {}
template <class _Up, class _OtherErr>
requires __can_convert<_Up, _OtherErr, _OtherErr>::value
_LIBCPP_HIDE_FROM_ABI constexpr explicit(!is_convertible_v<_OtherErr, _Err>)
expected(expected<_Up, _OtherErr>&& __rhs)
noexcept(is_nothrow_constructible_v<_Err, _OtherErr>) // strengthened
- : __repr_(__rhs.__repr_.__has_val_, std::move(__rhs.__repr_.__union_)) {}
+ : __base(__rhs.__repr_.__has_val_, std::move(__rhs.__repr_.__union_)) {}
template <class _OtherErr>
requires is_constructible_v<_Err, const _OtherErr&>
_LIBCPP_HIDE_FROM_ABI constexpr explicit(!is_convertible_v<const _OtherErr&, _Err>)
expected(const unexpected<_OtherErr>& __unex)
noexcept(is_nothrow_constructible_v<_Err, const _OtherErr&>) // strengthened
- : __repr_(unexpect, __unex.error()) {}
+ : __base(unexpect, __unex.error()) {}
template <class _OtherErr>
requires is_constructible_v<_Err, _OtherErr>
_LIBCPP_HIDE_FROM_ABI constexpr explicit(!is_convertible_v<_OtherErr, _Err>)
expected(unexpected<_OtherErr>&& __unex)
noexcept(is_nothrow_constructible_v<_Err, _OtherErr>) // strengthened
- : __repr_(unexpect, std::move(__unex.error())) {}
+ : __base(unexpect, std::move(__unex.error())) {}
- _LIBCPP_HIDE_FROM_ABI constexpr explicit expected(in_place_t) noexcept : __repr_(in_place) {}
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit expected(in_place_t) noexcept : __base(in_place) {}
template <class... _Args>
requires is_constructible_v<_Err, _Args...>
_LIBCPP_HIDE_FROM_ABI constexpr explicit expected(unexpect_t, _Args&&... __args)
noexcept(is_nothrow_constructible_v<_Err, _Args...>) // strengthened
- : __repr_(unexpect, std::forward<_Args>(__args)...) {}
+ : __base(unexpect, std::forward<_Args>(__args)...) {}
template <class _Up, class... _Args>
requires is_constructible_v< _Err, initializer_list<_Up>&, _Args... >
_LIBCPP_HIDE_FROM_ABI constexpr explicit expected(unexpect_t, initializer_list<_Up> __il, _Args&&... __args)
noexcept(is_nothrow_constructible_v<_Err, initializer_list<_Up>&, _Args...>) // strengthened
- : __repr_(unexpect, __il, std::forward<_Args>(__args)...) {}
+ : __base(unexpect, __il, std::forward<_Args>(__args)...) {}
private:
template <class _Func, class... _Args>
_LIBCPP_HIDE_FROM_ABI constexpr explicit expected(
__expected_construct_unexpected_from_invoke_tag __tag, _Func&& __f, _Args&&... __args)
- : __repr_(__tag, std::forward<_Func>(__f), std::forward<_Args>(__args)...) {}
+ : __base(__tag, std::forward<_Func>(__f), std::forward<_Args>(__args)...) {}
public:
// [expected.void.dtor], destructor
@@ -1090,17 +1466,16 @@ class expected<_Tp, _Err> {
// precondition: has_value()
template <class... _Args>
_LIBCPP_HIDE_FROM_ABI constexpr void __reinit_expected(unexpect_t, _Args&&... __args) {
- std::destroy_at(&__repr_);
- auto __trans =
- std::__make_exception_guard([&] { std::construct_at(&__repr_, in_place); });
- std::construct_at(&__repr_, unexpect, std::forward<_Args>(__args)...);
+ this->__destroy();
+ auto __trans = std::__make_exception_guard([&] { this->__construct(in_place); });
+ this->__construct(unexpect, std::forward<_Args>(__args)...);
__trans.__complete();
}
// precondition: !has_value()
_LIBCPP_HIDE_FROM_ABI constexpr void __reinit_expected(in_place_t) {
- std::destroy_at(&__repr_);
- std::construct_at(&__repr_, in_place);
+ this->__destroy();
+ this->__construct(in_place);
}
public:
@@ -1111,7 +1486,7 @@ class expected<_Tp, _Err> {
noexcept(is_nothrow_copy_assignable_v<_Err> && is_nothrow_copy_constructible_v<_Err>) // strengthened
requires(is_copy_assignable_v<_Err> && is_copy_constructible_v<_Err>)
{
- if (__repr_.__has_val_) {
+ if (this->__repr_.__has_val_) {
if (!__rhs.__repr_.__has_val_) {
__reinit_expected(unexpect, __rhs.__repr_.__union_.__unex_);
}
@@ -1119,7 +1494,7 @@ class expected<_Tp, _Err> {
if (__rhs.__repr_.__has_val_) {
__reinit_expected(in_place);
} else {
- __repr_.__union_.__unex_ = __rhs.__repr_.__union_.__unex_;
+ this->__repr_.__union_.__unex_ = __rhs.__repr_.__union_.__unex_;
}
}
return *this;
@@ -1133,7 +1508,7 @@ class expected<_Tp, _Err> {
requires(is_move_assignable_v<_Err> &&
is_move_constructible_v<_Err>)
{
- if (__repr_.__has_val_) {
+ if (this->__repr_.__has_val_) {
if (!__rhs.__repr_.__has_val_) {
__reinit_expected(unexpect, std::move(__rhs.__repr_.__union_.__unex_));
}
@@ -1141,7 +1516,7 @@ class expected<_Tp, _Err> {
if (__rhs.__repr_.__has_val_) {
__reinit_expected(in_place);
} else {
- __repr_.__union_.__unex_ = std::move(__rhs.__repr_.__union_.__unex_);
+ this->__repr_.__union_.__unex_ = std::move(__rhs.__repr_.__union_.__unex_);
}
}
return *this;
@@ -1150,10 +1525,10 @@ class expected<_Tp, _Err> {
template <class _OtherErr>
requires(is_constructible_v<_Err, const _OtherErr&> && is_assignable_v<_Err&, const _OtherErr&>)
_LIBCPP_HIDE_FROM_ABI constexpr expected& operator=(const unexpected<_OtherErr>& __un) {
- if (__repr_.__has_val_) {
+ if (this->__repr_.__has_val_) {
__reinit_expected(unexpect, __un.error());
} else {
- __repr_.__union_.__unex_ = __un.error();
+ this->__repr_.__union_.__unex_ = __un.error();
}
return *this;
}
@@ -1161,16 +1536,16 @@ class expected<_Tp, _Err> {
template <class _OtherErr>
requires(is_constructible_v<_Err, _OtherErr> && is_assignable_v<_Err&, _OtherErr>)
_LIBCPP_HIDE_FROM_ABI constexpr expected& operator=(unexpected<_OtherErr>&& __un) {
- if (__repr_.__has_val_) {
+ if (this->__repr_.__has_val_) {
__reinit_expected(unexpect, std::move(__un.error()));
} else {
- __repr_.__union_.__unex_ = std::move(__un.error());
+ this->__repr_.__union_.__unex_ = std::move(__un.error());
}
return *this;
}
_LIBCPP_HIDE_FROM_ABI constexpr void emplace() noexcept {
- if (!__repr_.__has_val_) {
+ if (!this->__repr_.__has_val_) {
__reinit_expected(in_place);
}
}
@@ -1187,7 +1562,7 @@ class expected<_Tp, _Err> {
__with_err.__reinit_expected(in_place);
};
- if (__repr_.__has_val_) {
+ if (this->__repr_.__has_val_) {
if (!__rhs.__repr_.__has_val_) {
__swap_val_unex_impl(*this, __rhs);
}
@@ -1196,7 +1571,7 @@ class expected<_Tp, _Err> {
__swap_val_unex_impl(__rhs, *this);
} else {
using std::swap;
- swap(__repr_.__union_.__unex_, __rhs.__repr_.__union_.__unex_);
+ swap(this->__repr_.__union_.__unex_, __rhs.__repr_.__union_.__unex_);
}
}
}
@@ -1209,44 +1584,44 @@ class expected<_Tp, _Err> {
}
// [expected.void.obs], observers
- _LIBCPP_HIDE_FROM_ABI constexpr explicit operator bool() const noexcept { return __repr_.__has_val_; }
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit operator bool() const noexcept { return this->__repr_.__has_val_; }
- _LIBCPP_HIDE_FROM_ABI constexpr bool has_value() const noexcept { return __repr_.__has_val_; }
+ _LIBCPP_HIDE_FROM_ABI constexpr bool has_value() const noexcept { return this->__repr_.__has_val_; }
_LIBCPP_HIDE_FROM_ABI constexpr void operator*() const noexcept {
- _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__repr_.__has_val_, "expected::operator* requires the expected to contain a value");
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(this->__repr_.__has_val_, "expected::operator* requires the expected to contain a value");
}
_LIBCPP_HIDE_FROM_ABI constexpr void value() const& {
- if (!__repr_.__has_val_) {
- std::__throw_bad_expected_access<_Err>(__repr_.__union_.__unex_);
+ if (!this->__repr_.__has_val_) {
+ std::__throw_bad_expected_access<_Err>(this->__repr_.__union_.__unex_);
}
}
_LIBCPP_HIDE_FROM_ABI constexpr void value() && {
- if (!__repr_.__has_val_) {
- std::__throw_bad_expected_access<_Err>(std::move(__repr_.__union_.__unex_));
+ if (!this->__repr_.__has_val_) {
+ std::__throw_bad_expected_access<_Err>(std::move(this->__repr_.__union_.__unex_));
}
}
_LIBCPP_HIDE_FROM_ABI constexpr const _Err& error() const& noexcept {
- _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!__repr_.__has_val_, "expected::error requires the expected to contain an error");
- return __repr_.__union_.__unex_;
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!this->__repr_.__has_val_, "expected::error requires the expected to contain an error");
+ return this->__repr_.__union_.__unex_;
}
_LIBCPP_HIDE_FROM_ABI constexpr _Err& error() & noexcept {
- _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!__repr_.__has_val_, "expected::error requires the expected to contain an error");
- return __repr_.__union_.__unex_;
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!this->__repr_.__has_val_, "expected::error requires the expected to contain an error");
+ return this->__repr_.__union_.__unex_;
}
_LIBCPP_HIDE_FROM_ABI constexpr const _Err&& error() const&& noexcept {
- _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!__repr_.__has_val_, "expected::error requires the expected to contain an error");
- return std::move(__repr_.__union_.__unex_);
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!this->__repr_.__has_val_, "expected::error requires the expected to contain an error");
+ return std::move(this->__repr_.__union_.__unex_);
}
_LIBCPP_HIDE_FROM_ABI constexpr _Err&& error() && noexcept {
- _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!__repr_.__has_val_, "expected::error requires the expected to contain an error");
- return std::move(__repr_.__union_.__unex_);
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!this->__repr_.__has_val_, "expected::error requires the expected to contain an error");
+ return std::move(this->__repr_.__union_.__unex_);
}
template <class _Up = _Err>
@@ -1493,133 +1868,6 @@ class expected<_Tp, _Err> {
_LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const expected& __x, const unexpected<_E2>& __y) {
return !__x.__repr_.__has_val_ && static_cast<bool>(__x.__repr_.__union_.__unex_ == __y.error());
}
-
-private:
- struct __empty_t {};
-
- template <class _ErrorType>
- union __union_t {
- _LIBCPP_HIDE_FROM_ABI constexpr __union_t() : __empty_() {}
-
- template <class... _Args>
- _LIBCPP_HIDE_FROM_ABI constexpr explicit __union_t(unexpect_t, _Args&&... __args)
- : __unex_(std::forward<_Args>(__args)...) {}
-
- template <class _Func, class... _Args>
- _LIBCPP_HIDE_FROM_ABI constexpr explicit __union_t(
- __expected_construct_unexpected_from_invoke_tag, _Func&& __f, _Args&&... __args)
- : __unex_(std::invoke(std::forward<_Func>(__f), std::forward<_Args>(__args)...)) {}
-
- template <class _Union>
- _LIBCPP_HIDE_FROM_ABI constexpr explicit __union_t(bool __has_val, _Union&& __other) {
- if (__has_val)
- std::construct_at(std::addressof(__empty_));
- else
- std::construct_at(std::addressof(__unex_), std::forward<_Union>(__other).__unex_);
- }
-
- _LIBCPP_HIDE_FROM_ABI constexpr ~__union_t()
- requires(is_trivially_destructible_v<_ErrorType>)
- = default;
-
- // __repr's destructor handles this
- _LIBCPP_HIDE_FROM_ABI constexpr ~__union_t() {}
-
- __empty_t __empty_;
- _ErrorType __unex_;
- };
-
- // use named union because [[no_unique_address]] cannot be applied to an unnamed union,
- // also guaranteed elision into a potentially-overlapping subobject is unsettled (and
- // it's not clear that it's implementable, given that the function is allowed to clobber
- // the tail padding) - see https://github.com/itanium-cxx-abi/cxx-abi/issues/107.
- template <class _ErrorType>
- requires is_trivially_move_constructible_v<_ErrorType>
- union __union_t<_ErrorType> {
- _LIBCPP_HIDE_FROM_ABI constexpr __union_t() : __empty_() {}
- _LIBCPP_HIDE_FROM_ABI constexpr __union_t(const __union_t&) = default;
- _LIBCPP_HIDE_FROM_ABI constexpr __union_t& operator=(const __union_t&) = default;
-
- template <class... _Args>
- _LIBCPP_HIDE_FROM_ABI constexpr explicit __union_t(unexpect_t, _Args&&... __args)
- : __unex_(std::forward<_Args>(__args)...) {}
-
- template <class _Func, class... _Args>
- _LIBCPP_HIDE_FROM_ABI constexpr explicit __union_t(
- __expected_construct_unexpected_from_invoke_tag, _Func&& __f, _Args&&... __args)
- : __unex_(std::invoke(std::forward<_Func>(__f), std::forward<_Args>(__args)...)) {}
-
- template <class _Union>
- _LIBCPP_HIDE_FROM_ABI constexpr explicit __union_t(bool __has_val, _Union&& __other) {
- if (__has_val)
- std::construct_at(std::addressof(__empty_));
- else
- std::construct_at(std::addressof(__unex_), std::forward<_Union>(__other).__unex_);
- }
-
- _LIBCPP_HIDE_FROM_ABI constexpr ~__union_t()
- requires(is_trivially_destructible_v<_ErrorType>)
- = default;
-
- // __repr's destructor handles this
- _LIBCPP_HIDE_FROM_ABI constexpr ~__union_t()
- requires(!is_trivially_destructible_v<_ErrorType>)
- {}
-
- _LIBCPP_NO_UNIQUE_ADDRESS __empty_t __empty_;
- _LIBCPP_NO_UNIQUE_ADDRESS _ErrorType __unex_;
- };
-
- struct __repr {
- _LIBCPP_HIDE_FROM_ABI constexpr explicit __repr() = delete;
-
- _LIBCPP_HIDE_FROM_ABI constexpr explicit __repr(in_place_t) : __union_(), __has_val_(true) {}
-
- template <class... _Args>
- _LIBCPP_HIDE_FROM_ABI constexpr explicit __repr(unexpect_t __tag, _Args&&... __args)
- : __union_(__tag, std::forward<_Args>(__args)...), __has_val_(false) {}
-
- template <class... _Args>
- _LIBCPP_HIDE_FROM_ABI constexpr explicit __repr(
- std::__expected_construct_unexpected_from_invoke_tag __tag, _Args&&... __args)
- : __union_(__tag, std::forward<_Args>(__args)...), __has_val_(false) {}
-
- template <class... _Args>
- _LIBCPP_HIDE_FROM_ABI constexpr explicit __repr(bool __has_val, _Args&&... __args)
- : __union_(__has_val, std::forward<_Args>(__args)...), __has_val_(__has_val) {}
-
- _LIBCPP_HIDE_FROM_ABI constexpr __repr(const __repr&) = delete;
- _LIBCPP_HIDE_FROM_ABI constexpr __repr(const __repr&)
- requires(is_copy_constructible_v<_Err> && is_trivially_copy_constructible_v<_Err>)
- = default;
- _LIBCPP_HIDE_FROM_ABI constexpr __repr(__repr&&) = delete;
- _LIBCPP_HIDE_FROM_ABI constexpr __repr(__repr&&)
- requires(is_move_constructible_v<_Err> && is_trivially_move_constructible_v<_Err>)
- = default;
-
- _LIBCPP_HIDE_FROM_ABI constexpr __repr& operator=(const __repr&) = delete;
-
- _LIBCPP_HIDE_FROM_ABI constexpr ~__repr()
- requires(is_trivially_destructible_v<_Err>)
- = default;
-
- _LIBCPP_HIDE_FROM_ABI constexpr ~__repr()
- requires(!is_trivially_destructible_v<_Err>)
- {
- if (!__has_val_) {
- std::destroy_at(std::addressof(__union_.__unex_));
- }
- }
-
- private:
- template <class, class>
- friend class expected;
-
- _LIBCPP_NO_UNIQUE_ADDRESS __union_t<_Err> __union_;
- _LIBCPP_NO_UNIQUE_ADDRESS bool __has_val_;
- };
-
- __repr __repr_;
};
_LIBCPP_END_NAMESPACE_STD
diff --git a/libcxx/test/libcxx/utilities/expected/expected.expected/no_unique_address.compile.pass.cpp b/libcxx/test/libcxx/utilities/expected/expected.expected/no_unique_address.compile.pass.cpp
index 8eeec70ff0e42..a7ddd13e7930a 100644
--- a/libcxx/test/libcxx/utilities/expected/expected.expected/no_unique_address.compile.pass.cpp
+++ b/libcxx/test/libcxx/utilities/expected/expected.expected/no_unique_address.compile.pass.cpp
@@ -13,6 +13,7 @@
// test [[no_unique_address]] is applied to the union
#include <expected>
+#include <optional>
#include <memory>
struct Empty {};
@@ -50,5 +51,22 @@ static_assert(sizeof(std::expected<Empty, BoolWithPadding>) ==
// In this case, there should be tail padding in the `expected` because `A`
// itself does _not_ have tail padding.
-// XXX
-// static_assert(sizeof(std::expected<A, A>) > std::__libcpp_datasizeof<std::expected<A, A>>::value);
+static_assert(sizeof(std::expected<A, A>) > std::__libcpp_datasizeof<std::expected<A, A>>::value);
+
+// Test with some real types.
+static_assert(sizeof(std::expected<std::optional<int>, int>) == 8);
+static_assert(std::__libcpp_datasizeof<std::expected<std::optional<int>, int>>::value == 8);
+
+static_assert(sizeof(std::expected<int, std::optional<int>>) == 8);
+static_assert(std::__libcpp_datasizeof<std::expected<int, std::optional<int>>>::value == 8);
+
+static_assert(sizeof(std::expected<int, int>) == 8);
+static_assert(std::__libcpp_datasizeof<std::expected<int, int>>::value == 5);
+
+// clang-format off
+static_assert(std::__libcpp_datasizeof<int>::value == 4);
+static_assert(std::__libcpp_datasizeof<std::expected<int, int>>::value == 5);
+static_assert(std::__libcpp_datasizeof<std::expected<std::expected<int, int>, int>>::value == 8);
+static_assert(std::__libcpp_datasizeof<std::expected<std::expected<std::expected<int, int>, int>, int>>::value == 9);
+static_assert(std::__libcpp_datasizeof<std::expected<std::expected<std::expected<std::expected<int, int>, int>, int>, int>>::value == 12);
+// clang-format on
diff --git a/libcxx/test/libcxx/utilities/expected/expected.expected/transform_error.mandates.verify.cpp b/libcxx/test/libcxx/utilities/expected/expected.expected/transform_error.mandates.verify.cpp
index 965e82a7b4034..16faddb280d3a 100644
--- a/libcxx/test/libcxx/utilities/expected/expected.expected/transform_error.mandates.verify.cpp
+++ b/libcxx/test/libcxx/utilities/expected/expected.expected/transform_error.mandates.verify.cpp
@@ -48,6 +48,7 @@ void test() {
e.transform_error(return_unexpected<int&>); // expected-error-re@*:* {{static assertion failed {{.*}}The result of {{.*}} must be a valid template argument for unexpected}}
// expected-error-re@*:* {{{{(excess elements in struct initializer|no matching constructor for initialization of)}}{{.*}}}}
// expected-error-re@*:* {{static assertion failed {{.*}}[expected.object.general] A program that instantiates the definition of template expected<T, E> for {{.*}} is ill-formed.}}
+ // expected-error-re@*:* {{union member {{.*}} has reference type {{.*}}}}
e.transform_error(return_no_object<int&>); // expected-error-re@*:* {{static assertion failed {{.*}}The result of {{.*}} must be a valid template argument for unexpected}}
// expected-error-re@*:* {{{{(excess elements in struct initializer|no matching constructor for initialization of)}}{{.*}}}}
diff --git a/libcxx/test/libcxx/utilities/expected/expected.void/no_unique_address.compile.pass.cpp b/libcxx/test/libcxx/utilities/expected/expected.void/no_unique_address.compile.pass.cpp
index 2129aa7b2405c..fe4ef4f1e0e23 100644
--- a/libcxx/test/libcxx/utilities/expected/expected.void/no_unique_address.compile.pass.cpp
+++ b/libcxx/test/libcxx/utilities/expected/expected.void/no_unique_address.compile.pass.cpp
@@ -13,6 +13,7 @@
// test [[no_unique_address]] is applied to the union
#include <expected>
+#include <optional>
#include <memory>
struct Empty {};
@@ -44,5 +45,19 @@ static_assert(sizeof(std::expected<void, BoolWithPadding>) ==
// In this case, there should be tail padding in the `expected` because `A`
// itself does _not_ have tail padding.
-// XXX
-// static_assert(sizeof(std::expected<void, A>) > std::__libcpp_datasizeof<std::expected<void, A>>::value);
+static_assert(sizeof(std::expected<void, A>) > std::__libcpp_datasizeof<std::expected<void, A>>::value);
+
+// Test with some real types.
+static_assert(sizeof(std::expected<void, std::optional<int>>) == 8);
+static_assert(std::__libcpp_datasizeof<std::expected<void, std::optional<int>>>::value == 8);
+
+static_assert(sizeof(std::expected<void, int>) == 8);
+static_assert(std::__libcpp_datasizeof<std::expected<void, int>>::value == 5);
+
+// clang-format off
+static_assert(std::__libcpp_datasizeof<int>::value == 4);
+static_assert(std::__libcpp_datasizeof<std::expected<void, int>>::value == 5);
+static_assert(std::__libcpp_datasizeof<std::expected<void, std::expected<void, int>>>::value == 8);
+static_assert(std::__libcpp_datasizeof<std::expected<void, std::expected<void, std::expected<void, int>>>>::value == 9);
+static_assert(std::__libcpp_datasizeof<std::expected<void, std::expected<void, std::expected<void, std::expected<void, int>>>>>::value == 12);
+// clang-format on
diff --git a/libcxx/test/libcxx/utilities/expected/expected.void/transform_error.mandates.verify.cpp b/libcxx/test/libcxx/utilities/expected/expected.void/transform_error.mandates.verify.cpp
index 09aa1332e9800..7687a42cb1a86 100644
--- a/libcxx/test/libcxx/utilities/expected/expected.void/transform_error.mandates.verify.cpp
+++ b/libcxx/test/libcxx/utilities/expected/expected.void/transform_error.mandates.verify.cpp
@@ -48,6 +48,8 @@ void test() {
e.transform_error(return_unexpected<int&>); // expected-error-re@*:* {{static assertion failed {{.*}}The result of {{.*}} must be a valid template argument for unexpected}}
// expected-error-re@*:* {{{{(excess elements in struct initializer|no matching constructor for initialization of)}}{{.*}}}}
// expected-error-re@*:* {{static assertion failed {{.*}}A program that instantiates expected<T, E> with a E that is not a valid argument for unexpected<E> is ill-formed}}
+ // expected-error-re@*:* {{union member {{.*}} has reference type {{.*}}}}
+ // expected-error-re@*:* {{call to deleted constructor of {{.*}}}}
e.transform_error(return_no_object<int&>); // expected-error-re@*:* {{static assertion failed {{.*}}The result of {{.*}} must be a valid template argument for unexpected}}
// expected-error-re@*:* {{{{(excess elements in struct initializer|no matching constructor for initialization of)}}{{.*}}}}
>From 4b88ab35c8c2ff0070da08cc6efc1d6639fade67 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jan=20Kokem=C3=BCller?= <jan.kokemueller at gmail.com>
Date: Tue, 24 Oct 2023 20:09:26 +0200
Subject: [PATCH 18/37] try to make guaranteed copy elision work with GCC
Seems to be related to
<https://github.com/itanium-cxx-abi/cxx-abi/issues/107>
---
libcxx/include/__expected/expected.h | 96 +++++++++++++++++-----------
1 file changed, 58 insertions(+), 38 deletions(-)
diff --git a/libcxx/include/__expected/expected.h b/libcxx/include/__expected/expected.h
index acc68f9546548..ae670ac1d1a8a 100644
--- a/libcxx/include/__expected/expected.h
+++ b/libcxx/include/__expected/expected.h
@@ -88,15 +88,6 @@ _LIBCPP_HIDE_FROM_ABI void __throw_bad_expected_access(_Arg&& __arg) {
# endif
}
-template <class _Union, class _OtherUnion>
-_LIBCPP_HIDE_FROM_ABI constexpr _Union __make_expected_union(bool __has_val, _OtherUnion&& __other)
-{
- if (__has_val)
- return _Union(in_place, std::forward<_OtherUnion>(__other).__val_);
- else
- return _Union(unexpect, std::forward<_OtherUnion>(__other).__unex_);
-}
-
template <class _ValueType, class _ErrorType>
union __expected_union_t {
template <class... _Args>
@@ -192,9 +183,7 @@ struct __expected_repr {
template <class _OtherUnion>
_LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_repr(bool __has_val, _OtherUnion&& __other)
- : __union_(__make_expected_union<__expected_union_t<_Tp, _Err>>(__has_val,
- std::forward<_OtherUnion>(__other))),
- __has_val_(__has_val) {}
+ : __union_(__make_union(__has_val, std::forward<_OtherUnion>(__other))), __has_val_(__has_val) {}
_LIBCPP_HIDE_FROM_ABI constexpr __expected_repr(const __expected_repr&) = delete;
_LIBCPP_HIDE_FROM_ABI constexpr __expected_repr(const __expected_repr&)
@@ -260,6 +249,16 @@ struct __expected_repr {
}
}
+ template <class _OtherUnion>
+ _LIBCPP_HIDE_FROM_ABI static constexpr __expected_union_t<_Tp, _Err>
+ __make_union(bool __has_val, _OtherUnion&& __other)
+ {
+ if (__has_val)
+ return __expected_union_t<_Tp, _Err>(in_place, std::forward<_OtherUnion>(__other).__val_);
+ else
+ return __expected_union_t<_Tp, _Err>(unexpect, std::forward<_OtherUnion>(__other).__unex_);
+ }
+
__expected_union_t<_Tp, _Err> __union_;
_LIBCPP_NO_UNIQUE_ADDRESS bool __has_val_;
};
@@ -286,12 +285,6 @@ struct __expected_repr<_Tp, _Err, true> {
std::__expected_construct_unexpected_from_invoke_tag __tag, _Args&&... __args)
: __union_(__tag, std::forward<_Args>(__args)...), __has_val_(false) {}
- template <class _OtherUnion>
- _LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_repr(bool __has_val, _OtherUnion&& __other)
- : __union_(__make_expected_union<__expected_union_t<_Tp, _Err>>(__has_val,
- std::forward<_OtherUnion>(__other))),
- __has_val_(__has_val) {}
-
_LIBCPP_HIDE_FROM_ABI constexpr __expected_repr(const __expected_repr&) = delete;
_LIBCPP_HIDE_FROM_ABI constexpr __expected_repr(const __expected_repr&)
requires(is_copy_constructible_v<_Tp> && is_copy_constructible_v<_Err> &&
@@ -355,6 +348,10 @@ struct __expected_base<_Tp, _Err> {
_LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_base(_Args&&... __args)
: __repr_(std::forward<_Args>(__args)...) {}
+ template <class _OtherUnion>
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_base(bool __has_val, _OtherUnion&& __other)
+ : __repr_(__make_repr(__has_val, std::forward<_OtherUnion>(__other))) {}
+
_LIBCPP_HIDE_FROM_ABI constexpr void __destroy() {
std::destroy_at(&__repr_);
}
@@ -365,7 +362,20 @@ struct __expected_base<_Tp, _Err> {
std::construct_at(&__repr_, __tag, std::forward<_Args>(__args)...);
}
- __expected_repr<_Tp, _Err, true> __repr_;
+private:
+ using __repr = __expected_repr<_Tp, _Err, true>;
+
+ template <class _OtherUnion>
+ _LIBCPP_HIDE_FROM_ABI static constexpr __repr __make_repr(bool __has_val, _OtherUnion&& __other)
+ {
+ if (__has_val)
+ return __repr(in_place, std::forward<_OtherUnion>(__other).__val_);
+ else
+ return __repr(unexpect, std::forward<_OtherUnion>(__other).__unex_);
+ }
+
+protected:
+ __repr __repr_;
};
template <class _Tp, class _Err>
@@ -1110,15 +1120,6 @@ class expected : private __expected_base<_Tp, _Err> {
struct __expected_empty_t {};
-template <class _Union, class _OtherUnion>
-_LIBCPP_HIDE_FROM_ABI constexpr _Union __make_expected_void_union(bool __has_val, _OtherUnion&& __other)
-{
- if (__has_val)
- return _Union(in_place);
- else
- return _Union(unexpect, std::forward<_OtherUnion>(__other).__unex_);
-}
-
template <class _ErrorType>
union __expected_void_union_t {
_LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_void_union_t(in_place_t) : __empty_() {}
@@ -1196,9 +1197,7 @@ struct __expected_void_repr {
template <class _OtherUnion>
_LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_void_repr(bool __has_val, _OtherUnion&& __other)
- : __union_(__make_expected_void_union<__expected_void_union_t<_Err>>(__has_val,
- std::forward<_OtherUnion>(__other))),
- __has_val_(__has_val) {}
+ : __union_(__make_union(__has_val, std::forward<_OtherUnion>(__other))), __has_val_(__has_val) {}
_LIBCPP_HIDE_FROM_ABI constexpr __expected_void_repr(const __expected_void_repr&) = delete;
_LIBCPP_HIDE_FROM_ABI constexpr __expected_void_repr(const __expected_void_repr&)
@@ -1259,6 +1258,16 @@ struct __expected_void_repr {
}
}
+ template <class _OtherUnion>
+ _LIBCPP_HIDE_FROM_ABI static constexpr __expected_void_union_t<_Err>
+ __make_union(bool __has_val, _OtherUnion&& __other)
+ {
+ if (__has_val)
+ return __expected_void_union_t<_Err>(in_place);
+ else
+ return __expected_void_union_t<_Err>(unexpect, std::forward<_OtherUnion>(__other).__unex_);
+ }
+
__expected_void_union_t<_Err> __union_;
_LIBCPP_NO_UNIQUE_ADDRESS bool __has_val_;
};
@@ -1279,12 +1288,6 @@ struct __expected_void_repr<_Err, true> {
std::__expected_construct_unexpected_from_invoke_tag __tag, _Args&&... __args)
: __union_(__tag, std::forward<_Args>(__args)...), __has_val_(false) {}
- template <class _OtherUnion>
- _LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_void_repr(bool __has_val, _OtherUnion&& __other)
- : __union_(__make_expected_void_union<__expected_void_union_t<_Err>>(__has_val,
- std::forward<_OtherUnion>(__other))),
- __has_val_(__has_val) {}
-
_LIBCPP_HIDE_FROM_ABI constexpr __expected_void_repr(const __expected_void_repr&) = delete;
_LIBCPP_HIDE_FROM_ABI constexpr __expected_void_repr(const __expected_void_repr&)
requires(is_copy_constructible_v<_Err> && is_trivially_copy_constructible_v<_Err>)
@@ -1344,6 +1347,10 @@ struct __expected_void_base<_Err> {
_LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_void_base(_Args&&... __args)
: __repr_(std::forward<_Args>(__args)...) {}
+ template <class _OtherUnion>
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_void_base(bool __has_val, _OtherUnion&& __other)
+ : __repr_(__make_repr(__has_val, std::forward<_OtherUnion>(__other))) {}
+
_LIBCPP_HIDE_FROM_ABI constexpr void __destroy() {
std::destroy_at(&__repr_);
}
@@ -1354,7 +1361,20 @@ struct __expected_void_base<_Err> {
std::construct_at(&__repr_, __tag, std::forward<_Args>(__args)...);
}
- __expected_void_repr<_Err, true> __repr_;
+private:
+ using __repr = __expected_void_repr<_Err, true>;
+
+ template <class _OtherUnion>
+ _LIBCPP_HIDE_FROM_ABI static constexpr __repr __make_repr(bool __has_val, _OtherUnion&& __other)
+ {
+ if (__has_val)
+ return __repr(in_place);
+ else
+ return __repr(unexpect, std::forward<_OtherUnion>(__other).__unex_);
+ }
+
+protected:
+ __repr __repr_;
};
template <class _Tp, class _Err>
>From 880a1253bc2d911a7e03857693d548cf726be185 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jan=20Kokem=C3=BCller?= <jan.kokemueller at gmail.com>
Date: Tue, 24 Oct 2023 22:47:14 +0200
Subject: [PATCH 19/37] add includes for datasizeof
---
.../expected.expected/no_unique_address.compile.pass.cpp | 1 +
.../expected/expected.void/no_unique_address.compile.pass.cpp | 1 +
2 files changed, 2 insertions(+)
diff --git a/libcxx/test/libcxx/utilities/expected/expected.expected/no_unique_address.compile.pass.cpp b/libcxx/test/libcxx/utilities/expected/expected.expected/no_unique_address.compile.pass.cpp
index a7ddd13e7930a..e316f7a0fc1b1 100644
--- a/libcxx/test/libcxx/utilities/expected/expected.expected/no_unique_address.compile.pass.cpp
+++ b/libcxx/test/libcxx/utilities/expected/expected.expected/no_unique_address.compile.pass.cpp
@@ -12,6 +12,7 @@
// test [[no_unique_address]] is applied to the union
+#include <__type_traits/datasizeof.h>
#include <expected>
#include <optional>
#include <memory>
diff --git a/libcxx/test/libcxx/utilities/expected/expected.void/no_unique_address.compile.pass.cpp b/libcxx/test/libcxx/utilities/expected/expected.void/no_unique_address.compile.pass.cpp
index fe4ef4f1e0e23..e764dbd66acaa 100644
--- a/libcxx/test/libcxx/utilities/expected/expected.void/no_unique_address.compile.pass.cpp
+++ b/libcxx/test/libcxx/utilities/expected/expected.void/no_unique_address.compile.pass.cpp
@@ -12,6 +12,7 @@
// test [[no_unique_address]] is applied to the union
+#include <__type_traits/datasizeof.h>
#include <expected>
#include <optional>
#include <memory>
>From cbf7f1bef0aa1abcec166688ae03bd7bedc9f8f9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jan=20Kokem=C3=BCller?= <jan.kokemueller at gmail.com>
Date: Wed, 25 Oct 2023 19:23:18 +0200
Subject: [PATCH 20/37] use std::conditional for conditional
[[no_unique_address]]
---
libcxx/include/__expected/expected.h | 643 ++++++++----------
.../no_unique_address.compile.pass.cpp | 6 +-
.../transform_error.mandates.verify.cpp | 1 -
3 files changed, 302 insertions(+), 348 deletions(-)
diff --git a/libcxx/include/__expected/expected.h b/libcxx/include/__expected/expected.h
index ae670ac1d1a8a..a09a291de9ff9 100644
--- a/libcxx/include/__expected/expected.h
+++ b/libcxx/include/__expected/expected.h
@@ -88,261 +88,207 @@ _LIBCPP_HIDE_FROM_ABI void __throw_bad_expected_access(_Arg&& __arg) {
# endif
}
-template <class _ValueType, class _ErrorType>
-union __expected_union_t {
- template <class... _Args>
- _LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_union_t(in_place_t, _Args&&... __args)
- : __val_(std::forward<_Args>(__args)...) {}
+template <class _Tp>
+concept __expected_union_member_no_unique_address = is_nothrow_move_constructible_v<_Tp>;
- template <class... _Args>
- _LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_union_t(unexpect_t, _Args&&... __args)
- : __unex_(std::forward<_Args>(__args)...) {}
+struct __expected_wrap_invoke_tag {};
- template <class _Func, class... _Args>
- _LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_union_t(
- std::__expected_construct_in_place_from_invoke_tag, _Func&& __f, _Args&&... __args)
- : __val_(std::invoke(std::forward<_Func>(__f), std::forward<_Args>(__args)...)) {}
+template <class _Tp>
+struct __expected_wrap_unique {
+ template <class... _Args>
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_wrap_unique(_Args&&... __args)
+ : __v(std::forward<_Args>(__args)...) {}
template <class _Func, class... _Args>
- _LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_union_t(
- std::__expected_construct_unexpected_from_invoke_tag, _Func&& __f, _Args&&... __args)
- : __unex_(std::invoke(std::forward<_Func>(__f), std::forward<_Args>(__args)...)) {}
-
- _LIBCPP_HIDE_FROM_ABI constexpr ~__expected_union_t()
- requires(is_trivially_destructible_v<_ValueType> && is_trivially_destructible_v<_ErrorType>)
- = default;
-
- // __expected_repr's destructor handles this
- _LIBCPP_HIDE_FROM_ABI constexpr ~__expected_union_t() {}
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_wrap_unique(
+ __expected_wrap_invoke_tag, _Func&& __f, _Args&&... __args)
+ : __v(std::invoke(std::forward<_Func>(__f), std::forward<_Args>(__args)...)) {}
- // XXX Why are those not [[no_unique_address]]?
- _ValueType __val_;
- _ErrorType __unex_;
+ _Tp __v;
};
-// use named union because [[no_unique_address]] cannot be applied to an unnamed union,
-// also guaranteed elision into a potentially-overlapping subobject is unsettled (and
-// it's not clear that it's implementable, given that the function is allowed to clobber
-// the tail padding) - see https://github.com/itanium-cxx-abi/cxx-abi/issues/107.
-template <class _ValueType, class _ErrorType>
- requires(is_trivially_move_constructible_v<_ValueType> && is_trivially_move_constructible_v<_ErrorType>)
-union __expected_union_t<_ValueType, _ErrorType> {
- _LIBCPP_HIDE_FROM_ABI constexpr __expected_union_t(const __expected_union_t&) = default;
- _LIBCPP_HIDE_FROM_ABI constexpr __expected_union_t& operator=(const __expected_union_t&) = default;
-
- template <class... _Args>
- _LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_union_t(in_place_t, _Args&&... __args)
- : __val_(std::forward<_Args>(__args)...) {}
-
+template <class _Tp>
+struct __expected_wrap_no_unique {
template <class... _Args>
- _LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_union_t(unexpect_t, _Args&&... __args)
- : __unex_(std::forward<_Args>(__args)...) {}
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_wrap_no_unique(_Args&&... __args)
+ : __v(std::forward<_Args>(__args)...) {}
template <class _Func, class... _Args>
- _LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_union_t(
- std::__expected_construct_in_place_from_invoke_tag, _Func&& __f, _Args&&... __args)
- : __val_(std::invoke(std::forward<_Func>(__f), std::forward<_Args>(__args)...)) {}
-
- template <class _Func, class... _Args>
- _LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_union_t(
- std::__expected_construct_unexpected_from_invoke_tag, _Func&& __f, _Args&&... __args)
- : __unex_(std::invoke(std::forward<_Func>(__f), std::forward<_Args>(__args)...)) {}
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_wrap_no_unique(
+ __expected_wrap_invoke_tag, _Func&& __f, _Args&&... __args)
+ : __v(std::invoke(std::forward<_Func>(__f), std::forward<_Args>(__args)...)) {}
- _LIBCPP_HIDE_FROM_ABI constexpr ~__expected_union_t()
- requires(is_trivially_destructible_v<_ValueType> && is_trivially_destructible_v<_ErrorType>)
- = default;
-
- // __expected_repr's destructor handles this
- _LIBCPP_HIDE_FROM_ABI constexpr ~__expected_union_t() {}
-
- _LIBCPP_NO_UNIQUE_ADDRESS _ValueType __val_;
- _LIBCPP_NO_UNIQUE_ADDRESS _ErrorType __unex_;
+ _LIBCPP_NO_UNIQUE_ADDRESS _Tp __v;
};
-template <class _Tp, class _Err, bool _StuffTail = false>
-struct __expected_repr {
- _LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_repr() = delete;
-
- template <class... _Args>
- _LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_repr(in_place_t __tag, _Args&&... __args)
- : __union_(__tag, std::forward<_Args>(__args)...), __has_val_(true) {}
-
- template <class... _Args>
- _LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_repr(unexpect_t __tag, _Args&&... __args)
- : __union_(__tag, std::forward<_Args>(__args)...), __has_val_(false) {}
-
- template <class... _Args>
- _LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_repr(
- std::__expected_construct_in_place_from_invoke_tag __tag, _Args&&... __args)
- : __union_(__tag, std::forward<_Args>(__args)...), __has_val_(true) {}
-
- template <class... _Args>
- _LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_repr(
- std::__expected_construct_unexpected_from_invoke_tag __tag, _Args&&... __args)
- : __union_(__tag, std::forward<_Args>(__args)...), __has_val_(false) {}
-
- template <class _OtherUnion>
- _LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_repr(bool __has_val, _OtherUnion&& __other)
- : __union_(__make_union(__has_val, std::forward<_OtherUnion>(__other))), __has_val_(__has_val) {}
-
- _LIBCPP_HIDE_FROM_ABI constexpr __expected_repr(const __expected_repr&) = delete;
- _LIBCPP_HIDE_FROM_ABI constexpr __expected_repr(const __expected_repr&)
- requires(is_copy_constructible_v<_Tp> && is_copy_constructible_v<_Err> &&
- is_trivially_copy_constructible_v<_Tp> && is_trivially_copy_constructible_v<_Err>)
- = default;
- _LIBCPP_HIDE_FROM_ABI constexpr __expected_repr(__expected_repr&&) = delete;
- _LIBCPP_HIDE_FROM_ABI constexpr __expected_repr(__expected_repr&&)
- requires(is_move_constructible_v<_Tp> && is_move_constructible_v<_Err> &&
- is_trivially_move_constructible_v<_Tp> && is_trivially_move_constructible_v<_Err>)
- = default;
-
- _LIBCPP_HIDE_FROM_ABI constexpr __expected_repr& operator=(const __expected_repr&) = delete;
-
- _LIBCPP_HIDE_FROM_ABI constexpr ~__expected_repr()
- requires(is_trivially_destructible_v<_Tp> && is_trivially_destructible_v<_Err>)
- = default;
-
- _LIBCPP_HIDE_FROM_ABI constexpr ~__expected_repr()
- requires(!is_trivially_destructible_v<_Tp> || !is_trivially_destructible_v<_Err>)
- {
- __destroy_union_member();
- }
-
- _LIBCPP_HIDE_FROM_ABI constexpr void __destroy_union()
- requires(is_trivially_destructible_v<_Tp> && is_trivially_destructible_v<_Err>)
- {
- std::destroy_at(&__union_);
- }
-
- _LIBCPP_HIDE_FROM_ABI constexpr void __destroy_union()
- requires(!is_trivially_destructible_v<_Tp> || !is_trivially_destructible_v<_Err>)
- {
- __destroy_union_member();
- std::destroy_at(&__union_);
- }
-
- template <class... _Args>
- _LIBCPP_HIDE_FROM_ABI constexpr void __construct_union(in_place_t, _Args&&... __args)
- {
- std::construct_at(&__union_, in_place, std::forward<_Args>(__args)...);
- __has_val_ = true;
- }
-
- template <class... _Args>
- _LIBCPP_HIDE_FROM_ABI constexpr void __construct_union(unexpect_t, _Args&&... __args)
- {
- std::construct_at(&__union_, unexpect, std::forward<_Args>(__args)...);
- __has_val_ = false;
- }
-
-private:
- template <class, class>
- friend class expected;
-
- _LIBCPP_HIDE_FROM_ABI constexpr void __destroy_union_member()
- requires(!is_trivially_destructible_v<_Tp> || !is_trivially_destructible_v<_Err>)
- {
- if (__has_val_) {
- std::destroy_at(std::addressof(__union_.__val_));
- } else {
- std::destroy_at(std::addressof(__union_.__unex_));
- }
- }
-
- template <class _OtherUnion>
- _LIBCPP_HIDE_FROM_ABI static constexpr __expected_union_t<_Tp, _Err>
- __make_union(bool __has_val, _OtherUnion&& __other)
- {
- if (__has_val)
- return __expected_union_t<_Tp, _Err>(in_place, std::forward<_OtherUnion>(__other).__val_);
- else
- return __expected_union_t<_Tp, _Err>(unexpect, std::forward<_OtherUnion>(__other).__unex_);
- }
-
- __expected_union_t<_Tp, _Err> __union_;
- _LIBCPP_NO_UNIQUE_ADDRESS bool __has_val_;
+template <bool _NoUnique, class _Tp>
+struct __expected_conditional_no_unique_address {
+ using __type = std::conditional<_NoUnique,
+ __expected_wrap_no_unique<_Tp>, __expected_wrap_unique<_Tp>>::type;
};
template <class _Tp, class _Err>
-struct __expected_repr<_Tp, _Err, true> {
- _LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_repr() = delete;
-
- template <class... _Args>
- _LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_repr(in_place_t __tag, _Args&&... __args)
- : __union_(__tag, std::forward<_Args>(__args)...), __has_val_(true) {}
-
- template <class... _Args>
- _LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_repr(unexpect_t __tag, _Args&&... __args)
- : __union_(__tag, std::forward<_Args>(__args)...), __has_val_(false) {}
-
- template <class... _Args>
- _LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_repr(
- std::__expected_construct_in_place_from_invoke_tag __tag, _Args&&... __args)
- : __union_(__tag, std::forward<_Args>(__args)...), __has_val_(true) {}
-
- template <class... _Args>
- _LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_repr(
- std::__expected_construct_unexpected_from_invoke_tag __tag, _Args&&... __args)
- : __union_(__tag, std::forward<_Args>(__args)...), __has_val_(false) {}
-
- _LIBCPP_HIDE_FROM_ABI constexpr __expected_repr(const __expected_repr&) = delete;
- _LIBCPP_HIDE_FROM_ABI constexpr __expected_repr(const __expected_repr&)
- requires(is_copy_constructible_v<_Tp> && is_copy_constructible_v<_Err> &&
- is_trivially_copy_constructible_v<_Tp> && is_trivially_copy_constructible_v<_Err>)
- = default;
- _LIBCPP_HIDE_FROM_ABI constexpr __expected_repr(__expected_repr&&) = delete;
- _LIBCPP_HIDE_FROM_ABI constexpr __expected_repr(__expected_repr&&)
- requires(is_move_constructible_v<_Tp> && is_move_constructible_v<_Err> &&
- is_trivially_move_constructible_v<_Tp> && is_trivially_move_constructible_v<_Err>)
- = default;
-
- _LIBCPP_HIDE_FROM_ABI constexpr __expected_repr& operator=(const __expected_repr&) = delete;
-
- _LIBCPP_HIDE_FROM_ABI constexpr ~__expected_repr()
- requires(is_trivially_destructible_v<_Tp> && is_trivially_destructible_v<_Err>)
- = default;
-
- _LIBCPP_HIDE_FROM_ABI constexpr ~__expected_repr()
- requires(!is_trivially_destructible_v<_Tp> || !is_trivially_destructible_v<_Err>)
+struct __expected_base {
+private:
+ // use named union because [[no_unique_address]] cannot be applied to an unnamed union,
+ // also guaranteed elision into a potentially-overlapping subobject is unsettled (and
+ // it's not clear that it's implementable, given that the function is allowed to clobber
+ // the tail padding) - see https://github.com/itanium-cxx-abi/cxx-abi/issues/107.
+ union __union_t {
+ _LIBCPP_HIDE_FROM_ABI constexpr __union_t(const __union_t&) = default;
+ _LIBCPP_HIDE_FROM_ABI constexpr __union_t(__union_t&&) = default;
+ _LIBCPP_HIDE_FROM_ABI constexpr __union_t& operator=(const __union_t&) = delete;
+
+ template <class... _Args>
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit __union_t(in_place_t, _Args&&... __args)
+ : __val_(std::forward<_Args>(__args)...) {}
+
+ template <class... _Args>
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit __union_t(unexpect_t, _Args&&... __args)
+ : __unex_(std::forward<_Args>(__args)...) {}
+
+ template <class _Func, class... _Args>
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit __union_t(
+ std::__expected_construct_in_place_from_invoke_tag, _Func&& __f, _Args&&... __args)
+ : __val_(__expected_wrap_invoke_tag{}, std::forward<_Func>(__f), std::forward<_Args>(__args)...) {}
+
+ template <class _Func, class... _Args>
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit __union_t(
+ std::__expected_construct_unexpected_from_invoke_tag, _Func&& __f, _Args&&... __args)
+ : __unex_(__expected_wrap_invoke_tag{}, std::forward<_Func>(__f), std::forward<_Args>(__args)...) {}
+
+ _LIBCPP_HIDE_FROM_ABI constexpr ~__union_t()
+ requires(is_trivially_destructible_v<_Tp> && is_trivially_destructible_v<_Err>)
+ = default;
+
+ // __repr's destructor handles this
+ _LIBCPP_HIDE_FROM_ABI constexpr ~__union_t() {}
+
+ _LIBCPP_NO_UNIQUE_ADDRESS __expected_conditional_no_unique_address<
+ __expected_union_member_no_unique_address<_Tp>, _Tp>::__type __val_;
+ _LIBCPP_NO_UNIQUE_ADDRESS __expected_conditional_no_unique_address<
+ __expected_union_member_no_unique_address<_Err>, _Err>::__type __unex_;
+ };
+
+ _LIBCPP_HIDE_FROM_ABI static constexpr bool __can_stuff_tail()
{
- if (__has_val_) {
- std::destroy_at(std::addressof(__union_.__val_));
- } else {
- std::destroy_at(std::addressof(__union_.__unex_));
+ struct __x {
+ private:
+ _LIBCPP_NO_UNIQUE_ADDRESS __union_t __union;
+ _LIBCPP_NO_UNIQUE_ADDRESS bool __has_val;
+ };
+ return sizeof(__x) == sizeof(__union_t);
+ }
+
+ struct __repr {
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit __repr() = delete;
+
+ template <class... _Args>
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit __repr(in_place_t __tag, _Args&&... __args)
+ : __union_(__tag, std::forward<_Args>(__args)...), __has_val_(true) {}
+
+ template <class... _Args>
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit __repr(unexpect_t __tag, _Args&&... __args)
+ : __union_(__tag, std::forward<_Args>(__args)...), __has_val_(false) {}
+
+ template <class... _Args>
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit __repr(
+ std::__expected_construct_in_place_from_invoke_tag __tag, _Args&&... __args)
+ : __union_(__tag, std::forward<_Args>(__args)...), __has_val_(true) {}
+
+ template <class... _Args>
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit __repr(
+ std::__expected_construct_unexpected_from_invoke_tag __tag, _Args&&... __args)
+ : __union_(__tag, std::forward<_Args>(__args)...), __has_val_(false) {}
+
+ template <class _OtherUnion>
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit __repr(bool __has_val, _OtherUnion&& __other)
+ requires(!__can_stuff_tail())
+ : __union_(__expected_wrap_invoke_tag{},
+ [&] { return __make_union(__has_val, std::forward<_OtherUnion>(__other)); }),
+ __has_val_(__has_val) {}
+
+ _LIBCPP_HIDE_FROM_ABI constexpr __repr(const __repr&) = delete;
+ _LIBCPP_HIDE_FROM_ABI constexpr __repr(const __repr&)
+ requires(is_copy_constructible_v<_Tp> && is_copy_constructible_v<_Err> &&
+ is_trivially_copy_constructible_v<_Tp> && is_trivially_copy_constructible_v<_Err>)
+ = default;
+ _LIBCPP_HIDE_FROM_ABI constexpr __repr(__repr&&) = delete;
+ _LIBCPP_HIDE_FROM_ABI constexpr __repr(__repr&&)
+ requires(is_move_constructible_v<_Tp> && is_move_constructible_v<_Err> &&
+ is_trivially_move_constructible_v<_Tp> && is_trivially_move_constructible_v<_Err>)
+ = default;
+
+ _LIBCPP_HIDE_FROM_ABI constexpr __repr& operator=(const __repr&) = delete;
+
+ _LIBCPP_HIDE_FROM_ABI constexpr ~__repr()
+ requires(is_trivially_destructible_v<_Tp> && is_trivially_destructible_v<_Err>)
+ = default;
+
+ _LIBCPP_HIDE_FROM_ABI constexpr ~__repr()
+ requires(!is_trivially_destructible_v<_Tp> || !is_trivially_destructible_v<_Err>)
+ {
+ __destroy_union_member();
+ }
+
+ _LIBCPP_HIDE_FROM_ABI constexpr void __destroy_union()
+ requires(!__can_stuff_tail() && (is_trivially_destructible_v<_Tp> && is_trivially_destructible_v<_Err>))
+ {
+ std::destroy_at(&__union_.__v);
+ }
+
+ _LIBCPP_HIDE_FROM_ABI constexpr void __destroy_union()
+ requires(!__can_stuff_tail() && (!is_trivially_destructible_v<_Tp> || !is_trivially_destructible_v<_Err>))
+ {
+ __destroy_union_member();
+ std::destroy_at(&__union_.__v);
+ }
+
+ template <class... _Args>
+ _LIBCPP_HIDE_FROM_ABI constexpr void __construct_union(in_place_t, _Args&&... __args)
+ requires(!__can_stuff_tail())
+ {
+ std::construct_at(&__union_.__v, in_place, std::forward<_Args>(__args)...);
+ __has_val_ = true;
+ }
+
+ template <class... _Args>
+ _LIBCPP_HIDE_FROM_ABI constexpr void __construct_union(unexpect_t, _Args&&... __args)
+ requires(!__can_stuff_tail())
+ {
+ std::construct_at(&__union_.__v, unexpect, std::forward<_Args>(__args)...);
+ __has_val_ = false;
+ }
+
+ private:
+ template <class, class>
+ friend class expected;
+
+ _LIBCPP_HIDE_FROM_ABI constexpr void __destroy_union_member()
+ requires(!is_trivially_destructible_v<_Tp> || !is_trivially_destructible_v<_Err>)
+ {
+ if (__has_val_) {
+ std::destroy_at(std::addressof(__union_.__v.__val_));
+ } else {
+ std::destroy_at(std::addressof(__union_.__v.__unex_));
+ }
}
- }
-
-private:
- template <class, class>
- friend class expected;
-
- _LIBCPP_NO_UNIQUE_ADDRESS __expected_union_t<_Tp, _Err> __union_;
- _LIBCPP_NO_UNIQUE_ADDRESS bool __has_val_;
-};
-
-template <class _Tp, class _Err>
-struct __expected_base {
-protected:
- template <class... _Args>
- _LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_base(_Args&&... __args)
- : __repr_(std::forward<_Args>(__args)...) {}
- _LIBCPP_HIDE_FROM_ABI constexpr void __destroy() {
- __repr_.__destroy_union();
- }
-
- template <class _Tag, class... _Args>
- _LIBCPP_HIDE_FROM_ABI constexpr void __construct(_Tag __tag, _Args&&... __args)
- {
- __repr_.__construct_union(__tag, std::forward<_Args>(__args)...);
- }
+ template <class _OtherUnion>
+ _LIBCPP_HIDE_FROM_ABI static constexpr __union_t __make_union(bool __has_val, _OtherUnion&& __other)
+ requires(!__can_stuff_tail())
+ {
+ if (__has_val)
+ return __union_t(in_place, std::forward<_OtherUnion>(__other).__val_.__v);
+ else
+ return __union_t(unexpect, std::forward<_OtherUnion>(__other).__unex_.__v);
+ }
- _LIBCPP_NO_UNIQUE_ADDRESS __expected_repr<_Tp, _Err, false> __repr_;
-};
+ _LIBCPP_NO_UNIQUE_ADDRESS __expected_conditional_no_unique_address<
+ __can_stuff_tail(), __union_t>::__type __union_;
+ _LIBCPP_NO_UNIQUE_ADDRESS bool __has_val_;
+ };
-template <class _Tp, class _Err>
- requires (sizeof(__expected_repr<_Tp, _Err, true>) == sizeof(__expected_union_t<_Tp, _Err>))
-struct __expected_base<_Tp, _Err> {
protected:
template <class... _Args>
_LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_base(_Args&&... __args)
@@ -350,32 +296,39 @@ struct __expected_base<_Tp, _Err> {
template <class _OtherUnion>
_LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_base(bool __has_val, _OtherUnion&& __other)
- : __repr_(__make_repr(__has_val, std::forward<_OtherUnion>(__other))) {}
+ requires(__can_stuff_tail())
+ : __repr_(__expected_wrap_invoke_tag{},
+ [&] { return __make_repr(__has_val, std::forward<_OtherUnion>(__other)); }) {}
_LIBCPP_HIDE_FROM_ABI constexpr void __destroy() {
- std::destroy_at(&__repr_);
+ if constexpr (__can_stuff_tail())
+ std::destroy_at(&__repr_.__v);
+ else
+ __repr_.__v.__destroy_union();
}
template <class _Tag, class... _Args>
- _LIBCPP_HIDE_FROM_ABI constexpr void __construct(_Tag __tag, _Args&&... __args)
- {
- std::construct_at(&__repr_, __tag, std::forward<_Args>(__args)...);
+ _LIBCPP_HIDE_FROM_ABI constexpr void __construct(_Tag __tag, _Args&&... __args) {
+ if constexpr (__can_stuff_tail())
+ std::construct_at(&__repr_.__v, __tag, std::forward<_Args>(__args)...);
+ else
+ __repr_.__v.__construct_union(__tag, std::forward<_Args>(__args)...);
}
private:
- using __repr = __expected_repr<_Tp, _Err, true>;
-
template <class _OtherUnion>
_LIBCPP_HIDE_FROM_ABI static constexpr __repr __make_repr(bool __has_val, _OtherUnion&& __other)
+ requires(__can_stuff_tail())
{
if (__has_val)
- return __repr(in_place, std::forward<_OtherUnion>(__other).__val_);
+ return __repr(in_place, std::forward<_OtherUnion>(__other).__val_.__v);
else
- return __repr(unexpect, std::forward<_OtherUnion>(__other).__unex_);
+ return __repr(unexpect, std::forward<_OtherUnion>(__other).__unex_.__v);
}
protected:
- __repr __repr_;
+ _LIBCPP_NO_UNIQUE_ADDRESS __expected_conditional_no_unique_address<
+ !__can_stuff_tail(), __repr>::__type __repr_;
};
template <class _Tp, class _Err>
@@ -424,7 +377,7 @@ class expected : private __expected_base<_Tp, _Err> {
noexcept(is_nothrow_copy_constructible_v<_Tp> && is_nothrow_copy_constructible_v<_Err>) // strengthened
requires(is_copy_constructible_v<_Tp> && is_copy_constructible_v<_Err> &&
!(is_trivially_copy_constructible_v<_Tp> && is_trivially_copy_constructible_v<_Err>))
- : __base(__other.__repr_.__has_val_, __other.__repr_.__union_) { }
+ : __base(__other.__repr_.__v.__has_val_, __other.__repr_.__v.__union_.__v) { }
_LIBCPP_HIDE_FROM_ABI constexpr expected(expected&&)
requires(is_move_constructible_v<_Tp> && is_move_constructible_v<_Err>
@@ -435,7 +388,7 @@ class expected : private __expected_base<_Tp, _Err> {
noexcept(is_nothrow_move_constructible_v<_Tp> && is_nothrow_move_constructible_v<_Err>)
requires(is_move_constructible_v<_Tp> && is_move_constructible_v<_Err> &&
!(is_trivially_move_constructible_v<_Tp> && is_trivially_move_constructible_v<_Err>))
- : __base(__other.__repr_.__has_val_, std::move(__other.__repr_.__union_)) { }
+ : __base(__other.__repr_.__v.__has_val_, std::move(__other.__repr_.__v.__union_.__v)) { }
private:
template <class _Up, class _OtherErr, class _UfQual, class _OtherErrQual>
@@ -475,14 +428,14 @@ class expected : private __expected_base<_Tp, _Err> {
expected(const expected<_Up, _OtherErr>& __other)
noexcept(is_nothrow_constructible_v<_Tp, const _Up&> &&
is_nothrow_constructible_v<_Err, const _OtherErr&>) // strengthened
- : __base(__other.__repr_.__has_val_, __other.__repr_.__union_) {}
+ : __base(__other.__repr_.__v.__has_val_, __other.__repr_.__v.__union_.__v) {}
template <class _Up, class _OtherErr>
requires __can_convert<_Up, _OtherErr, _Up, _OtherErr>::value
_LIBCPP_HIDE_FROM_ABI constexpr explicit(!is_convertible_v<_Up, _Tp> || !is_convertible_v<_OtherErr, _Err>)
expected(expected<_Up, _OtherErr>&& __other)
noexcept(is_nothrow_constructible_v<_Tp, _Up> && is_nothrow_constructible_v<_Err, _OtherErr>) // strengthened
- : __base(__other.__repr_.__has_val_, std::move(__other.__repr_.__union_)) {}
+ : __base(__other.__repr_.__v.__has_val_, std::move(__other.__repr_.__v.__union_.__v)) {}
template <class _Up = _Tp>
requires(!is_same_v<remove_cvref_t<_Up>, in_place_t> && !is_same_v<expected, remove_cvref_t<_Up>> &&
@@ -575,16 +528,16 @@ class expected : private __expected_base<_Tp, _Err> {
(is_nothrow_move_constructible_v<_Tp> ||
is_nothrow_move_constructible_v<_Err>))
{
- if (this->__repr_.__has_val_ && __rhs.__repr_.__has_val_) {
- this->__repr_.__union_.__val_ = __rhs.__repr_.__union_.__val_;
- } else if (this->__repr_.__has_val_) {
+ if (this->__repr_.__v.__has_val_ && __rhs.__repr_.__v.__has_val_) {
+ this->__repr_.__v.__union_.__v.__val_.__v = __rhs.__repr_.__v.__union_.__v.__val_.__v;
+ } else if (this->__repr_.__v.__has_val_) {
__reinit_expected<unexpect_t, in_place_t, _Err, _Tp>(
- this->__repr_.__union_.__val_, __rhs.__repr_.__union_.__unex_);
- } else if (__rhs.__repr_.__has_val_) {
+ this->__repr_.__v.__union_.__v.__val_.__v, __rhs.__repr_.__v.__union_.__v.__unex_.__v);
+ } else if (__rhs.__repr_.__v.__has_val_) {
__reinit_expected<in_place_t, unexpect_t, _Tp, _Err>(
- this->__repr_.__union_.__unex_, __rhs.__repr_.__union_.__val_);
+ this->__repr_.__v.__union_.__v.__unex_.__v, __rhs.__repr_.__v.__union_.__v.__val_.__v);
} else {
- this->__repr_.__union_.__unex_ = __rhs.__repr_.__union_.__unex_;
+ this->__repr_.__v.__union_.__v.__unex_.__v = __rhs.__repr_.__v.__union_.__v.__unex_.__v;
}
return *this;
}
@@ -601,16 +554,16 @@ class expected : private __expected_base<_Tp, _Err> {
(is_nothrow_move_constructible_v<_Tp> ||
is_nothrow_move_constructible_v<_Err>))
{
- if (this->__repr_.__has_val_ && __rhs.__repr_.__has_val_) {
- this->__repr_.__union_.__val_ = std::move(__rhs.__repr_.__union_.__val_);
- } else if (this->__repr_.__has_val_) {
+ if (this->__repr_.__v.__has_val_ && __rhs.__repr_.__v.__has_val_) {
+ this->__repr_.__v.__union_.__v.__val_.__v = std::move(__rhs.__repr_.__v.__union_.__v.__val_.__v);
+ } else if (this->__repr_.__v.__has_val_) {
__reinit_expected<unexpect_t, in_place_t, _Err, _Tp>(
- this->__repr_.__union_.__val_, std::move(__rhs.__repr_.__union_.__unex_));
- } else if (__rhs.__repr_.__has_val_) {
+ this->__repr_.__v.__union_.__v.__val_.__v, std::move(__rhs.__repr_.__v.__union_.__v.__unex_.__v));
+ } else if (__rhs.__repr_.__v.__has_val_) {
__reinit_expected<in_place_t, unexpect_t, _Tp, _Err>(
- this->__repr_.__union_.__unex_, std::move(__rhs.__repr_.__union_.__val_));
+ this->__repr_.__v.__union_.__v.__unex_.__v, std::move(__rhs.__repr_.__v.__union_.__v.__val_.__v));
} else {
- this->__repr_.__union_.__unex_ = std::move(__rhs.__repr_.__union_.__unex_);
+ this->__repr_.__v.__union_.__v.__unex_.__v = std::move(__rhs.__repr_.__v.__union_.__v.__unex_.__v);
}
return *this;
}
@@ -625,11 +578,11 @@ class expected : private __expected_base<_Tp, _Err> {
is_nothrow_move_constructible_v<_Tp> ||
is_nothrow_move_constructible_v<_Err>))
{
- if (this->__repr_.__has_val_) {
- this->__repr_.__union_.__val_ = std::forward<_Up>(__v);
+ if (this->__repr_.__v.__has_val_) {
+ this->__repr_.__v.__union_.__v.__val_.__v = std::forward<_Up>(__v);
} else {
__reinit_expected<in_place_t, unexpect_t, _Tp, _Err>(
- this->__repr_.__union_.__unex_, std::forward<_Up>(__v));
+ this->__repr_.__v.__union_.__v.__unex_.__v, std::forward<_Up>(__v));
}
return *this;
}
@@ -648,11 +601,11 @@ class expected : private __expected_base<_Tp, _Err> {
template <class _OtherErr>
requires(__can_assign_from_unexpected<const _OtherErr&>)
_LIBCPP_HIDE_FROM_ABI constexpr expected& operator=(const unexpected<_OtherErr>& __un) {
- if (this->__repr_.__has_val_) {
+ if (this->__repr_.__v.__has_val_) {
__reinit_expected<unexpect_t, in_place_t, _Err, _Tp>(
- this->__repr_.__union_.__val_, __un.error());
+ this->__repr_.__v.__union_.__v.__val_.__v, __un.error());
} else {
- this->__repr_.__union_.__unex_ = __un.error();
+ this->__repr_.__v.__union_.__v.__unex_.__v = __un.error();
}
return *this;
}
@@ -660,11 +613,11 @@ class expected : private __expected_base<_Tp, _Err> {
template <class _OtherErr>
requires(__can_assign_from_unexpected<_OtherErr>)
_LIBCPP_HIDE_FROM_ABI constexpr expected& operator=(unexpected<_OtherErr>&& __un) {
- if (this->__repr_.__has_val_) {
+ if (this->__repr_.__v.__has_val_) {
__reinit_expected<unexpect_t, in_place_t, _Err, _Tp>(
- this->__repr_.__union_.__val_, std::move(__un.error()));
+ this->__repr_.__v.__union_.__v.__val_.__v, std::move(__un.error()));
} else {
- this->__repr_.__union_.__unex_ = std::move(__un.error());
+ this->__repr_.__v.__union_.__v.__unex_.__v = std::move(__un.error());
}
return *this;
}
@@ -674,7 +627,7 @@ class expected : private __expected_base<_Tp, _Err> {
_LIBCPP_HIDE_FROM_ABI constexpr _Tp& emplace(_Args&&... __args) noexcept {
this->__destroy();
this->__construct(in_place, std::forward<_Args>(__args)...);
- return __repr_.__union_.__val_;
+ return this->__repr_.__v.__union_.__v.__val_.__v;
}
template <class _Up, class... _Args>
@@ -682,7 +635,7 @@ class expected : private __expected_base<_Tp, _Err> {
_LIBCPP_HIDE_FROM_ABI constexpr _Tp& emplace(initializer_list<_Up> __il, _Args&&... __args) noexcept {
this->__destroy();
this->__construct(in_place, __il, std::forward<_Args>(__args)...);
- return __repr_.__union_.__val_;
+ return this->__repr_.__v.__union_.__v.__val_.__v;
}
public:
@@ -701,12 +654,12 @@ class expected : private __expected_base<_Tp, _Err> {
{
auto __swap_val_unex_impl = [](expected& __with_val, expected& __with_err) {
if constexpr (is_nothrow_move_constructible_v<_Err>) {
- _Err __tmp(std::move(__with_err.__repr_.__union_.__unex_));
+ _Err __tmp(std::move(__with_err.__repr_.__v.__union_.__v.__unex_.__v));
__with_err.__destroy();
auto __trans = std::__make_exception_guard([&] {
__with_err.__construct(unexpect, std::move(__tmp));
});
- __with_err.__construct(in_place, std::move(__with_val.__repr_.__union_.__val_));
+ __with_err.__construct(in_place, std::move(__with_val.__repr_.__v.__union_.__v.__val_.__v));
__trans.__complete();
__with_val.__destroy();
__with_val.__construct(unexpect, std::move(__tmp));
@@ -714,31 +667,31 @@ class expected : private __expected_base<_Tp, _Err> {
static_assert(is_nothrow_move_constructible_v<_Tp>,
"To provide strong exception guarantee, Tp has to satisfy `is_nothrow_move_constructible_v` so "
"that it can be reverted to the previous state in case an exception is thrown during swap.");
- _Tp __tmp(std::move(__with_val.__repr_.__union_.__val_));
+ _Tp __tmp(std::move(__with_val.__repr_.__v.__union_.__v.__val_.__v));
__with_val.__destroy();
auto __trans = std::__make_exception_guard([&] {
__with_val.__construct(in_place, std::move(__tmp));
});
- __with_val.__construct(unexpect, std::move(__with_err.__repr_.__union_.__unex_));
+ __with_val.__construct(unexpect, std::move(__with_err.__repr_.__v.__union_.__v.__unex_.__v));
__trans.__complete();
__with_err.__destroy();
__with_err.__construct(in_place, std::move(__tmp));
}
};
- if (this->__repr_.__has_val_) {
- if (__rhs.__repr_.__has_val_) {
+ if (this->__repr_.__v.__has_val_) {
+ if (__rhs.__repr_.__v.__has_val_) {
using std::swap;
- swap(this->__repr_.__union_.__val_, __rhs.__repr_.__union_.__val_);
+ swap(this->__repr_.__v.__union_.__v.__val_.__v, __rhs.__repr_.__v.__union_.__v.__val_.__v);
} else {
__swap_val_unex_impl(*this, __rhs);
}
} else {
- if (__rhs.__repr_.__has_val_) {
+ if (__rhs.__repr_.__v.__has_val_) {
__swap_val_unex_impl(__rhs, *this);
} else {
using std::swap;
- swap(this->__repr_.__union_.__unex_, __rhs.__repr_.__union_.__unex_);
+ swap(this->__repr_.__v.__union_.__v.__unex_.__v, __rhs.__repr_.__v.__union_.__v.__unex_.__v);
}
}
}
@@ -752,105 +705,105 @@ class expected : private __expected_base<_Tp, _Err> {
// [expected.object.obs], observers
_LIBCPP_HIDE_FROM_ABI constexpr const _Tp* operator->() const noexcept {
- _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(this->__repr_.__has_val_, "expected::operator-> requires the expected to contain a value");
- return std::addressof(this->__repr_.__union_.__val_);
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(this->__repr_.__v.__has_val_, "expected::operator-> requires the expected to contain a value");
+ return std::addressof(this->__repr_.__v.__union_.__v.__val_.__v);
}
_LIBCPP_HIDE_FROM_ABI constexpr _Tp* operator->() noexcept {
- _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(this->__repr_.__has_val_, "expected::operator-> requires the expected to contain a value");
- return std::addressof(this->__repr_.__union_.__val_);
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(this->__repr_.__v.__has_val_, "expected::operator-> requires the expected to contain a value");
+ return std::addressof(this->__repr_.__v.__union_.__v.__val_.__v);
}
_LIBCPP_HIDE_FROM_ABI constexpr const _Tp& operator*() const& noexcept {
- _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(this->__repr_.__has_val_, "expected::operator* requires the expected to contain a value");
- return this->__repr_.__union_.__val_;
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(this->__repr_.__v.__has_val_, "expected::operator* requires the expected to contain a value");
+ return this->__repr_.__v.__union_.__v.__val_.__v;
}
_LIBCPP_HIDE_FROM_ABI constexpr _Tp& operator*() & noexcept {
- _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(this->__repr_.__has_val_, "expected::operator* requires the expected to contain a value");
- return this->__repr_.__union_.__val_;
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(this->__repr_.__v.__has_val_, "expected::operator* requires the expected to contain a value");
+ return this->__repr_.__v.__union_.__v.__val_.__v;
}
_LIBCPP_HIDE_FROM_ABI constexpr const _Tp&& operator*() const&& noexcept {
- _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(this->__repr_.__has_val_, "expected::operator* requires the expected to contain a value");
- return std::move(this->__repr_.__union_.__val_);
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(this->__repr_.__v.__has_val_, "expected::operator* requires the expected to contain a value");
+ return std::move(this->__repr_.__v.__union_.__v.__val_.__v);
}
_LIBCPP_HIDE_FROM_ABI constexpr _Tp&& operator*() && noexcept {
- _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(this->__repr_.__has_val_, "expected::operator* requires the expected to contain a value");
- return std::move(this->__repr_.__union_.__val_);
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(this->__repr_.__v.__has_val_, "expected::operator* requires the expected to contain a value");
+ return std::move(this->__repr_.__v.__union_.__v.__val_.__v);
}
- _LIBCPP_HIDE_FROM_ABI constexpr explicit operator bool() const noexcept { return this->__repr_.__has_val_; }
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit operator bool() const noexcept { return this->__repr_.__v.__has_val_; }
- _LIBCPP_HIDE_FROM_ABI constexpr bool has_value() const noexcept { return this->__repr_.__has_val_; }
+ _LIBCPP_HIDE_FROM_ABI constexpr bool has_value() const noexcept { return this->__repr_.__v.__has_val_; }
_LIBCPP_HIDE_FROM_ABI constexpr const _Tp& value() const& {
static_assert(is_copy_constructible_v<_Err>, "error_type has to be copy constructible");
- if (!this->__repr_.__has_val_) {
+ if (!this->__repr_.__v.__has_val_) {
std::__throw_bad_expected_access<_Err>(std::as_const(error()));
}
- return this->__repr_.__union_.__val_;
+ return this->__repr_.__v.__union_.__v.__val_.__v;
}
_LIBCPP_HIDE_FROM_ABI constexpr _Tp& value() & {
static_assert(is_copy_constructible_v<_Err>, "error_type has to be copy constructible");
- if (!this->__repr_.__has_val_) {
+ if (!this->__repr_.__v.__has_val_) {
std::__throw_bad_expected_access<_Err>(std::as_const(error()));
}
- return this->__repr_.__union_.__val_;
+ return this->__repr_.__v.__union_.__v.__val_.__v;
}
_LIBCPP_HIDE_FROM_ABI constexpr const _Tp&& value() const&& {
static_assert(is_copy_constructible_v<_Err> && is_constructible_v<_Err, decltype(std::move(error()))>,
"error_type has to be both copy constructible and constructible from decltype(std::move(error()))");
- if (!this->__repr_.__has_val_) {
+ if (!this->__repr_.__v.__has_val_) {
std::__throw_bad_expected_access<_Err>(std::move(error()));
}
- return std::move(this->__repr_.__union_.__val_);
+ return std::move(this->__repr_.__v.__union_.__v.__val_.__v);
}
_LIBCPP_HIDE_FROM_ABI constexpr _Tp&& value() && {
static_assert(is_copy_constructible_v<_Err> && is_constructible_v<_Err, decltype(std::move(error()))>,
"error_type has to be both copy constructible and constructible from decltype(std::move(error()))");
- if (!this->__repr_.__has_val_) {
+ if (!this->__repr_.__v.__has_val_) {
std::__throw_bad_expected_access<_Err>(std::move(error()));
}
- return std::move(this->__repr_.__union_.__val_);
+ return std::move(this->__repr_.__v.__union_.__v.__val_.__v);
}
_LIBCPP_HIDE_FROM_ABI constexpr const _Err& error() const& noexcept {
- _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!this->__repr_.__has_val_, "expected::error requires the expected to contain an error");
- return this->__repr_.__union_.__unex_;
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!this->__repr_.__v.__has_val_, "expected::error requires the expected to contain an error");
+ return this->__repr_.__v.__union_.__v.__unex_.__v;
}
_LIBCPP_HIDE_FROM_ABI constexpr _Err& error() & noexcept {
- _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!this->__repr_.__has_val_, "expected::error requires the expected to contain an error");
- return this->__repr_.__union_.__unex_;
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!this->__repr_.__v.__has_val_, "expected::error requires the expected to contain an error");
+ return this->__repr_.__v.__union_.__v.__unex_.__v;
}
_LIBCPP_HIDE_FROM_ABI constexpr const _Err&& error() const&& noexcept {
- _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!this->__repr_.__has_val_, "expected::error requires the expected to contain an error");
- return std::move(this->__repr_.__union_.__unex_);
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!this->__repr_.__v.__has_val_, "expected::error requires the expected to contain an error");
+ return std::move(this->__repr_.__v.__union_.__v.__unex_.__v);
}
_LIBCPP_HIDE_FROM_ABI constexpr _Err&& error() && noexcept {
- _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!this->__repr_.__has_val_, "expected::error requires the expected to contain an error");
- return std::move(this->__repr_.__union_.__unex_);
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!this->__repr_.__v.__has_val_, "expected::error requires the expected to contain an error");
+ return std::move(this->__repr_.__v.__union_.__v.__unex_.__v);
}
template <class _Up>
_LIBCPP_HIDE_FROM_ABI constexpr _Tp value_or(_Up&& __v) const& {
static_assert(is_copy_constructible_v<_Tp>, "value_type has to be copy constructible");
static_assert(is_convertible_v<_Up, _Tp>, "argument has to be convertible to value_type");
- return this->__repr_.__has_val_ ? this->__repr_.__union_.__val_ : static_cast<_Tp>(std::forward<_Up>(__v));
+ return this->__repr_.__v.__has_val_ ? this->__repr_.__v.__union_.__v.__val_.__v : static_cast<_Tp>(std::forward<_Up>(__v));
}
template <class _Up>
_LIBCPP_HIDE_FROM_ABI constexpr _Tp value_or(_Up&& __v) && {
static_assert(is_move_constructible_v<_Tp>, "value_type has to be move constructible");
static_assert(is_convertible_v<_Up, _Tp>, "argument has to be convertible to value_type");
- return this->__repr_.__has_val_ ? std::move(this->__repr_.__union_.__val_) : static_cast<_Tp>(std::forward<_Up>(__v));
+ return this->__repr_.__v.__has_val_ ? std::move(this->__repr_.__v.__union_.__v.__val_.__v) : static_cast<_Tp>(std::forward<_Up>(__v));
}
template <class _Up = _Err>
@@ -880,7 +833,7 @@ class expected : private __expected_base<_Tp, _Err> {
static_assert(is_same_v<typename _Up::error_type, _Err>,
"The result of f(**this) must have the same error_type as this expected");
if (has_value()) {
- return std::invoke(std::forward<_Func>(__f), this->__repr_.__union_.__val_);
+ return std::invoke(std::forward<_Func>(__f), this->__repr_.__v.__union_.__v.__val_.__v);
}
return _Up(unexpect, error());
}
@@ -893,7 +846,7 @@ class expected : private __expected_base<_Tp, _Err> {
static_assert(is_same_v<typename _Up::error_type, _Err>,
"The result of f(**this) must have the same error_type as this expected");
if (has_value()) {
- return std::invoke(std::forward<_Func>(__f), this->__repr_.__union_.__val_);
+ return std::invoke(std::forward<_Func>(__f), this->__repr_.__v.__union_.__v.__val_.__v);
}
return _Up(unexpect, error());
}
@@ -907,7 +860,7 @@ class expected : private __expected_base<_Tp, _Err> {
static_assert(is_same_v<typename _Up::error_type, _Err>,
"The result of f(std::move(**this)) must have the same error_type as this expected");
if (has_value()) {
- return std::invoke(std::forward<_Func>(__f), std::move(this->__repr_.__union_.__val_));
+ return std::invoke(std::forward<_Func>(__f), std::move(this->__repr_.__v.__union_.__v.__val_.__v));
}
return _Up(unexpect, std::move(error()));
}
@@ -921,7 +874,7 @@ class expected : private __expected_base<_Tp, _Err> {
static_assert(is_same_v<typename _Up::error_type, _Err>,
"The result of f(std::move(**this)) must have the same error_type as this expected");
if (has_value()) {
- return std::invoke(std::forward<_Func>(__f), std::move(this->__repr_.__union_.__val_));
+ return std::invoke(std::forward<_Func>(__f), std::move(this->__repr_.__v.__union_.__v.__val_.__v));
}
return _Up(unexpect, std::move(error()));
}
@@ -934,7 +887,7 @@ class expected : private __expected_base<_Tp, _Err> {
static_assert(is_same_v<typename _Gp::value_type, _Tp>,
"The result of f(error()) must have the same value_type as this expected");
if (has_value()) {
- return _Gp(in_place, this->__repr_.__union_.__val_);
+ return _Gp(in_place, this->__repr_.__v.__union_.__v.__val_.__v);
}
return std::invoke(std::forward<_Func>(__f), error());
}
@@ -947,7 +900,7 @@ class expected : private __expected_base<_Tp, _Err> {
static_assert(is_same_v<typename _Gp::value_type, _Tp>,
"The result of f(error()) must have the same value_type as this expected");
if (has_value()) {
- return _Gp(in_place, this->__repr_.__union_.__val_);
+ return _Gp(in_place, this->__repr_.__v.__union_.__v.__val_.__v);
}
return std::invoke(std::forward<_Func>(__f), error());
}
@@ -961,7 +914,7 @@ class expected : private __expected_base<_Tp, _Err> {
static_assert(is_same_v<typename _Gp::value_type, _Tp>,
"The result of f(std::move(error())) must have the same value_type as this expected");
if (has_value()) {
- return _Gp(in_place, std::move(this->__repr_.__union_.__val_));
+ return _Gp(in_place, std::move(this->__repr_.__v.__union_.__v.__val_.__v));
}
return std::invoke(std::forward<_Func>(__f), std::move(error()));
}
@@ -975,7 +928,7 @@ class expected : private __expected_base<_Tp, _Err> {
static_assert(is_same_v<typename _Gp::value_type, _Tp>,
"The result of f(std::move(error())) must have the same value_type as this expected");
if (has_value()) {
- return _Gp(in_place, std::move(this->__repr_.__union_.__val_));
+ return _Gp(in_place, std::move(this->__repr_.__v.__union_.__v.__val_.__v));
}
return std::invoke(std::forward<_Func>(__f), std::move(error()));
}
@@ -988,9 +941,10 @@ class expected : private __expected_base<_Tp, _Err> {
return expected<_Up, _Err>(unexpect, error());
}
if constexpr (!is_void_v<_Up>) {
- return expected<_Up, _Err>(__expected_construct_in_place_from_invoke_tag{}, std::forward<_Func>(__f), this->__repr_.__union_.__val_);
+ return expected<_Up, _Err>(__expected_construct_in_place_from_invoke_tag{},
+ std::forward<_Func>(__f), this->__repr_.__v.__union_.__v.__val_.__v);
} else {
- std::invoke(std::forward<_Func>(__f), this->__repr_.__union_.__val_);
+ std::invoke(std::forward<_Func>(__f), this->__repr_.__v.__union_.__v.__val_.__v);
return expected<_Up, _Err>();
}
}
@@ -1003,9 +957,10 @@ class expected : private __expected_base<_Tp, _Err> {
return expected<_Up, _Err>(unexpect, error());
}
if constexpr (!is_void_v<_Up>) {
- return expected<_Up, _Err>(__expected_construct_in_place_from_invoke_tag{}, std::forward<_Func>(__f), this->__repr_.__union_.__val_);
+ return expected<_Up, _Err>(__expected_construct_in_place_from_invoke_tag{},
+ std::forward<_Func>(__f), this->__repr_.__v.__union_.__v.__val_.__v);
} else {
- std::invoke(std::forward<_Func>(__f), this->__repr_.__union_.__val_);
+ std::invoke(std::forward<_Func>(__f), this->__repr_.__v.__union_.__v.__val_.__v);
return expected<_Up, _Err>();
}
}
@@ -1018,10 +973,10 @@ class expected : private __expected_base<_Tp, _Err> {
return expected<_Up, _Err>(unexpect, std::move(error()));
}
if constexpr (!is_void_v<_Up>) {
- return expected<_Up, _Err>(
- __expected_construct_in_place_from_invoke_tag{}, std::forward<_Func>(__f), std::move(this->__repr_.__union_.__val_));
+ return expected<_Up, _Err>(__expected_construct_in_place_from_invoke_tag{},
+ std::forward<_Func>(__f), std::move(this->__repr_.__v.__union_.__v.__val_.__v));
} else {
- std::invoke(std::forward<_Func>(__f), std::move(this->__repr_.__union_.__val_));
+ std::invoke(std::forward<_Func>(__f), std::move(this->__repr_.__v.__union_.__v.__val_.__v));
return expected<_Up, _Err>();
}
}
@@ -1034,10 +989,10 @@ class expected : private __expected_base<_Tp, _Err> {
return expected<_Up, _Err>(unexpect, std::move(error()));
}
if constexpr (!is_void_v<_Up>) {
- return expected<_Up, _Err>(
- __expected_construct_in_place_from_invoke_tag{}, std::forward<_Func>(__f), std::move(this->__repr_.__union_.__val_));
+ return expected<_Up, _Err>(__expected_construct_in_place_from_invoke_tag{},
+ std::forward<_Func>(__f), std::move(this->__repr_.__v.__union_.__v.__val_.__v));
} else {
- std::invoke(std::forward<_Func>(__f), std::move(this->__repr_.__union_.__val_));
+ std::invoke(std::forward<_Func>(__f), std::move(this->__repr_.__v.__union_.__v.__val_.__v));
return expected<_Up, _Err>();
}
}
@@ -1049,7 +1004,7 @@ class expected : private __expected_base<_Tp, _Err> {
static_assert(__valid_std_unexpected<_Gp>::value,
"The result of f(error()) must be a valid template argument for unexpected");
if (has_value()) {
- return expected<_Tp, _Gp>(in_place, this->__repr_.__union_.__val_);
+ return expected<_Tp, _Gp>(in_place, this->__repr_.__v.__union_.__v.__val_.__v);
}
return expected<_Tp, _Gp>(__expected_construct_unexpected_from_invoke_tag{}, std::forward<_Func>(__f), error());
}
@@ -1061,7 +1016,7 @@ class expected : private __expected_base<_Tp, _Err> {
static_assert(__valid_std_unexpected<_Gp>::value,
"The result of f(error()) must be a valid template argument for unexpected");
if (has_value()) {
- return expected<_Tp, _Gp>(in_place, this->__repr_.__union_.__val_);
+ return expected<_Tp, _Gp>(in_place, this->__repr_.__v.__union_.__v.__val_.__v);
}
return expected<_Tp, _Gp>(__expected_construct_unexpected_from_invoke_tag{}, std::forward<_Func>(__f), error());
}
@@ -1073,7 +1028,7 @@ class expected : private __expected_base<_Tp, _Err> {
static_assert(__valid_std_unexpected<_Gp>::value,
"The result of f(std::move(error())) must be a valid template argument for unexpected");
if (has_value()) {
- return expected<_Tp, _Gp>(in_place, std::move(this->__repr_.__union_.__val_));
+ return expected<_Tp, _Gp>(in_place, std::move(this->__repr_.__v.__union_.__v.__val_.__v));
}
return expected<_Tp, _Gp>(
__expected_construct_unexpected_from_invoke_tag{}, std::forward<_Func>(__f), std::move(error()));
@@ -1086,7 +1041,7 @@ class expected : private __expected_base<_Tp, _Err> {
static_assert(__valid_std_unexpected<_Gp>::value,
"The result of f(std::move(error())) must be a valid template argument for unexpected");
if (has_value()) {
- return expected<_Tp, _Gp>(in_place, std::move(this->__repr_.__union_.__val_));
+ return expected<_Tp, _Gp>(in_place, std::move(this->__repr_.__v.__union_.__v.__val_.__v));
}
return expected<_Tp, _Gp>(
__expected_construct_unexpected_from_invoke_tag{}, std::forward<_Func>(__f), std::move(error()));
@@ -1096,25 +1051,25 @@ class expected : private __expected_base<_Tp, _Err> {
template <class _T2, class _E2>
requires(!is_void_v<_T2>)
_LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const expected& __x, const expected<_T2, _E2>& __y) {
- if (__x.__repr_.__has_val_ != __y.__repr_.__has_val_) {
+ if (__x.__repr_.__v.__has_val_ != __y.__repr_.__v.__has_val_) {
return false;
} else {
- if (__x.__repr_.__has_val_) {
- return __x.__repr_.__union_.__val_ == __y.__repr_.__union_.__val_;
+ if (__x.__repr_.__v.__has_val_) {
+ return __x.__repr_.__v.__union_.__v.__val_.__v == __y.__repr_.__v.__union_.__v.__val_.__v;
} else {
- return __x.__repr_.__union_.__unex_ == __y.__repr_.__union_.__unex_;
+ return __x.__repr_.__v.__union_.__v.__unex_.__v == __y.__repr_.__v.__union_.__v.__unex_.__v;
}
}
}
template <class _T2>
_LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const expected& __x, const _T2& __v) {
- return __x.__repr_.__has_val_ && static_cast<bool>(__x.__repr_.__union_.__val_ == __v);
+ return __x.__repr_.__v.__has_val_ && static_cast<bool>(__x.__repr_.__v.__union_.__v.__val_.__v == __v);
}
template <class _E2>
_LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const expected& __x, const unexpected<_E2>& __e) {
- return !__x.__repr_.__has_val_ && static_cast<bool>(__x.__repr_.__union_.__unex_ == __e.error());
+ return !__x.__repr_.__v.__has_val_ && static_cast<bool>(__x.__repr_.__v.__union_.__v.__unex_.__v == __e.error());
}
};
@@ -1137,7 +1092,7 @@ union __expected_void_union_t {
requires(is_trivially_destructible_v<_ErrorType>)
= default;
- // __expected_repr's destructor handles this
+ // __repr's destructor handles this
_LIBCPP_HIDE_FROM_ABI constexpr ~__expected_void_union_t() {}
// XXX: Why are those not [[no_unique_address]]?
@@ -1170,7 +1125,7 @@ union __expected_void_union_t<_ErrorType> {
requires(is_trivially_destructible_v<_ErrorType>)
= default;
- // __expected_repr's destructor handles this
+ // __repr's destructor handles this
_LIBCPP_HIDE_FROM_ABI constexpr ~__expected_void_union_t()
requires(!is_trivially_destructible_v<_ErrorType>)
{}
diff --git a/libcxx/test/libcxx/utilities/expected/expected.expected/no_unique_address.compile.pass.cpp b/libcxx/test/libcxx/utilities/expected/expected.expected/no_unique_address.compile.pass.cpp
index e316f7a0fc1b1..4d523d1ad6950 100644
--- a/libcxx/test/libcxx/utilities/expected/expected.expected/no_unique_address.compile.pass.cpp
+++ b/libcxx/test/libcxx/utilities/expected/expected.expected/no_unique_address.compile.pass.cpp
@@ -38,11 +38,11 @@ struct BoolWithPadding {
static_assert(sizeof(std::expected<Empty, Empty>) == sizeof(bool));
static_assert(sizeof(std::expected<Empty, A>) == 2 * sizeof(int) + alignof(std::expected<Empty, A>));
-static_assert(sizeof(std::expected<Empty, B>) == sizeof(B) + alignof(std::expected<Empty, B>));
+static_assert(sizeof(std::expected<Empty, B>) == sizeof(B));
static_assert(sizeof(std::expected<A, Empty>) == 2 * sizeof(int) + alignof(std::expected<A, Empty>));
static_assert(sizeof(std::expected<A, A>) == 2 * sizeof(int) + alignof(std::expected<A, A>));
-static_assert(sizeof(std::expected<B, Empty>) == sizeof(B) + alignof(std::expected<B, Empty>));
-static_assert(sizeof(std::expected<B, B>) == sizeof(B) + alignof(std::expected<B, B>));
+static_assert(sizeof(std::expected<B, Empty>) == sizeof(B));
+static_assert(sizeof(std::expected<B, B>) == sizeof(B));
// Check that `expected`'s datasize is large enough for the parameter type(s).
static_assert(sizeof(std::expected<BoolWithPadding, Empty>) ==
diff --git a/libcxx/test/libcxx/utilities/expected/expected.expected/transform_error.mandates.verify.cpp b/libcxx/test/libcxx/utilities/expected/expected.expected/transform_error.mandates.verify.cpp
index 16faddb280d3a..965e82a7b4034 100644
--- a/libcxx/test/libcxx/utilities/expected/expected.expected/transform_error.mandates.verify.cpp
+++ b/libcxx/test/libcxx/utilities/expected/expected.expected/transform_error.mandates.verify.cpp
@@ -48,7 +48,6 @@ void test() {
e.transform_error(return_unexpected<int&>); // expected-error-re@*:* {{static assertion failed {{.*}}The result of {{.*}} must be a valid template argument for unexpected}}
// expected-error-re@*:* {{{{(excess elements in struct initializer|no matching constructor for initialization of)}}{{.*}}}}
// expected-error-re@*:* {{static assertion failed {{.*}}[expected.object.general] A program that instantiates the definition of template expected<T, E> for {{.*}} is ill-formed.}}
- // expected-error-re@*:* {{union member {{.*}} has reference type {{.*}}}}
e.transform_error(return_no_object<int&>); // expected-error-re@*:* {{static assertion failed {{.*}}The result of {{.*}} must be a valid template argument for unexpected}}
// expected-error-re@*:* {{{{(excess elements in struct initializer|no matching constructor for initialization of)}}{{.*}}}}
>From f8321faa21e7dd76e97a34965a2acc3c3617360c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jan=20Kokem=C3=BCller?= <jan.kokemueller at gmail.com>
Date: Wed, 25 Oct 2023 19:39:46 +0200
Subject: [PATCH 21/37] slight refactoring
---
libcxx/include/__expected/expected.h | 85 +++++++++++++---------------
1 file changed, 40 insertions(+), 45 deletions(-)
diff --git a/libcxx/include/__expected/expected.h b/libcxx/include/__expected/expected.h
index a09a291de9ff9..2d660e67e7619 100644
--- a/libcxx/include/__expected/expected.h
+++ b/libcxx/include/__expected/expected.h
@@ -91,45 +91,42 @@ _LIBCPP_HIDE_FROM_ABI void __throw_bad_expected_access(_Arg&& __arg) {
template <class _Tp>
concept __expected_union_member_no_unique_address = is_nothrow_move_constructible_v<_Tp>;
-struct __expected_wrap_invoke_tag {};
+struct __expected_invoke_tag {};
-template <class _Tp>
-struct __expected_wrap_unique {
- template <class... _Args>
- _LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_wrap_unique(_Args&&... __args)
- : __v(std::forward<_Args>(__args)...) {}
+template <bool _NoUnique, class _Tp>
+class __expected_conditional_no_unique_address {
+ struct __unique {
+ template <class... _Args>
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit __unique(_Args&&... __args)
+ : __v(std::forward<_Args>(__args)...) {}
- template <class _Func, class... _Args>
- _LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_wrap_unique(
- __expected_wrap_invoke_tag, _Func&& __f, _Args&&... __args)
- : __v(std::invoke(std::forward<_Func>(__f), std::forward<_Args>(__args)...)) {}
+ template <class _Func, class... _Args>
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit __unique(
+ __expected_invoke_tag, _Func&& __f, _Args&&... __args)
+ : __v(std::invoke(std::forward<_Func>(__f), std::forward<_Args>(__args)...)) {}
- _Tp __v;
-};
+ _Tp __v;
+ };
-template <class _Tp>
-struct __expected_wrap_no_unique {
- template <class... _Args>
- _LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_wrap_no_unique(_Args&&... __args)
- : __v(std::forward<_Args>(__args)...) {}
+ struct __no_unique {
+ template <class... _Args>
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit __no_unique(_Args&&... __args)
+ : __v(std::forward<_Args>(__args)...) {}
- template <class _Func, class... _Args>
- _LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_wrap_no_unique(
- __expected_wrap_invoke_tag, _Func&& __f, _Args&&... __args)
- : __v(std::invoke(std::forward<_Func>(__f), std::forward<_Args>(__args)...)) {}
+ template <class _Func, class... _Args>
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit __no_unique(
+ __expected_invoke_tag, _Func&& __f, _Args&&... __args)
+ : __v(std::invoke(std::forward<_Func>(__f), std::forward<_Args>(__args)...)) {}
- _LIBCPP_NO_UNIQUE_ADDRESS _Tp __v;
-};
+ _LIBCPP_NO_UNIQUE_ADDRESS _Tp __v;
+ };
-template <bool _NoUnique, class _Tp>
-struct __expected_conditional_no_unique_address {
- using __type = std::conditional<_NoUnique,
- __expected_wrap_no_unique<_Tp>, __expected_wrap_unique<_Tp>>::type;
+public:
+ using __type = std::conditional<_NoUnique, __no_unique, __unique>::type;
};
template <class _Tp, class _Err>
-struct __expected_base {
-private:
+class __expected_base {
// use named union because [[no_unique_address]] cannot be applied to an unnamed union,
// also guaranteed elision into a potentially-overlapping subobject is unsettled (and
// it's not clear that it's implementable, given that the function is allowed to clobber
@@ -150,12 +147,12 @@ struct __expected_base {
template <class _Func, class... _Args>
_LIBCPP_HIDE_FROM_ABI constexpr explicit __union_t(
std::__expected_construct_in_place_from_invoke_tag, _Func&& __f, _Args&&... __args)
- : __val_(__expected_wrap_invoke_tag{}, std::forward<_Func>(__f), std::forward<_Args>(__args)...) {}
+ : __val_(__expected_invoke_tag{}, std::forward<_Func>(__f), std::forward<_Args>(__args)...) {}
template <class _Func, class... _Args>
_LIBCPP_HIDE_FROM_ABI constexpr explicit __union_t(
std::__expected_construct_unexpected_from_invoke_tag, _Func&& __f, _Args&&... __args)
- : __unex_(__expected_wrap_invoke_tag{}, std::forward<_Func>(__f), std::forward<_Args>(__args)...) {}
+ : __unex_(__expected_invoke_tag{}, std::forward<_Func>(__f), std::forward<_Args>(__args)...) {}
_LIBCPP_HIDE_FROM_ABI constexpr ~__union_t()
requires(is_trivially_destructible_v<_Tp> && is_trivially_destructible_v<_Err>)
@@ -204,7 +201,7 @@ struct __expected_base {
template <class _OtherUnion>
_LIBCPP_HIDE_FROM_ABI constexpr explicit __repr(bool __has_val, _OtherUnion&& __other)
requires(!__can_stuff_tail())
- : __union_(__expected_wrap_invoke_tag{},
+ : __union_(__expected_invoke_tag{},
[&] { return __make_union(__has_val, std::forward<_OtherUnion>(__other)); }),
__has_val_(__has_val) {}
@@ -289,6 +286,16 @@ struct __expected_base {
_LIBCPP_NO_UNIQUE_ADDRESS bool __has_val_;
};
+ template <class _OtherUnion>
+ _LIBCPP_HIDE_FROM_ABI static constexpr __repr __make_repr(bool __has_val, _OtherUnion&& __other)
+ requires(__can_stuff_tail())
+ {
+ if (__has_val)
+ return __repr(in_place, std::forward<_OtherUnion>(__other).__val_.__v);
+ else
+ return __repr(unexpect, std::forward<_OtherUnion>(__other).__unex_.__v);
+ }
+
protected:
template <class... _Args>
_LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_base(_Args&&... __args)
@@ -297,7 +304,7 @@ struct __expected_base {
template <class _OtherUnion>
_LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_base(bool __has_val, _OtherUnion&& __other)
requires(__can_stuff_tail())
- : __repr_(__expected_wrap_invoke_tag{},
+ : __repr_(__expected_invoke_tag{},
[&] { return __make_repr(__has_val, std::forward<_OtherUnion>(__other)); }) {}
_LIBCPP_HIDE_FROM_ABI constexpr void __destroy() {
@@ -315,18 +322,6 @@ struct __expected_base {
__repr_.__v.__construct_union(__tag, std::forward<_Args>(__args)...);
}
-private:
- template <class _OtherUnion>
- _LIBCPP_HIDE_FROM_ABI static constexpr __repr __make_repr(bool __has_val, _OtherUnion&& __other)
- requires(__can_stuff_tail())
- {
- if (__has_val)
- return __repr(in_place, std::forward<_OtherUnion>(__other).__val_.__v);
- else
- return __repr(unexpect, std::forward<_OtherUnion>(__other).__unex_.__v);
- }
-
-protected:
_LIBCPP_NO_UNIQUE_ADDRESS __expected_conditional_no_unique_address<
!__can_stuff_tail(), __repr>::__type __repr_;
};
>From 32b765e38c275e0f774ce8142826b2531fa50fc3 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jan=20Kokem=C3=BCller?= <jan.kokemueller at gmail.com>
Date: Wed, 25 Oct 2023 20:10:11 +0200
Subject: [PATCH 22/37] more refactoring
---
libcxx/include/__expected/expected.h | 45 +++++++++++++++-------------
1 file changed, 24 insertions(+), 21 deletions(-)
diff --git a/libcxx/include/__expected/expected.h b/libcxx/include/__expected/expected.h
index 2d660e67e7619..b4f3f3cfeef97 100644
--- a/libcxx/include/__expected/expected.h
+++ b/libcxx/include/__expected/expected.h
@@ -125,6 +125,17 @@ class __expected_conditional_no_unique_address {
using __type = std::conditional<_NoUnique, __no_unique, __unique>::type;
};
+template <class _Union>
+_LIBCPP_HIDE_FROM_ABI constexpr bool __expected_can_stuff_tail()
+{
+ struct __x {
+ private:
+ _LIBCPP_NO_UNIQUE_ADDRESS _Union __union;
+ _LIBCPP_NO_UNIQUE_ADDRESS bool __has_val;
+ };
+ return sizeof(__x) == sizeof(_Union);
+}
+
template <class _Tp, class _Err>
class __expected_base {
// use named union because [[no_unique_address]] cannot be applied to an unnamed union,
@@ -167,15 +178,7 @@ class __expected_base {
__expected_union_member_no_unique_address<_Err>, _Err>::__type __unex_;
};
- _LIBCPP_HIDE_FROM_ABI static constexpr bool __can_stuff_tail()
- {
- struct __x {
- private:
- _LIBCPP_NO_UNIQUE_ADDRESS __union_t __union;
- _LIBCPP_NO_UNIQUE_ADDRESS bool __has_val;
- };
- return sizeof(__x) == sizeof(__union_t);
- }
+ static constexpr bool __can_stuff_tail = __expected_can_stuff_tail<__union_t>();
struct __repr {
_LIBCPP_HIDE_FROM_ABI constexpr explicit __repr() = delete;
@@ -200,7 +203,7 @@ class __expected_base {
template <class _OtherUnion>
_LIBCPP_HIDE_FROM_ABI constexpr explicit __repr(bool __has_val, _OtherUnion&& __other)
- requires(!__can_stuff_tail())
+ requires(!__can_stuff_tail)
: __union_(__expected_invoke_tag{},
[&] { return __make_union(__has_val, std::forward<_OtherUnion>(__other)); }),
__has_val_(__has_val) {}
@@ -229,13 +232,13 @@ class __expected_base {
}
_LIBCPP_HIDE_FROM_ABI constexpr void __destroy_union()
- requires(!__can_stuff_tail() && (is_trivially_destructible_v<_Tp> && is_trivially_destructible_v<_Err>))
+ requires(!__can_stuff_tail && (is_trivially_destructible_v<_Tp> && is_trivially_destructible_v<_Err>))
{
std::destroy_at(&__union_.__v);
}
_LIBCPP_HIDE_FROM_ABI constexpr void __destroy_union()
- requires(!__can_stuff_tail() && (!is_trivially_destructible_v<_Tp> || !is_trivially_destructible_v<_Err>))
+ requires(!__can_stuff_tail && (!is_trivially_destructible_v<_Tp> || !is_trivially_destructible_v<_Err>))
{
__destroy_union_member();
std::destroy_at(&__union_.__v);
@@ -243,7 +246,7 @@ class __expected_base {
template <class... _Args>
_LIBCPP_HIDE_FROM_ABI constexpr void __construct_union(in_place_t, _Args&&... __args)
- requires(!__can_stuff_tail())
+ requires(!__can_stuff_tail)
{
std::construct_at(&__union_.__v, in_place, std::forward<_Args>(__args)...);
__has_val_ = true;
@@ -251,7 +254,7 @@ class __expected_base {
template <class... _Args>
_LIBCPP_HIDE_FROM_ABI constexpr void __construct_union(unexpect_t, _Args&&... __args)
- requires(!__can_stuff_tail())
+ requires(!__can_stuff_tail)
{
std::construct_at(&__union_.__v, unexpect, std::forward<_Args>(__args)...);
__has_val_ = false;
@@ -273,7 +276,7 @@ class __expected_base {
template <class _OtherUnion>
_LIBCPP_HIDE_FROM_ABI static constexpr __union_t __make_union(bool __has_val, _OtherUnion&& __other)
- requires(!__can_stuff_tail())
+ requires(!__can_stuff_tail)
{
if (__has_val)
return __union_t(in_place, std::forward<_OtherUnion>(__other).__val_.__v);
@@ -282,13 +285,13 @@ class __expected_base {
}
_LIBCPP_NO_UNIQUE_ADDRESS __expected_conditional_no_unique_address<
- __can_stuff_tail(), __union_t>::__type __union_;
+ __can_stuff_tail, __union_t>::__type __union_;
_LIBCPP_NO_UNIQUE_ADDRESS bool __has_val_;
};
template <class _OtherUnion>
_LIBCPP_HIDE_FROM_ABI static constexpr __repr __make_repr(bool __has_val, _OtherUnion&& __other)
- requires(__can_stuff_tail())
+ requires(__can_stuff_tail)
{
if (__has_val)
return __repr(in_place, std::forward<_OtherUnion>(__other).__val_.__v);
@@ -303,12 +306,12 @@ class __expected_base {
template <class _OtherUnion>
_LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_base(bool __has_val, _OtherUnion&& __other)
- requires(__can_stuff_tail())
+ requires(__can_stuff_tail)
: __repr_(__expected_invoke_tag{},
[&] { return __make_repr(__has_val, std::forward<_OtherUnion>(__other)); }) {}
_LIBCPP_HIDE_FROM_ABI constexpr void __destroy() {
- if constexpr (__can_stuff_tail())
+ if constexpr (__can_stuff_tail)
std::destroy_at(&__repr_.__v);
else
__repr_.__v.__destroy_union();
@@ -316,14 +319,14 @@ class __expected_base {
template <class _Tag, class... _Args>
_LIBCPP_HIDE_FROM_ABI constexpr void __construct(_Tag __tag, _Args&&... __args) {
- if constexpr (__can_stuff_tail())
+ if constexpr (__can_stuff_tail)
std::construct_at(&__repr_.__v, __tag, std::forward<_Args>(__args)...);
else
__repr_.__v.__construct_union(__tag, std::forward<_Args>(__args)...);
}
_LIBCPP_NO_UNIQUE_ADDRESS __expected_conditional_no_unique_address<
- !__can_stuff_tail(), __repr>::__type __repr_;
+ !__can_stuff_tail, __repr>::__type __repr_;
};
template <class _Tp, class _Err>
>From cbb661476c96bad0c94454ee191dd6af6f11807e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jan=20Kokem=C3=BCller?= <jan.kokemueller at gmail.com>
Date: Wed, 25 Oct 2023 21:00:34 +0200
Subject: [PATCH 23/37] refactor expected<void>
---
libcxx/include/__expected/expected.h | 643 ++++++++----------
.../no_unique_address.compile.pass.cpp | 2 +-
.../transform_error.mandates.verify.cpp | 2 +-
3 files changed, 287 insertions(+), 360 deletions(-)
diff --git a/libcxx/include/__expected/expected.h b/libcxx/include/__expected/expected.h
index b4f3f3cfeef97..e0f5489d2207a 100644
--- a/libcxx/include/__expected/expected.h
+++ b/libcxx/include/__expected/expected.h
@@ -262,7 +262,7 @@ class __expected_base {
private:
template <class, class>
- friend class expected;
+ friend class __expected_base;
_LIBCPP_HIDE_FROM_ABI constexpr void __destroy_union_member()
requires(!is_trivially_destructible_v<_Tp> || !is_trivially_destructible_v<_Err>)
@@ -325,6 +325,15 @@ class __expected_base {
__repr_.__v.__construct_union(__tag, std::forward<_Args>(__args)...);
}
+ _LIBCPP_HIDE_FROM_ABI constexpr bool __has_val() const { return __repr_.__v.__has_val_; }
+ _LIBCPP_HIDE_FROM_ABI constexpr __union_t& __union() { return __repr_.__v.__union_.__v; }
+ _LIBCPP_HIDE_FROM_ABI constexpr const __union_t& __union() const { return __repr_.__v.__union_.__v; }
+ _LIBCPP_HIDE_FROM_ABI constexpr _Tp& __val() { return __repr_.__v.__union_.__v.__val_.__v; }
+ _LIBCPP_HIDE_FROM_ABI constexpr const _Tp& __val() const { return __repr_.__v.__union_.__v.__val_.__v; }
+ _LIBCPP_HIDE_FROM_ABI constexpr _Err& __unex() { return __repr_.__v.__union_.__v.__unex_.__v; }
+ _LIBCPP_HIDE_FROM_ABI constexpr const _Err& __unex() const { return __repr_.__v.__union_.__v.__unex_.__v; }
+
+private:
_LIBCPP_NO_UNIQUE_ADDRESS __expected_conditional_no_unique_address<
!__can_stuff_tail, __repr>::__type __repr_;
};
@@ -375,7 +384,7 @@ class expected : private __expected_base<_Tp, _Err> {
noexcept(is_nothrow_copy_constructible_v<_Tp> && is_nothrow_copy_constructible_v<_Err>) // strengthened
requires(is_copy_constructible_v<_Tp> && is_copy_constructible_v<_Err> &&
!(is_trivially_copy_constructible_v<_Tp> && is_trivially_copy_constructible_v<_Err>))
- : __base(__other.__repr_.__v.__has_val_, __other.__repr_.__v.__union_.__v) { }
+ : __base(__other.__has_val(), __other.__union()) { }
_LIBCPP_HIDE_FROM_ABI constexpr expected(expected&&)
requires(is_move_constructible_v<_Tp> && is_move_constructible_v<_Err>
@@ -386,7 +395,7 @@ class expected : private __expected_base<_Tp, _Err> {
noexcept(is_nothrow_move_constructible_v<_Tp> && is_nothrow_move_constructible_v<_Err>)
requires(is_move_constructible_v<_Tp> && is_move_constructible_v<_Err> &&
!(is_trivially_move_constructible_v<_Tp> && is_trivially_move_constructible_v<_Err>))
- : __base(__other.__repr_.__v.__has_val_, std::move(__other.__repr_.__v.__union_.__v)) { }
+ : __base(__other.__has_val(), std::move(__other.__union())) { }
private:
template <class _Up, class _OtherErr, class _UfQual, class _OtherErrQual>
@@ -426,14 +435,14 @@ class expected : private __expected_base<_Tp, _Err> {
expected(const expected<_Up, _OtherErr>& __other)
noexcept(is_nothrow_constructible_v<_Tp, const _Up&> &&
is_nothrow_constructible_v<_Err, const _OtherErr&>) // strengthened
- : __base(__other.__repr_.__v.__has_val_, __other.__repr_.__v.__union_.__v) {}
+ : __base(__other.__has_val(), __other.__union()) {}
template <class _Up, class _OtherErr>
requires __can_convert<_Up, _OtherErr, _Up, _OtherErr>::value
_LIBCPP_HIDE_FROM_ABI constexpr explicit(!is_convertible_v<_Up, _Tp> || !is_convertible_v<_OtherErr, _Err>)
expected(expected<_Up, _OtherErr>&& __other)
noexcept(is_nothrow_constructible_v<_Tp, _Up> && is_nothrow_constructible_v<_Err, _OtherErr>) // strengthened
- : __base(__other.__repr_.__v.__has_val_, std::move(__other.__repr_.__v.__union_.__v)) {}
+ : __base(__other.__has_val(), std::move(__other.__union())) {}
template <class _Up = _Tp>
requires(!is_same_v<remove_cvref_t<_Up>, in_place_t> && !is_same_v<expected, remove_cvref_t<_Up>> &&
@@ -526,16 +535,14 @@ class expected : private __expected_base<_Tp, _Err> {
(is_nothrow_move_constructible_v<_Tp> ||
is_nothrow_move_constructible_v<_Err>))
{
- if (this->__repr_.__v.__has_val_ && __rhs.__repr_.__v.__has_val_) {
- this->__repr_.__v.__union_.__v.__val_.__v = __rhs.__repr_.__v.__union_.__v.__val_.__v;
- } else if (this->__repr_.__v.__has_val_) {
- __reinit_expected<unexpect_t, in_place_t, _Err, _Tp>(
- this->__repr_.__v.__union_.__v.__val_.__v, __rhs.__repr_.__v.__union_.__v.__unex_.__v);
- } else if (__rhs.__repr_.__v.__has_val_) {
- __reinit_expected<in_place_t, unexpect_t, _Tp, _Err>(
- this->__repr_.__v.__union_.__v.__unex_.__v, __rhs.__repr_.__v.__union_.__v.__val_.__v);
+ if (this->__has_val() && __rhs.__has_val()) {
+ this->__val() = __rhs.__val();
+ } else if (this->__has_val()) {
+ __reinit_expected<unexpect_t, in_place_t, _Err, _Tp>(this->__val(), __rhs.__unex());
+ } else if (__rhs.__has_val()) {
+ __reinit_expected<in_place_t, unexpect_t, _Tp, _Err>(this->__unex(), __rhs.__val());
} else {
- this->__repr_.__v.__union_.__v.__unex_.__v = __rhs.__repr_.__v.__union_.__v.__unex_.__v;
+ this->__unex() = __rhs.__unex();
}
return *this;
}
@@ -552,16 +559,14 @@ class expected : private __expected_base<_Tp, _Err> {
(is_nothrow_move_constructible_v<_Tp> ||
is_nothrow_move_constructible_v<_Err>))
{
- if (this->__repr_.__v.__has_val_ && __rhs.__repr_.__v.__has_val_) {
- this->__repr_.__v.__union_.__v.__val_.__v = std::move(__rhs.__repr_.__v.__union_.__v.__val_.__v);
- } else if (this->__repr_.__v.__has_val_) {
- __reinit_expected<unexpect_t, in_place_t, _Err, _Tp>(
- this->__repr_.__v.__union_.__v.__val_.__v, std::move(__rhs.__repr_.__v.__union_.__v.__unex_.__v));
- } else if (__rhs.__repr_.__v.__has_val_) {
- __reinit_expected<in_place_t, unexpect_t, _Tp, _Err>(
- this->__repr_.__v.__union_.__v.__unex_.__v, std::move(__rhs.__repr_.__v.__union_.__v.__val_.__v));
+ if (this->__has_val() && __rhs.__has_val()) {
+ this->__val() = std::move(__rhs.__val());
+ } else if (this->__has_val()) {
+ __reinit_expected<unexpect_t, in_place_t, _Err, _Tp>(this->__val(), std::move(__rhs.__unex()));
+ } else if (__rhs.__has_val()) {
+ __reinit_expected<in_place_t, unexpect_t, _Tp, _Err>(this->__unex(), std::move(__rhs.__val()));
} else {
- this->__repr_.__v.__union_.__v.__unex_.__v = std::move(__rhs.__repr_.__v.__union_.__v.__unex_.__v);
+ this->__unex() = std::move(__rhs.__unex());
}
return *this;
}
@@ -576,11 +581,10 @@ class expected : private __expected_base<_Tp, _Err> {
is_nothrow_move_constructible_v<_Tp> ||
is_nothrow_move_constructible_v<_Err>))
{
- if (this->__repr_.__v.__has_val_) {
- this->__repr_.__v.__union_.__v.__val_.__v = std::forward<_Up>(__v);
+ if (this->__has_val()) {
+ this->__val() = std::forward<_Up>(__v);
} else {
- __reinit_expected<in_place_t, unexpect_t, _Tp, _Err>(
- this->__repr_.__v.__union_.__v.__unex_.__v, std::forward<_Up>(__v));
+ __reinit_expected<in_place_t, unexpect_t, _Tp, _Err>(this->__unex(), std::forward<_Up>(__v));
}
return *this;
}
@@ -599,11 +603,10 @@ class expected : private __expected_base<_Tp, _Err> {
template <class _OtherErr>
requires(__can_assign_from_unexpected<const _OtherErr&>)
_LIBCPP_HIDE_FROM_ABI constexpr expected& operator=(const unexpected<_OtherErr>& __un) {
- if (this->__repr_.__v.__has_val_) {
- __reinit_expected<unexpect_t, in_place_t, _Err, _Tp>(
- this->__repr_.__v.__union_.__v.__val_.__v, __un.error());
+ if (this->__has_val()) {
+ __reinit_expected<unexpect_t, in_place_t, _Err, _Tp>(this->__val(), __un.error());
} else {
- this->__repr_.__v.__union_.__v.__unex_.__v = __un.error();
+ this->__unex() = __un.error();
}
return *this;
}
@@ -611,11 +614,10 @@ class expected : private __expected_base<_Tp, _Err> {
template <class _OtherErr>
requires(__can_assign_from_unexpected<_OtherErr>)
_LIBCPP_HIDE_FROM_ABI constexpr expected& operator=(unexpected<_OtherErr>&& __un) {
- if (this->__repr_.__v.__has_val_) {
- __reinit_expected<unexpect_t, in_place_t, _Err, _Tp>(
- this->__repr_.__v.__union_.__v.__val_.__v, std::move(__un.error()));
+ if (this->__has_val()) {
+ __reinit_expected<unexpect_t, in_place_t, _Err, _Tp>(this->__val(), std::move(__un.error()));
} else {
- this->__repr_.__v.__union_.__v.__unex_.__v = std::move(__un.error());
+ this->__unex() = std::move(__un.error());
}
return *this;
}
@@ -625,15 +627,15 @@ class expected : private __expected_base<_Tp, _Err> {
_LIBCPP_HIDE_FROM_ABI constexpr _Tp& emplace(_Args&&... __args) noexcept {
this->__destroy();
this->__construct(in_place, std::forward<_Args>(__args)...);
- return this->__repr_.__v.__union_.__v.__val_.__v;
+ return this->__val();
}
template <class _Up, class... _Args>
- requires is_nothrow_constructible_v< _Tp, initializer_list<_Up>&, _Args... >
+ requires is_nothrow_constructible_v<_Tp, initializer_list<_Up>&, _Args...>
_LIBCPP_HIDE_FROM_ABI constexpr _Tp& emplace(initializer_list<_Up> __il, _Args&&... __args) noexcept {
this->__destroy();
this->__construct(in_place, __il, std::forward<_Args>(__args)...);
- return this->__repr_.__v.__union_.__v.__val_.__v;
+ return this->__val();
}
public:
@@ -652,12 +654,12 @@ class expected : private __expected_base<_Tp, _Err> {
{
auto __swap_val_unex_impl = [](expected& __with_val, expected& __with_err) {
if constexpr (is_nothrow_move_constructible_v<_Err>) {
- _Err __tmp(std::move(__with_err.__repr_.__v.__union_.__v.__unex_.__v));
+ _Err __tmp(std::move(__with_err.__unex()));
__with_err.__destroy();
auto __trans = std::__make_exception_guard([&] {
__with_err.__construct(unexpect, std::move(__tmp));
});
- __with_err.__construct(in_place, std::move(__with_val.__repr_.__v.__union_.__v.__val_.__v));
+ __with_err.__construct(in_place, std::move(__with_val.__val()));
__trans.__complete();
__with_val.__destroy();
__with_val.__construct(unexpect, std::move(__tmp));
@@ -665,31 +667,31 @@ class expected : private __expected_base<_Tp, _Err> {
static_assert(is_nothrow_move_constructible_v<_Tp>,
"To provide strong exception guarantee, Tp has to satisfy `is_nothrow_move_constructible_v` so "
"that it can be reverted to the previous state in case an exception is thrown during swap.");
- _Tp __tmp(std::move(__with_val.__repr_.__v.__union_.__v.__val_.__v));
+ _Tp __tmp(std::move(__with_val.__val()));
__with_val.__destroy();
auto __trans = std::__make_exception_guard([&] {
__with_val.__construct(in_place, std::move(__tmp));
});
- __with_val.__construct(unexpect, std::move(__with_err.__repr_.__v.__union_.__v.__unex_.__v));
+ __with_val.__construct(unexpect, std::move(__with_err.__unex()));
__trans.__complete();
__with_err.__destroy();
__with_err.__construct(in_place, std::move(__tmp));
}
};
- if (this->__repr_.__v.__has_val_) {
- if (__rhs.__repr_.__v.__has_val_) {
+ if (this->__has_val()) {
+ if (__rhs.__has_val()) {
using std::swap;
- swap(this->__repr_.__v.__union_.__v.__val_.__v, __rhs.__repr_.__v.__union_.__v.__val_.__v);
+ swap(this->__val(), __rhs.__val());
} else {
__swap_val_unex_impl(*this, __rhs);
}
} else {
- if (__rhs.__repr_.__v.__has_val_) {
+ if (__rhs.__has_val()) {
__swap_val_unex_impl(__rhs, *this);
} else {
using std::swap;
- swap(this->__repr_.__v.__union_.__v.__unex_.__v, __rhs.__repr_.__v.__union_.__v.__unex_.__v);
+ swap(this->__unex(), __rhs.__unex());
}
}
}
@@ -703,105 +705,105 @@ class expected : private __expected_base<_Tp, _Err> {
// [expected.object.obs], observers
_LIBCPP_HIDE_FROM_ABI constexpr const _Tp* operator->() const noexcept {
- _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(this->__repr_.__v.__has_val_, "expected::operator-> requires the expected to contain a value");
- return std::addressof(this->__repr_.__v.__union_.__v.__val_.__v);
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(this->__has_val(), "expected::operator-> requires the expected to contain a value");
+ return std::addressof(this->__val());
}
_LIBCPP_HIDE_FROM_ABI constexpr _Tp* operator->() noexcept {
- _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(this->__repr_.__v.__has_val_, "expected::operator-> requires the expected to contain a value");
- return std::addressof(this->__repr_.__v.__union_.__v.__val_.__v);
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(this->__has_val(), "expected::operator-> requires the expected to contain a value");
+ return std::addressof(this->__val());
}
_LIBCPP_HIDE_FROM_ABI constexpr const _Tp& operator*() const& noexcept {
- _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(this->__repr_.__v.__has_val_, "expected::operator* requires the expected to contain a value");
- return this->__repr_.__v.__union_.__v.__val_.__v;
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(this->__has_val(), "expected::operator* requires the expected to contain a value");
+ return this->__val();
}
_LIBCPP_HIDE_FROM_ABI constexpr _Tp& operator*() & noexcept {
- _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(this->__repr_.__v.__has_val_, "expected::operator* requires the expected to contain a value");
- return this->__repr_.__v.__union_.__v.__val_.__v;
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(this->__has_val(), "expected::operator* requires the expected to contain a value");
+ return this->__val();
}
_LIBCPP_HIDE_FROM_ABI constexpr const _Tp&& operator*() const&& noexcept {
- _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(this->__repr_.__v.__has_val_, "expected::operator* requires the expected to contain a value");
- return std::move(this->__repr_.__v.__union_.__v.__val_.__v);
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(this->__has_val(), "expected::operator* requires the expected to contain a value");
+ return std::move(this->__val());
}
_LIBCPP_HIDE_FROM_ABI constexpr _Tp&& operator*() && noexcept {
- _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(this->__repr_.__v.__has_val_, "expected::operator* requires the expected to contain a value");
- return std::move(this->__repr_.__v.__union_.__v.__val_.__v);
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(this->__has_val(), "expected::operator* requires the expected to contain a value");
+ return std::move(this->__val());
}
- _LIBCPP_HIDE_FROM_ABI constexpr explicit operator bool() const noexcept { return this->__repr_.__v.__has_val_; }
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit operator bool() const noexcept { return this->__has_val(); }
- _LIBCPP_HIDE_FROM_ABI constexpr bool has_value() const noexcept { return this->__repr_.__v.__has_val_; }
+ _LIBCPP_HIDE_FROM_ABI constexpr bool has_value() const noexcept { return this->__has_val(); }
_LIBCPP_HIDE_FROM_ABI constexpr const _Tp& value() const& {
static_assert(is_copy_constructible_v<_Err>, "error_type has to be copy constructible");
- if (!this->__repr_.__v.__has_val_) {
+ if (!this->__has_val()) {
std::__throw_bad_expected_access<_Err>(std::as_const(error()));
}
- return this->__repr_.__v.__union_.__v.__val_.__v;
+ return this->__val();
}
_LIBCPP_HIDE_FROM_ABI constexpr _Tp& value() & {
static_assert(is_copy_constructible_v<_Err>, "error_type has to be copy constructible");
- if (!this->__repr_.__v.__has_val_) {
+ if (!this->__has_val()) {
std::__throw_bad_expected_access<_Err>(std::as_const(error()));
}
- return this->__repr_.__v.__union_.__v.__val_.__v;
+ return this->__val();
}
_LIBCPP_HIDE_FROM_ABI constexpr const _Tp&& value() const&& {
static_assert(is_copy_constructible_v<_Err> && is_constructible_v<_Err, decltype(std::move(error()))>,
"error_type has to be both copy constructible and constructible from decltype(std::move(error()))");
- if (!this->__repr_.__v.__has_val_) {
+ if (!this->__has_val()) {
std::__throw_bad_expected_access<_Err>(std::move(error()));
}
- return std::move(this->__repr_.__v.__union_.__v.__val_.__v);
+ return std::move(this->__val());
}
_LIBCPP_HIDE_FROM_ABI constexpr _Tp&& value() && {
static_assert(is_copy_constructible_v<_Err> && is_constructible_v<_Err, decltype(std::move(error()))>,
"error_type has to be both copy constructible and constructible from decltype(std::move(error()))");
- if (!this->__repr_.__v.__has_val_) {
+ if (!this->__has_val()) {
std::__throw_bad_expected_access<_Err>(std::move(error()));
}
- return std::move(this->__repr_.__v.__union_.__v.__val_.__v);
+ return std::move(this->__val());
}
_LIBCPP_HIDE_FROM_ABI constexpr const _Err& error() const& noexcept {
- _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!this->__repr_.__v.__has_val_, "expected::error requires the expected to contain an error");
- return this->__repr_.__v.__union_.__v.__unex_.__v;
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!this->__has_val(), "expected::error requires the expected to contain an error");
+ return this->__unex();
}
_LIBCPP_HIDE_FROM_ABI constexpr _Err& error() & noexcept {
- _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!this->__repr_.__v.__has_val_, "expected::error requires the expected to contain an error");
- return this->__repr_.__v.__union_.__v.__unex_.__v;
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!this->__has_val(), "expected::error requires the expected to contain an error");
+ return this->__unex();
}
_LIBCPP_HIDE_FROM_ABI constexpr const _Err&& error() const&& noexcept {
- _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!this->__repr_.__v.__has_val_, "expected::error requires the expected to contain an error");
- return std::move(this->__repr_.__v.__union_.__v.__unex_.__v);
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!this->__has_val(), "expected::error requires the expected to contain an error");
+ return std::move(this->__unex());
}
_LIBCPP_HIDE_FROM_ABI constexpr _Err&& error() && noexcept {
- _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!this->__repr_.__v.__has_val_, "expected::error requires the expected to contain an error");
- return std::move(this->__repr_.__v.__union_.__v.__unex_.__v);
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!this->__has_val(), "expected::error requires the expected to contain an error");
+ return std::move(this->__unex());
}
template <class _Up>
_LIBCPP_HIDE_FROM_ABI constexpr _Tp value_or(_Up&& __v) const& {
static_assert(is_copy_constructible_v<_Tp>, "value_type has to be copy constructible");
static_assert(is_convertible_v<_Up, _Tp>, "argument has to be convertible to value_type");
- return this->__repr_.__v.__has_val_ ? this->__repr_.__v.__union_.__v.__val_.__v : static_cast<_Tp>(std::forward<_Up>(__v));
+ return this->__has_val() ? this->__val() : static_cast<_Tp>(std::forward<_Up>(__v));
}
template <class _Up>
_LIBCPP_HIDE_FROM_ABI constexpr _Tp value_or(_Up&& __v) && {
static_assert(is_move_constructible_v<_Tp>, "value_type has to be move constructible");
static_assert(is_convertible_v<_Up, _Tp>, "argument has to be convertible to value_type");
- return this->__repr_.__v.__has_val_ ? std::move(this->__repr_.__v.__union_.__v.__val_.__v) : static_cast<_Tp>(std::forward<_Up>(__v));
+ return this->__has_val() ? std::move(this->__val()) : static_cast<_Tp>(std::forward<_Up>(__v));
}
template <class _Up = _Err>
@@ -831,7 +833,7 @@ class expected : private __expected_base<_Tp, _Err> {
static_assert(is_same_v<typename _Up::error_type, _Err>,
"The result of f(**this) must have the same error_type as this expected");
if (has_value()) {
- return std::invoke(std::forward<_Func>(__f), this->__repr_.__v.__union_.__v.__val_.__v);
+ return std::invoke(std::forward<_Func>(__f), this->__val());
}
return _Up(unexpect, error());
}
@@ -844,7 +846,7 @@ class expected : private __expected_base<_Tp, _Err> {
static_assert(is_same_v<typename _Up::error_type, _Err>,
"The result of f(**this) must have the same error_type as this expected");
if (has_value()) {
- return std::invoke(std::forward<_Func>(__f), this->__repr_.__v.__union_.__v.__val_.__v);
+ return std::invoke(std::forward<_Func>(__f), this->__val());
}
return _Up(unexpect, error());
}
@@ -858,7 +860,7 @@ class expected : private __expected_base<_Tp, _Err> {
static_assert(is_same_v<typename _Up::error_type, _Err>,
"The result of f(std::move(**this)) must have the same error_type as this expected");
if (has_value()) {
- return std::invoke(std::forward<_Func>(__f), std::move(this->__repr_.__v.__union_.__v.__val_.__v));
+ return std::invoke(std::forward<_Func>(__f), std::move(this->__val()));
}
return _Up(unexpect, std::move(error()));
}
@@ -872,7 +874,7 @@ class expected : private __expected_base<_Tp, _Err> {
static_assert(is_same_v<typename _Up::error_type, _Err>,
"The result of f(std::move(**this)) must have the same error_type as this expected");
if (has_value()) {
- return std::invoke(std::forward<_Func>(__f), std::move(this->__repr_.__v.__union_.__v.__val_.__v));
+ return std::invoke(std::forward<_Func>(__f), std::move(this->__val()));
}
return _Up(unexpect, std::move(error()));
}
@@ -885,7 +887,7 @@ class expected : private __expected_base<_Tp, _Err> {
static_assert(is_same_v<typename _Gp::value_type, _Tp>,
"The result of f(error()) must have the same value_type as this expected");
if (has_value()) {
- return _Gp(in_place, this->__repr_.__v.__union_.__v.__val_.__v);
+ return _Gp(in_place, this->__val());
}
return std::invoke(std::forward<_Func>(__f), error());
}
@@ -898,7 +900,7 @@ class expected : private __expected_base<_Tp, _Err> {
static_assert(is_same_v<typename _Gp::value_type, _Tp>,
"The result of f(error()) must have the same value_type as this expected");
if (has_value()) {
- return _Gp(in_place, this->__repr_.__v.__union_.__v.__val_.__v);
+ return _Gp(in_place, this->__val());
}
return std::invoke(std::forward<_Func>(__f), error());
}
@@ -912,7 +914,7 @@ class expected : private __expected_base<_Tp, _Err> {
static_assert(is_same_v<typename _Gp::value_type, _Tp>,
"The result of f(std::move(error())) must have the same value_type as this expected");
if (has_value()) {
- return _Gp(in_place, std::move(this->__repr_.__v.__union_.__v.__val_.__v));
+ return _Gp(in_place, std::move(this->__val()));
}
return std::invoke(std::forward<_Func>(__f), std::move(error()));
}
@@ -926,7 +928,7 @@ class expected : private __expected_base<_Tp, _Err> {
static_assert(is_same_v<typename _Gp::value_type, _Tp>,
"The result of f(std::move(error())) must have the same value_type as this expected");
if (has_value()) {
- return _Gp(in_place, std::move(this->__repr_.__v.__union_.__v.__val_.__v));
+ return _Gp(in_place, std::move(this->__val()));
}
return std::invoke(std::forward<_Func>(__f), std::move(error()));
}
@@ -940,9 +942,9 @@ class expected : private __expected_base<_Tp, _Err> {
}
if constexpr (!is_void_v<_Up>) {
return expected<_Up, _Err>(__expected_construct_in_place_from_invoke_tag{},
- std::forward<_Func>(__f), this->__repr_.__v.__union_.__v.__val_.__v);
+ std::forward<_Func>(__f), this->__val());
} else {
- std::invoke(std::forward<_Func>(__f), this->__repr_.__v.__union_.__v.__val_.__v);
+ std::invoke(std::forward<_Func>(__f), this->__val());
return expected<_Up, _Err>();
}
}
@@ -956,9 +958,9 @@ class expected : private __expected_base<_Tp, _Err> {
}
if constexpr (!is_void_v<_Up>) {
return expected<_Up, _Err>(__expected_construct_in_place_from_invoke_tag{},
- std::forward<_Func>(__f), this->__repr_.__v.__union_.__v.__val_.__v);
+ std::forward<_Func>(__f), this->__val());
} else {
- std::invoke(std::forward<_Func>(__f), this->__repr_.__v.__union_.__v.__val_.__v);
+ std::invoke(std::forward<_Func>(__f), this->__val());
return expected<_Up, _Err>();
}
}
@@ -972,9 +974,9 @@ class expected : private __expected_base<_Tp, _Err> {
}
if constexpr (!is_void_v<_Up>) {
return expected<_Up, _Err>(__expected_construct_in_place_from_invoke_tag{},
- std::forward<_Func>(__f), std::move(this->__repr_.__v.__union_.__v.__val_.__v));
+ std::forward<_Func>(__f), std::move(this->__val()));
} else {
- std::invoke(std::forward<_Func>(__f), std::move(this->__repr_.__v.__union_.__v.__val_.__v));
+ std::invoke(std::forward<_Func>(__f), std::move(this->__val()));
return expected<_Up, _Err>();
}
}
@@ -988,9 +990,9 @@ class expected : private __expected_base<_Tp, _Err> {
}
if constexpr (!is_void_v<_Up>) {
return expected<_Up, _Err>(__expected_construct_in_place_from_invoke_tag{},
- std::forward<_Func>(__f), std::move(this->__repr_.__v.__union_.__v.__val_.__v));
+ std::forward<_Func>(__f), std::move(this->__val()));
} else {
- std::invoke(std::forward<_Func>(__f), std::move(this->__repr_.__v.__union_.__v.__val_.__v));
+ std::invoke(std::forward<_Func>(__f), std::move(this->__val()));
return expected<_Up, _Err>();
}
}
@@ -1002,7 +1004,7 @@ class expected : private __expected_base<_Tp, _Err> {
static_assert(__valid_std_unexpected<_Gp>::value,
"The result of f(error()) must be a valid template argument for unexpected");
if (has_value()) {
- return expected<_Tp, _Gp>(in_place, this->__repr_.__v.__union_.__v.__val_.__v);
+ return expected<_Tp, _Gp>(in_place, this->__val());
}
return expected<_Tp, _Gp>(__expected_construct_unexpected_from_invoke_tag{}, std::forward<_Func>(__f), error());
}
@@ -1014,7 +1016,7 @@ class expected : private __expected_base<_Tp, _Err> {
static_assert(__valid_std_unexpected<_Gp>::value,
"The result of f(error()) must be a valid template argument for unexpected");
if (has_value()) {
- return expected<_Tp, _Gp>(in_place, this->__repr_.__v.__union_.__v.__val_.__v);
+ return expected<_Tp, _Gp>(in_place, this->__val());
}
return expected<_Tp, _Gp>(__expected_construct_unexpected_from_invoke_tag{}, std::forward<_Func>(__f), error());
}
@@ -1026,7 +1028,7 @@ class expected : private __expected_base<_Tp, _Err> {
static_assert(__valid_std_unexpected<_Gp>::value,
"The result of f(std::move(error())) must be a valid template argument for unexpected");
if (has_value()) {
- return expected<_Tp, _Gp>(in_place, std::move(this->__repr_.__v.__union_.__v.__val_.__v));
+ return expected<_Tp, _Gp>(in_place, std::move(this->__val()));
}
return expected<_Tp, _Gp>(
__expected_construct_unexpected_from_invoke_tag{}, std::forward<_Func>(__f), std::move(error()));
@@ -1039,7 +1041,7 @@ class expected : private __expected_base<_Tp, _Err> {
static_assert(__valid_std_unexpected<_Gp>::value,
"The result of f(std::move(error())) must be a valid template argument for unexpected");
if (has_value()) {
- return expected<_Tp, _Gp>(in_place, std::move(this->__repr_.__v.__union_.__v.__val_.__v));
+ return expected<_Tp, _Gp>(in_place, std::move(this->__val()));
}
return expected<_Tp, _Gp>(
__expected_construct_unexpected_from_invoke_tag{}, std::forward<_Func>(__f), std::move(error()));
@@ -1049,252 +1051,175 @@ class expected : private __expected_base<_Tp, _Err> {
template <class _T2, class _E2>
requires(!is_void_v<_T2>)
_LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const expected& __x, const expected<_T2, _E2>& __y) {
- if (__x.__repr_.__v.__has_val_ != __y.__repr_.__v.__has_val_) {
+ if (__x.__has_val() != __y.__has_val()) {
return false;
} else {
- if (__x.__repr_.__v.__has_val_) {
- return __x.__repr_.__v.__union_.__v.__val_.__v == __y.__repr_.__v.__union_.__v.__val_.__v;
+ if (__x.__has_val()) {
+ return __x.__val() == __y.__val();
} else {
- return __x.__repr_.__v.__union_.__v.__unex_.__v == __y.__repr_.__v.__union_.__v.__unex_.__v;
+ return __x.__unex() == __y.__unex();
}
}
}
template <class _T2>
_LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const expected& __x, const _T2& __v) {
- return __x.__repr_.__v.__has_val_ && static_cast<bool>(__x.__repr_.__v.__union_.__v.__val_.__v == __v);
+ return __x.__has_val() && static_cast<bool>(__x.__val() == __v);
}
template <class _E2>
_LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const expected& __x, const unexpected<_E2>& __e) {
- return !__x.__repr_.__v.__has_val_ && static_cast<bool>(__x.__repr_.__v.__union_.__v.__unex_.__v == __e.error());
+ return !__x.__has_val() && static_cast<bool>(__x.__unex() == __e.error());
}
};
-struct __expected_empty_t {};
-
-template <class _ErrorType>
-union __expected_void_union_t {
- _LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_void_union_t(in_place_t) : __empty_() {}
-
- template <class... _Args>
- _LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_void_union_t(unexpect_t, _Args&&... __args)
- : __unex_(std::forward<_Args>(__args)...) {}
-
- template <class _Func, class... _Args>
- _LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_void_union_t(
- __expected_construct_unexpected_from_invoke_tag, _Func&& __f, _Args&&... __args)
- : __unex_(std::invoke(std::forward<_Func>(__f), std::forward<_Args>(__args)...)) {}
-
- _LIBCPP_HIDE_FROM_ABI constexpr ~__expected_void_union_t()
- requires(is_trivially_destructible_v<_ErrorType>)
- = default;
-
- // __repr's destructor handles this
- _LIBCPP_HIDE_FROM_ABI constexpr ~__expected_void_union_t() {}
+template <class _Err>
+class __expected_void_base {
+ struct __empty_t {};
+ // use named union because [[no_unique_address]] cannot be applied to an unnamed union,
+ // also guaranteed elision into a potentially-overlapping subobject is unsettled (and
+ // it's not clear that it's implementable, given that the function is allowed to clobber
+ // the tail padding) - see https://github.com/itanium-cxx-abi/cxx-abi/issues/107.
+ union __union_t {
+ _LIBCPP_HIDE_FROM_ABI constexpr __union_t(const __union_t&) = default;
+ _LIBCPP_HIDE_FROM_ABI constexpr __union_t(__union_t&&) = default;
+ _LIBCPP_HIDE_FROM_ABI constexpr __union_t& operator=(const __union_t&) = delete;
- // XXX: Why are those not [[no_unique_address]]?
- __expected_empty_t __empty_;
- _ErrorType __unex_;
-};
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit __union_t(in_place_t) : __empty_() {}
-// use named union because [[no_unique_address]] cannot be applied to an unnamed union,
-// also guaranteed elision into a potentially-overlapping subobject is unsettled (and
-// it's not clear that it's implementable, given that the function is allowed to clobber
-// the tail padding) - see https://github.com/itanium-cxx-abi/cxx-abi/issues/107.
-template <class _ErrorType>
- requires is_trivially_move_constructible_v<_ErrorType>
-union __expected_void_union_t<_ErrorType> {
- _LIBCPP_HIDE_FROM_ABI constexpr __expected_void_union_t(const __expected_void_union_t&) = default;
- _LIBCPP_HIDE_FROM_ABI constexpr __expected_void_union_t& operator=(const __expected_void_union_t&) = default;
+ template <class... _Args>
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit __union_t(unexpect_t, _Args&&... __args)
+ : __unex_(std::forward<_Args>(__args)...) {}
- _LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_void_union_t(in_place_t) : __empty_() {}
+ template <class _Func, class... _Args>
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit __union_t(
+ __expected_construct_unexpected_from_invoke_tag, _Func&& __f, _Args&&... __args)
+ : __unex_(__expected_invoke_tag{}, std::forward<_Func>(__f), std::forward<_Args>(__args)...) {}
- template <class... _Args>
- _LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_void_union_t(unexpect_t, _Args&&... __args)
- : __unex_(std::forward<_Args>(__args)...) {}
+ _LIBCPP_HIDE_FROM_ABI constexpr ~__union_t()
+ requires(is_trivially_destructible_v<_Err>)
+ = default;
- template <class _Func, class... _Args>
- _LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_void_union_t(
- __expected_construct_unexpected_from_invoke_tag, _Func&& __f, _Args&&... __args)
- : __unex_(std::invoke(std::forward<_Func>(__f), std::forward<_Args>(__args)...)) {}
+ // __repr's destructor handles this
+ _LIBCPP_HIDE_FROM_ABI constexpr ~__union_t()
+ requires(!is_trivially_destructible_v<_Err>)
+ {}
- _LIBCPP_HIDE_FROM_ABI constexpr ~__expected_void_union_t()
- requires(is_trivially_destructible_v<_ErrorType>)
- = default;
+ _LIBCPP_NO_UNIQUE_ADDRESS __empty_t __empty_;
+ _LIBCPP_NO_UNIQUE_ADDRESS __expected_conditional_no_unique_address<
+ __expected_union_member_no_unique_address<_Err>, _Err>::__type __unex_;
+ };
- // __repr's destructor handles this
- _LIBCPP_HIDE_FROM_ABI constexpr ~__expected_void_union_t()
- requires(!is_trivially_destructible_v<_ErrorType>)
- {}
+ static constexpr bool __can_stuff_tail = __expected_can_stuff_tail<__union_t>();
- _LIBCPP_NO_UNIQUE_ADDRESS __expected_empty_t __empty_;
- _LIBCPP_NO_UNIQUE_ADDRESS _ErrorType __unex_;
-};
+ struct __repr {
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit __repr() = delete;
-template <class _Err, bool _StuffTail = false>
-struct __expected_void_repr {
- _LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_void_repr() = delete;
+ template <class... _Args>
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit __repr(in_place_t __tag)
+ : __union_(__tag), __has_val_(true) {}
- _LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_void_repr(in_place_t __tag)
- : __union_(__tag), __has_val_(true) {}
+ template <class... _Args>
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit __repr(unexpect_t __tag, _Args&&... __args)
+ : __union_(__tag, std::forward<_Args>(__args)...), __has_val_(false) {}
- template <class... _Args>
- _LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_void_repr(unexpect_t __tag, _Args&&... __args)
- : __union_(__tag, std::forward<_Args>(__args)...), __has_val_(false) {}
+ template <class... _Args>
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit __repr(
+ std::__expected_construct_unexpected_from_invoke_tag __tag, _Args&&... __args)
+ : __union_(__tag, std::forward<_Args>(__args)...), __has_val_(false) {}
- template <class... _Args>
- _LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_void_repr(
- std::__expected_construct_unexpected_from_invoke_tag __tag, _Args&&... __args)
- : __union_(__tag, std::forward<_Args>(__args)...), __has_val_(false) {}
+ template <class _OtherUnion>
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit __repr(bool __has_val, _OtherUnion&& __other)
+ requires(!__can_stuff_tail)
+ : __union_(__expected_invoke_tag{},
+ [&] { return __make_union(__has_val, std::forward<_OtherUnion>(__other)); }),
+ __has_val_(__has_val) {}
- template <class _OtherUnion>
- _LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_void_repr(bool __has_val, _OtherUnion&& __other)
- : __union_(__make_union(__has_val, std::forward<_OtherUnion>(__other))), __has_val_(__has_val) {}
+ _LIBCPP_HIDE_FROM_ABI constexpr __repr(const __repr&) = delete;
+ _LIBCPP_HIDE_FROM_ABI constexpr __repr(const __repr&)
+ requires(is_copy_constructible_v<_Err> && is_trivially_copy_constructible_v<_Err>)
+ = default;
+ _LIBCPP_HIDE_FROM_ABI constexpr __repr(__repr&&) = delete;
+ _LIBCPP_HIDE_FROM_ABI constexpr __repr(__repr&&)
+ requires(is_move_constructible_v<_Err> && is_trivially_move_constructible_v<_Err>)
+ = default;
- _LIBCPP_HIDE_FROM_ABI constexpr __expected_void_repr(const __expected_void_repr&) = delete;
- _LIBCPP_HIDE_FROM_ABI constexpr __expected_void_repr(const __expected_void_repr&)
- requires(is_copy_constructible_v<_Err> && is_trivially_copy_constructible_v<_Err>)
- = default;
- _LIBCPP_HIDE_FROM_ABI constexpr __expected_void_repr(__expected_void_repr&&) = delete;
- _LIBCPP_HIDE_FROM_ABI constexpr __expected_void_repr(__expected_void_repr&&)
- requires(is_move_constructible_v<_Err> && is_trivially_move_constructible_v<_Err>)
- = default;
+ _LIBCPP_HIDE_FROM_ABI constexpr __repr& operator=(const __repr&) = delete;
- _LIBCPP_HIDE_FROM_ABI constexpr __expected_void_repr& operator=(const __expected_void_repr&) = delete;
+ _LIBCPP_HIDE_FROM_ABI constexpr ~__repr()
+ requires(is_trivially_destructible_v<_Err>)
+ = default;
- _LIBCPP_HIDE_FROM_ABI constexpr ~__expected_void_repr()
- requires(is_trivially_destructible_v<_Err>)
- = default;
+ _LIBCPP_HIDE_FROM_ABI constexpr ~__repr()
+ requires(!is_trivially_destructible_v<_Err>)
+ {
+ __destroy_union_member();
+ }
- _LIBCPP_HIDE_FROM_ABI constexpr ~__expected_void_repr()
- requires(!is_trivially_destructible_v<_Err>)
- {
- __destroy_union_member();
- }
+ _LIBCPP_HIDE_FROM_ABI constexpr void __destroy_union()
+ requires(!__can_stuff_tail && is_trivially_destructible_v<_Err>)
+ {
+ std::destroy_at(&__union_.__v);
+ }
- _LIBCPP_HIDE_FROM_ABI constexpr void __destroy_union()
- requires(is_trivially_destructible_v<_Err>)
- {
- std::destroy_at(&__union_);
- }
+ _LIBCPP_HIDE_FROM_ABI constexpr void __destroy_union()
+ requires(!__can_stuff_tail && !is_trivially_destructible_v<_Err>)
+ {
+ __destroy_union_member();
+ std::destroy_at(&__union_.__v);
+ }
- _LIBCPP_HIDE_FROM_ABI constexpr void __destroy_union()
- requires(!is_trivially_destructible_v<_Err>)
- {
- __destroy_union_member();
- std::destroy_at(&__union_);
- }
+ _LIBCPP_HIDE_FROM_ABI constexpr void __construct_union(in_place_t)
+ requires(!__can_stuff_tail)
+ {
+ std::construct_at(&__union_.__v, in_place);
+ __has_val_ = true;
+ }
- _LIBCPP_HIDE_FROM_ABI constexpr void __construct_union(in_place_t)
- {
- std::construct_at(&__union_, in_place);
- __has_val_ = true;
- }
+ template <class... _Args>
+ _LIBCPP_HIDE_FROM_ABI constexpr void __construct_union(unexpect_t, _Args&&... __args)
+ requires(!__can_stuff_tail)
+ {
+ std::construct_at(&__union_.__v, unexpect, std::forward<_Args>(__args)...);
+ __has_val_ = false;
+ }
- template <class... _Args>
- _LIBCPP_HIDE_FROM_ABI constexpr void __construct_union(unexpect_t, _Args&&... __args)
- {
- std::construct_at(&__union_, unexpect, std::forward<_Args>(__args)...);
- __has_val_ = false;
- }
+ private:
+ template <class>
+ friend class __expected_void_base;
-private:
- template <class, class>
- friend class expected;
+ _LIBCPP_HIDE_FROM_ABI constexpr void __destroy_union_member()
+ requires(!is_trivially_destructible_v<_Err>)
+ {
+ if (!__has_val_)
+ std::destroy_at(std::addressof(__union_.__v.__unex_));
+ }
- _LIBCPP_HIDE_FROM_ABI constexpr void __destroy_union_member()
- requires(!is_trivially_destructible_v<_Err>)
- {
- if (!__has_val_) {
- std::destroy_at(std::addressof(__union_.__unex_));
+ template <class _OtherUnion>
+ _LIBCPP_HIDE_FROM_ABI static constexpr __union_t __make_union(bool __has_val, _OtherUnion&& __other)
+ requires(!__can_stuff_tail)
+ {
+ if (__has_val)
+ return __union_t(in_place);
+ else
+ return __union_t(unexpect, std::forward<_OtherUnion>(__other).__unex_.__v);
}
- }
+
+ _LIBCPP_NO_UNIQUE_ADDRESS __expected_conditional_no_unique_address<
+ __can_stuff_tail, __union_t>::__type __union_;
+ _LIBCPP_NO_UNIQUE_ADDRESS bool __has_val_;
+ };
template <class _OtherUnion>
- _LIBCPP_HIDE_FROM_ABI static constexpr __expected_void_union_t<_Err>
- __make_union(bool __has_val, _OtherUnion&& __other)
+ _LIBCPP_HIDE_FROM_ABI static constexpr __repr __make_repr(bool __has_val, _OtherUnion&& __other)
+ requires(__can_stuff_tail)
{
if (__has_val)
- return __expected_void_union_t<_Err>(in_place);
+ return __repr(in_place);
else
- return __expected_void_union_t<_Err>(unexpect, std::forward<_OtherUnion>(__other).__unex_);
- }
-
- __expected_void_union_t<_Err> __union_;
- _LIBCPP_NO_UNIQUE_ADDRESS bool __has_val_;
-};
-
-template <class _Err>
-struct __expected_void_repr<_Err, true> {
- _LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_void_repr() = delete;
-
- _LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_void_repr(in_place_t __tag)
- : __union_(__tag), __has_val_(true) {}
-
- template <class... _Args>
- _LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_void_repr(unexpect_t __tag, _Args&&... __args)
- : __union_(__tag, std::forward<_Args>(__args)...), __has_val_(false) {}
-
- template <class... _Args>
- _LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_void_repr(
- std::__expected_construct_unexpected_from_invoke_tag __tag, _Args&&... __args)
- : __union_(__tag, std::forward<_Args>(__args)...), __has_val_(false) {}
-
- _LIBCPP_HIDE_FROM_ABI constexpr __expected_void_repr(const __expected_void_repr&) = delete;
- _LIBCPP_HIDE_FROM_ABI constexpr __expected_void_repr(const __expected_void_repr&)
- requires(is_copy_constructible_v<_Err> && is_trivially_copy_constructible_v<_Err>)
- = default;
- _LIBCPP_HIDE_FROM_ABI constexpr __expected_void_repr(__expected_void_repr&&) = delete;
- _LIBCPP_HIDE_FROM_ABI constexpr __expected_void_repr(__expected_void_repr&&)
- requires(is_move_constructible_v<_Err> && is_trivially_move_constructible_v<_Err>)
- = default;
-
- _LIBCPP_HIDE_FROM_ABI constexpr __expected_void_repr& operator=(const __expected_void_repr&) = delete;
-
- _LIBCPP_HIDE_FROM_ABI constexpr ~__expected_void_repr()
- requires(is_trivially_destructible_v<_Err>)
- = default;
-
- _LIBCPP_HIDE_FROM_ABI constexpr ~__expected_void_repr()
- requires(!is_trivially_destructible_v<_Err>)
- {
- if (!__has_val_) {
- std::destroy_at(std::addressof(__union_.__unex_));
- }
- }
-
-private:
- template <class, class>
- friend class expected;
-
- _LIBCPP_NO_UNIQUE_ADDRESS __expected_void_union_t<_Err> __union_;
- _LIBCPP_NO_UNIQUE_ADDRESS bool __has_val_;
-};
-
-template <class _Err>
-struct __expected_void_base {
-protected:
- template <class... _Args>
- _LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_void_base(_Args&&... __args)
- : __repr_(std::forward<_Args>(__args)...) {}
-
- _LIBCPP_HIDE_FROM_ABI constexpr void __destroy() {
- __repr_.__destroy_union();
- }
-
- template <class _Tag, class... _Args>
- _LIBCPP_HIDE_FROM_ABI constexpr void __construct(_Tag __tag, _Args&&... __args)
- {
- __repr_.__construct_union(__tag, std::forward<_Args>(__args)...);
+ return __repr(unexpect, std::forward<_OtherUnion>(__other).__unex_.__v);
}
- _LIBCPP_NO_UNIQUE_ADDRESS __expected_void_repr<_Err, false> __repr_;
-};
-
-template <class _Err>
- requires (sizeof(__expected_void_repr<_Err, true>) == sizeof(__expected_void_union_t<_Err>))
-struct __expected_void_base<_Err> {
protected:
template <class... _Args>
_LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_void_base(_Args&&... __args)
@@ -1302,32 +1227,34 @@ struct __expected_void_base<_Err> {
template <class _OtherUnion>
_LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_void_base(bool __has_val, _OtherUnion&& __other)
- : __repr_(__make_repr(__has_val, std::forward<_OtherUnion>(__other))) {}
+ requires(__can_stuff_tail)
+ : __repr_(__expected_invoke_tag{},
+ [&] { return __make_repr(__has_val, std::forward<_OtherUnion>(__other)); }) {}
_LIBCPP_HIDE_FROM_ABI constexpr void __destroy() {
- std::destroy_at(&__repr_);
+ if constexpr (__can_stuff_tail)
+ std::destroy_at(&__repr_.__v);
+ else
+ __repr_.__v.__destroy_union();
}
template <class _Tag, class... _Args>
- _LIBCPP_HIDE_FROM_ABI constexpr void __construct(_Tag __tag, _Args&&... __args)
- {
- std::construct_at(&__repr_, __tag, std::forward<_Args>(__args)...);
- }
-
-private:
- using __repr = __expected_void_repr<_Err, true>;
-
- template <class _OtherUnion>
- _LIBCPP_HIDE_FROM_ABI static constexpr __repr __make_repr(bool __has_val, _OtherUnion&& __other)
- {
- if (__has_val)
- return __repr(in_place);
+ _LIBCPP_HIDE_FROM_ABI constexpr void __construct(_Tag __tag, _Args&&... __args) {
+ if constexpr (__can_stuff_tail)
+ std::construct_at(&__repr_.__v, __tag, std::forward<_Args>(__args)...);
else
- return __repr(unexpect, std::forward<_OtherUnion>(__other).__unex_);
+ __repr_.__v.__construct_union(__tag, std::forward<_Args>(__args)...);
}
-protected:
- __repr __repr_;
+ _LIBCPP_HIDE_FROM_ABI constexpr bool __has_val() const { return __repr_.__v.__has_val_; }
+ _LIBCPP_HIDE_FROM_ABI constexpr __union_t& __union() { return __repr_.__v.__union_.__v; }
+ _LIBCPP_HIDE_FROM_ABI constexpr const __union_t& __union() const { return __repr_.__v.__union_.__v; }
+ _LIBCPP_HIDE_FROM_ABI constexpr _Err& __unex() { return __repr_.__v.__union_.__v.__unex_.__v; }
+ _LIBCPP_HIDE_FROM_ABI constexpr const _Err& __unex() const { return __repr_.__v.__union_.__v.__unex_.__v; }
+
+private:
+ _LIBCPP_NO_UNIQUE_ADDRESS __expected_conditional_no_unique_address<
+ !__can_stuff_tail, __repr>::__type __repr_;
};
template <class _Tp, class _Err>
@@ -1371,7 +1298,7 @@ class expected<_Tp, _Err> : private __expected_void_base<_Err> {
_LIBCPP_HIDE_FROM_ABI constexpr expected(const expected& __rhs)
noexcept(is_nothrow_copy_constructible_v<_Err>) // strengthened
requires(is_copy_constructible_v<_Err> && !is_trivially_copy_constructible_v<_Err>)
- : __base(__rhs.__repr_.__has_val_, __rhs.__repr_.__union_) {}
+ : __base(__rhs.__has_val(), __rhs.__union()) {}
_LIBCPP_HIDE_FROM_ABI constexpr expected(expected&&)
requires(is_move_constructible_v<_Err> && is_trivially_move_constructible_v<_Err>)
@@ -1380,21 +1307,21 @@ class expected<_Tp, _Err> : private __expected_void_base<_Err> {
_LIBCPP_HIDE_FROM_ABI constexpr expected(expected&& __rhs)
noexcept(is_nothrow_move_constructible_v<_Err>)
requires(is_move_constructible_v<_Err> && !is_trivially_move_constructible_v<_Err>)
- : __base(__rhs.__repr_.__has_val_, std::move(__rhs.__repr_.__union_)) {}
+ : __base(__rhs.__has_val(), std::move(__rhs.__union())) {}
template <class _Up, class _OtherErr>
requires __can_convert<_Up, _OtherErr, const _OtherErr&>::value
_LIBCPP_HIDE_FROM_ABI constexpr explicit(!is_convertible_v<const _OtherErr&, _Err>)
expected(const expected<_Up, _OtherErr>& __rhs)
noexcept(is_nothrow_constructible_v<_Err, const _OtherErr&>) // strengthened
- : __base(__rhs.__repr_.__has_val_, __rhs.__repr_.__union_) {}
+ : __base(__rhs.__has_val(), __rhs.__union()) {}
template <class _Up, class _OtherErr>
requires __can_convert<_Up, _OtherErr, _OtherErr>::value
_LIBCPP_HIDE_FROM_ABI constexpr explicit(!is_convertible_v<_OtherErr, _Err>)
expected(expected<_Up, _OtherErr>&& __rhs)
noexcept(is_nothrow_constructible_v<_Err, _OtherErr>) // strengthened
- : __base(__rhs.__repr_.__has_val_, std::move(__rhs.__repr_.__union_)) {}
+ : __base(__rhs.__has_val(), std::move(__rhs.__union())) {}
template <class _OtherErr>
requires is_constructible_v<_Err, const _OtherErr&>
@@ -1459,15 +1386,15 @@ class expected<_Tp, _Err> : private __expected_void_base<_Err> {
noexcept(is_nothrow_copy_assignable_v<_Err> && is_nothrow_copy_constructible_v<_Err>) // strengthened
requires(is_copy_assignable_v<_Err> && is_copy_constructible_v<_Err>)
{
- if (this->__repr_.__has_val_) {
- if (!__rhs.__repr_.__has_val_) {
- __reinit_expected(unexpect, __rhs.__repr_.__union_.__unex_);
+ if (this->__has_val()) {
+ if (!__rhs.__has_val()) {
+ __reinit_expected(unexpect, __rhs.__unex());
}
} else {
- if (__rhs.__repr_.__has_val_) {
+ if (__rhs.__has_val()) {
__reinit_expected(in_place);
} else {
- this->__repr_.__union_.__unex_ = __rhs.__repr_.__union_.__unex_;
+ this->__unex() = __rhs.__unex();
}
}
return *this;
@@ -1481,15 +1408,15 @@ class expected<_Tp, _Err> : private __expected_void_base<_Err> {
requires(is_move_assignable_v<_Err> &&
is_move_constructible_v<_Err>)
{
- if (this->__repr_.__has_val_) {
- if (!__rhs.__repr_.__has_val_) {
- __reinit_expected(unexpect, std::move(__rhs.__repr_.__union_.__unex_));
+ if (this->__has_val()) {
+ if (!__rhs.__has_val()) {
+ __reinit_expected(unexpect, std::move(__rhs.__unex()));
}
} else {
- if (__rhs.__repr_.__has_val_) {
+ if (__rhs.__has_val()) {
__reinit_expected(in_place);
} else {
- this->__repr_.__union_.__unex_ = std::move(__rhs.__repr_.__union_.__unex_);
+ this->__unex() = std::move(__rhs.__unex());
}
}
return *this;
@@ -1498,10 +1425,10 @@ class expected<_Tp, _Err> : private __expected_void_base<_Err> {
template <class _OtherErr>
requires(is_constructible_v<_Err, const _OtherErr&> && is_assignable_v<_Err&, const _OtherErr&>)
_LIBCPP_HIDE_FROM_ABI constexpr expected& operator=(const unexpected<_OtherErr>& __un) {
- if (this->__repr_.__has_val_) {
+ if (this->__has_val()) {
__reinit_expected(unexpect, __un.error());
} else {
- this->__repr_.__union_.__unex_ = __un.error();
+ this->__unex() = __un.error();
}
return *this;
}
@@ -1509,16 +1436,16 @@ class expected<_Tp, _Err> : private __expected_void_base<_Err> {
template <class _OtherErr>
requires(is_constructible_v<_Err, _OtherErr> && is_assignable_v<_Err&, _OtherErr>)
_LIBCPP_HIDE_FROM_ABI constexpr expected& operator=(unexpected<_OtherErr>&& __un) {
- if (this->__repr_.__has_val_) {
+ if (this->__has_val()) {
__reinit_expected(unexpect, std::move(__un.error()));
} else {
- this->__repr_.__union_.__unex_ = std::move(__un.error());
+ this->__unex() = std::move(__un.error());
}
return *this;
}
_LIBCPP_HIDE_FROM_ABI constexpr void emplace() noexcept {
- if (!this->__repr_.__has_val_) {
+ if (!this->__has_val()) {
__reinit_expected(in_place);
}
}
@@ -1530,21 +1457,21 @@ class expected<_Tp, _Err> : private __expected_void_base<_Err> {
{
auto __swap_val_unex_impl = [](expected& __with_val, expected& __with_err) {
// May throw, but will re-engage `__with_val` in that case.
- __with_val.__reinit_expected(unexpect, std::move(__with_err.__repr_.__union_.__unex_));
+ __with_val.__reinit_expected(unexpect, std::move(__with_err.__unex()));
// Will not throw.
__with_err.__reinit_expected(in_place);
};
- if (this->__repr_.__has_val_) {
- if (!__rhs.__repr_.__has_val_) {
+ if (this->__has_val()) {
+ if (!__rhs.__has_val()) {
__swap_val_unex_impl(*this, __rhs);
}
} else {
- if (__rhs.__repr_.__has_val_) {
+ if (__rhs.__has_val()) {
__swap_val_unex_impl(__rhs, *this);
} else {
using std::swap;
- swap(this->__repr_.__union_.__unex_, __rhs.__repr_.__union_.__unex_);
+ swap(this->__unex(), __rhs.__unex());
}
}
}
@@ -1557,44 +1484,44 @@ class expected<_Tp, _Err> : private __expected_void_base<_Err> {
}
// [expected.void.obs], observers
- _LIBCPP_HIDE_FROM_ABI constexpr explicit operator bool() const noexcept { return this->__repr_.__has_val_; }
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit operator bool() const noexcept { return this->__has_val(); }
- _LIBCPP_HIDE_FROM_ABI constexpr bool has_value() const noexcept { return this->__repr_.__has_val_; }
+ _LIBCPP_HIDE_FROM_ABI constexpr bool has_value() const noexcept { return this->__has_val(); }
_LIBCPP_HIDE_FROM_ABI constexpr void operator*() const noexcept {
- _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(this->__repr_.__has_val_, "expected::operator* requires the expected to contain a value");
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(this->__has_val(), "expected::operator* requires the expected to contain a value");
}
_LIBCPP_HIDE_FROM_ABI constexpr void value() const& {
- if (!this->__repr_.__has_val_) {
- std::__throw_bad_expected_access<_Err>(this->__repr_.__union_.__unex_);
+ if (!this->__has_val()) {
+ std::__throw_bad_expected_access<_Err>(this->__unex());
}
}
_LIBCPP_HIDE_FROM_ABI constexpr void value() && {
- if (!this->__repr_.__has_val_) {
- std::__throw_bad_expected_access<_Err>(std::move(this->__repr_.__union_.__unex_));
+ if (!this->__has_val()) {
+ std::__throw_bad_expected_access<_Err>(std::move(this->__unex()));
}
}
_LIBCPP_HIDE_FROM_ABI constexpr const _Err& error() const& noexcept {
- _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!this->__repr_.__has_val_, "expected::error requires the expected to contain an error");
- return this->__repr_.__union_.__unex_;
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!this->__has_val(), "expected::error requires the expected to contain an error");
+ return this->__unex();
}
_LIBCPP_HIDE_FROM_ABI constexpr _Err& error() & noexcept {
- _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!this->__repr_.__has_val_, "expected::error requires the expected to contain an error");
- return this->__repr_.__union_.__unex_;
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!this->__has_val(), "expected::error requires the expected to contain an error");
+ return this->__unex();
}
_LIBCPP_HIDE_FROM_ABI constexpr const _Err&& error() const&& noexcept {
- _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!this->__repr_.__has_val_, "expected::error requires the expected to contain an error");
- return std::move(this->__repr_.__union_.__unex_);
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!this->__has_val(), "expected::error requires the expected to contain an error");
+ return std::move(this->__unex());
}
_LIBCPP_HIDE_FROM_ABI constexpr _Err&& error() && noexcept {
- _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!this->__repr_.__has_val_, "expected::error requires the expected to contain an error");
- return std::move(this->__repr_.__union_.__unex_);
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!this->__has_val(), "expected::error requires the expected to contain an error");
+ return std::move(this->__unex());
}
template <class _Up = _Err>
@@ -1830,16 +1757,16 @@ class expected<_Tp, _Err> : private __expected_void_base<_Err> {
template <class _T2, class _E2>
requires is_void_v<_T2>
_LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const expected& __x, const expected<_T2, _E2>& __y) {
- if (__x.__repr_.__has_val_ != __y.__repr_.__has_val_) {
+ if (__x.__has_val() != __y.__has_val()) {
return false;
} else {
- return __x.__repr_.__has_val_ || static_cast<bool>(__x.__repr_.__union_.__unex_ == __y.__repr_.__union_.__unex_);
+ return __x.__has_val() || static_cast<bool>(__x.__unex() == __y.__unex());
}
}
template <class _E2>
_LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const expected& __x, const unexpected<_E2>& __y) {
- return !__x.__repr_.__has_val_ && static_cast<bool>(__x.__repr_.__union_.__unex_ == __y.error());
+ return !__x.__has_val() && static_cast<bool>(__x.__unex() == __y.error());
}
};
diff --git a/libcxx/test/libcxx/utilities/expected/expected.void/no_unique_address.compile.pass.cpp b/libcxx/test/libcxx/utilities/expected/expected.void/no_unique_address.compile.pass.cpp
index e764dbd66acaa..eab2acf147184 100644
--- a/libcxx/test/libcxx/utilities/expected/expected.void/no_unique_address.compile.pass.cpp
+++ b/libcxx/test/libcxx/utilities/expected/expected.void/no_unique_address.compile.pass.cpp
@@ -38,7 +38,7 @@ struct BoolWithPadding {
static_assert(sizeof(std::expected<void, Empty>) == sizeof(bool));
static_assert(sizeof(std::expected<void, A>) == 2 * sizeof(int) + alignof(std::expected<void, A>));
-static_assert(sizeof(std::expected<void, B>) == sizeof(B) + alignof(std::expected<void, B>));
+static_assert(sizeof(std::expected<void, B>) == sizeof(B));
// Check that `expected`'s datasize is large enough for the parameter type(s).
static_assert(sizeof(std::expected<void, BoolWithPadding>) ==
diff --git a/libcxx/test/libcxx/utilities/expected/expected.void/transform_error.mandates.verify.cpp b/libcxx/test/libcxx/utilities/expected/expected.void/transform_error.mandates.verify.cpp
index 7687a42cb1a86..9c8cbcdaaa6d6 100644
--- a/libcxx/test/libcxx/utilities/expected/expected.void/transform_error.mandates.verify.cpp
+++ b/libcxx/test/libcxx/utilities/expected/expected.void/transform_error.mandates.verify.cpp
@@ -48,12 +48,12 @@ void test() {
e.transform_error(return_unexpected<int&>); // expected-error-re@*:* {{static assertion failed {{.*}}The result of {{.*}} must be a valid template argument for unexpected}}
// expected-error-re@*:* {{{{(excess elements in struct initializer|no matching constructor for initialization of)}}{{.*}}}}
// expected-error-re@*:* {{static assertion failed {{.*}}A program that instantiates expected<T, E> with a E that is not a valid argument for unexpected<E> is ill-formed}}
- // expected-error-re@*:* {{union member {{.*}} has reference type {{.*}}}}
// expected-error-re@*:* {{call to deleted constructor of {{.*}}}}
e.transform_error(return_no_object<int&>); // expected-error-re@*:* {{static assertion failed {{.*}}The result of {{.*}} must be a valid template argument for unexpected}}
// expected-error-re@*:* {{{{(excess elements in struct initializer|no matching constructor for initialization of)}}{{.*}}}}
// expected-error-re@*:* {{static assertion failed {{.*}}A program that instantiates expected<T, E> with a E that is not a valid argument for unexpected<E> is ill-formed}}
+ // expected-error-re@*:* {{call to deleted constructor of {{.*}}}}
}
// Test const& overload
>From a75e0f16a8b30e69aa2796b3b1e834e5e9d3c08a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jan=20Kokem=C3=BCller?= <jan.kokemueller at gmail.com>
Date: Wed, 25 Oct 2023 21:11:27 +0200
Subject: [PATCH 24/37] add missing __repr and __union_t operators to be more
explicit
---
libcxx/include/__expected/expected.h | 26 ++++++++++++++++++++++----
1 file changed, 22 insertions(+), 4 deletions(-)
diff --git a/libcxx/include/__expected/expected.h b/libcxx/include/__expected/expected.h
index e0f5489d2207a..529965f60c2cb 100644
--- a/libcxx/include/__expected/expected.h
+++ b/libcxx/include/__expected/expected.h
@@ -143,9 +143,18 @@ class __expected_base {
// it's not clear that it's implementable, given that the function is allowed to clobber
// the tail padding) - see https://github.com/itanium-cxx-abi/cxx-abi/issues/107.
union __union_t {
- _LIBCPP_HIDE_FROM_ABI constexpr __union_t(const __union_t&) = default;
- _LIBCPP_HIDE_FROM_ABI constexpr __union_t(__union_t&&) = default;
+ _LIBCPP_HIDE_FROM_ABI constexpr __union_t(const __union_t&) = delete;
+ _LIBCPP_HIDE_FROM_ABI constexpr __union_t(const __union_t&)
+ requires(is_copy_constructible_v<_Tp> && is_copy_constructible_v<_Err> &&
+ is_trivially_copy_constructible_v<_Tp> && is_trivially_copy_constructible_v<_Err>)
+ = default;
+ _LIBCPP_HIDE_FROM_ABI constexpr __union_t(__union_t&&) = delete;
+ _LIBCPP_HIDE_FROM_ABI constexpr __union_t(__union_t&&)
+ requires(is_move_constructible_v<_Tp> && is_move_constructible_v<_Err> &&
+ is_trivially_move_constructible_v<_Tp> && is_trivially_move_constructible_v<_Err>)
+ = default;
_LIBCPP_HIDE_FROM_ABI constexpr __union_t& operator=(const __union_t&) = delete;
+ _LIBCPP_HIDE_FROM_ABI constexpr __union_t& operator=(__union_t&&) = delete;
template <class... _Args>
_LIBCPP_HIDE_FROM_ABI constexpr explicit __union_t(in_place_t, _Args&&... __args)
@@ -220,6 +229,7 @@ class __expected_base {
= default;
_LIBCPP_HIDE_FROM_ABI constexpr __repr& operator=(const __repr&) = delete;
+ _LIBCPP_HIDE_FROM_ABI constexpr __repr& operator=(__repr&&) = delete;
_LIBCPP_HIDE_FROM_ABI constexpr ~__repr()
requires(is_trivially_destructible_v<_Tp> && is_trivially_destructible_v<_Err>)
@@ -1081,9 +1091,16 @@ class __expected_void_base {
// it's not clear that it's implementable, given that the function is allowed to clobber
// the tail padding) - see https://github.com/itanium-cxx-abi/cxx-abi/issues/107.
union __union_t {
- _LIBCPP_HIDE_FROM_ABI constexpr __union_t(const __union_t&) = default;
- _LIBCPP_HIDE_FROM_ABI constexpr __union_t(__union_t&&) = default;
+ _LIBCPP_HIDE_FROM_ABI constexpr __union_t(const __union_t&) = delete;
+ _LIBCPP_HIDE_FROM_ABI constexpr __union_t(const __union_t&)
+ requires(is_copy_constructible_v<_Err> && is_trivially_copy_constructible_v<_Err>)
+ = default;
+ _LIBCPP_HIDE_FROM_ABI constexpr __union_t(__union_t&&) = delete;
+ _LIBCPP_HIDE_FROM_ABI constexpr __union_t(__union_t&&)
+ requires(is_move_constructible_v<_Err> && is_trivially_move_constructible_v<_Err>)
+ = default;
_LIBCPP_HIDE_FROM_ABI constexpr __union_t& operator=(const __union_t&) = delete;
+ _LIBCPP_HIDE_FROM_ABI constexpr __union_t& operator=(__union_t&&) = delete;
_LIBCPP_HIDE_FROM_ABI constexpr explicit __union_t(in_place_t) : __empty_() {}
@@ -1145,6 +1162,7 @@ class __expected_void_base {
= default;
_LIBCPP_HIDE_FROM_ABI constexpr __repr& operator=(const __repr&) = delete;
+ _LIBCPP_HIDE_FROM_ABI constexpr __repr& operator=(__repr&&) = delete;
_LIBCPP_HIDE_FROM_ABI constexpr ~__repr()
requires(is_trivially_destructible_v<_Err>)
>From e3607fd066827fd7f33cd8895276fd7e7a492e15 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jan=20Kokem=C3=BCller?= <jan.kokemueller at gmail.com>
Date: Thu, 26 Oct 2023 07:00:22 +0200
Subject: [PATCH 25/37] fix invalid case style
---
libcxx/include/__expected/expected.h | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/libcxx/include/__expected/expected.h b/libcxx/include/__expected/expected.h
index 529965f60c2cb..0208125e07bce 100644
--- a/libcxx/include/__expected/expected.h
+++ b/libcxx/include/__expected/expected.h
@@ -130,8 +130,8 @@ _LIBCPP_HIDE_FROM_ABI constexpr bool __expected_can_stuff_tail()
{
struct __x {
private:
- _LIBCPP_NO_UNIQUE_ADDRESS _Union __union;
- _LIBCPP_NO_UNIQUE_ADDRESS bool __has_val;
+ _LIBCPP_NO_UNIQUE_ADDRESS _Union __union_;
+ _LIBCPP_NO_UNIQUE_ADDRESS bool __has_val_;
};
return sizeof(__x) == sizeof(_Union);
}
>From 54b8899eff05d4e473cfc26d6c251604464026cc Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jan=20Kokem=C3=BCller?= <jan.kokemueller at gmail.com>
Date: Thu, 26 Oct 2023 11:35:06 +0200
Subject: [PATCH 26/37] try to fix layout tests for 32-bit platforms
---
.../expected.expected/no_unique_address.compile.pass.cpp | 1 +
.../expected/expected.void/no_unique_address.compile.pass.cpp | 1 +
2 files changed, 2 insertions(+)
diff --git a/libcxx/test/libcxx/utilities/expected/expected.expected/no_unique_address.compile.pass.cpp b/libcxx/test/libcxx/utilities/expected/expected.expected/no_unique_address.compile.pass.cpp
index 4d523d1ad6950..cf1909b928732 100644
--- a/libcxx/test/libcxx/utilities/expected/expected.expected/no_unique_address.compile.pass.cpp
+++ b/libcxx/test/libcxx/utilities/expected/expected.expected/no_unique_address.compile.pass.cpp
@@ -26,6 +26,7 @@ struct A {
struct B : public A {
int z_;
+ short z2_;
virtual ~B() = default;
};
diff --git a/libcxx/test/libcxx/utilities/expected/expected.void/no_unique_address.compile.pass.cpp b/libcxx/test/libcxx/utilities/expected/expected.void/no_unique_address.compile.pass.cpp
index eab2acf147184..d533762340d1c 100644
--- a/libcxx/test/libcxx/utilities/expected/expected.void/no_unique_address.compile.pass.cpp
+++ b/libcxx/test/libcxx/utilities/expected/expected.void/no_unique_address.compile.pass.cpp
@@ -26,6 +26,7 @@ struct A {
struct B : public A {
int z_;
+ short z2_;
virtual ~B() = default;
};
>From a3e468f4b5cb9295519f069bb0eb270a8dead271 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jan=20Kokem=C3=BCller?= <jan.kokemueller at gmail.com>
Date: Thu, 26 Oct 2023 15:21:25 +0200
Subject: [PATCH 27/37] remove conditional [[no_unique_address]] of union
members
---
libcxx/include/__expected/expected.h | 42 ++++++++-----------
.../transform_error.mandates.verify.cpp | 1 +
.../transform_error.mandates.verify.cpp | 2 +-
3 files changed, 20 insertions(+), 25 deletions(-)
diff --git a/libcxx/include/__expected/expected.h b/libcxx/include/__expected/expected.h
index 0208125e07bce..d817a6bce9a45 100644
--- a/libcxx/include/__expected/expected.h
+++ b/libcxx/include/__expected/expected.h
@@ -88,9 +88,6 @@ _LIBCPP_HIDE_FROM_ABI void __throw_bad_expected_access(_Arg&& __arg) {
# endif
}
-template <class _Tp>
-concept __expected_union_member_no_unique_address = is_nothrow_move_constructible_v<_Tp>;
-
struct __expected_invoke_tag {};
template <bool _NoUnique, class _Tp>
@@ -167,12 +164,12 @@ class __expected_base {
template <class _Func, class... _Args>
_LIBCPP_HIDE_FROM_ABI constexpr explicit __union_t(
std::__expected_construct_in_place_from_invoke_tag, _Func&& __f, _Args&&... __args)
- : __val_(__expected_invoke_tag{}, std::forward<_Func>(__f), std::forward<_Args>(__args)...) {}
+ : __val_(std::invoke(std::forward<_Func>(__f), std::forward<_Args>(__args)...)) {}
template <class _Func, class... _Args>
_LIBCPP_HIDE_FROM_ABI constexpr explicit __union_t(
std::__expected_construct_unexpected_from_invoke_tag, _Func&& __f, _Args&&... __args)
- : __unex_(__expected_invoke_tag{}, std::forward<_Func>(__f), std::forward<_Args>(__args)...) {}
+ : __unex_(std::invoke(std::forward<_Func>(__f), std::forward<_Args>(__args)...)) {}
_LIBCPP_HIDE_FROM_ABI constexpr ~__union_t()
requires(is_trivially_destructible_v<_Tp> && is_trivially_destructible_v<_Err>)
@@ -181,10 +178,8 @@ class __expected_base {
// __repr's destructor handles this
_LIBCPP_HIDE_FROM_ABI constexpr ~__union_t() {}
- _LIBCPP_NO_UNIQUE_ADDRESS __expected_conditional_no_unique_address<
- __expected_union_member_no_unique_address<_Tp>, _Tp>::__type __val_;
- _LIBCPP_NO_UNIQUE_ADDRESS __expected_conditional_no_unique_address<
- __expected_union_member_no_unique_address<_Err>, _Err>::__type __unex_;
+ _LIBCPP_NO_UNIQUE_ADDRESS _Tp __val_;
+ _LIBCPP_NO_UNIQUE_ADDRESS _Err __unex_;
};
static constexpr bool __can_stuff_tail = __expected_can_stuff_tail<__union_t>();
@@ -289,9 +284,9 @@ class __expected_base {
requires(!__can_stuff_tail)
{
if (__has_val)
- return __union_t(in_place, std::forward<_OtherUnion>(__other).__val_.__v);
+ return __union_t(in_place, std::forward<_OtherUnion>(__other).__val_);
else
- return __union_t(unexpect, std::forward<_OtherUnion>(__other).__unex_.__v);
+ return __union_t(unexpect, std::forward<_OtherUnion>(__other).__unex_);
}
_LIBCPP_NO_UNIQUE_ADDRESS __expected_conditional_no_unique_address<
@@ -304,9 +299,9 @@ class __expected_base {
requires(__can_stuff_tail)
{
if (__has_val)
- return __repr(in_place, std::forward<_OtherUnion>(__other).__val_.__v);
+ return __repr(in_place, std::forward<_OtherUnion>(__other).__val_);
else
- return __repr(unexpect, std::forward<_OtherUnion>(__other).__unex_.__v);
+ return __repr(unexpect, std::forward<_OtherUnion>(__other).__unex_);
}
protected:
@@ -338,10 +333,10 @@ class __expected_base {
_LIBCPP_HIDE_FROM_ABI constexpr bool __has_val() const { return __repr_.__v.__has_val_; }
_LIBCPP_HIDE_FROM_ABI constexpr __union_t& __union() { return __repr_.__v.__union_.__v; }
_LIBCPP_HIDE_FROM_ABI constexpr const __union_t& __union() const { return __repr_.__v.__union_.__v; }
- _LIBCPP_HIDE_FROM_ABI constexpr _Tp& __val() { return __repr_.__v.__union_.__v.__val_.__v; }
- _LIBCPP_HIDE_FROM_ABI constexpr const _Tp& __val() const { return __repr_.__v.__union_.__v.__val_.__v; }
- _LIBCPP_HIDE_FROM_ABI constexpr _Err& __unex() { return __repr_.__v.__union_.__v.__unex_.__v; }
- _LIBCPP_HIDE_FROM_ABI constexpr const _Err& __unex() const { return __repr_.__v.__union_.__v.__unex_.__v; }
+ _LIBCPP_HIDE_FROM_ABI constexpr _Tp& __val() { return __repr_.__v.__union_.__v.__val_; }
+ _LIBCPP_HIDE_FROM_ABI constexpr const _Tp& __val() const { return __repr_.__v.__union_.__v.__val_; }
+ _LIBCPP_HIDE_FROM_ABI constexpr _Err& __unex() { return __repr_.__v.__union_.__v.__unex_; }
+ _LIBCPP_HIDE_FROM_ABI constexpr const _Err& __unex() const { return __repr_.__v.__union_.__v.__unex_; }
private:
_LIBCPP_NO_UNIQUE_ADDRESS __expected_conditional_no_unique_address<
@@ -1111,7 +1106,7 @@ class __expected_void_base {
template <class _Func, class... _Args>
_LIBCPP_HIDE_FROM_ABI constexpr explicit __union_t(
__expected_construct_unexpected_from_invoke_tag, _Func&& __f, _Args&&... __args)
- : __unex_(__expected_invoke_tag{}, std::forward<_Func>(__f), std::forward<_Args>(__args)...) {}
+ : __unex_(std::invoke(std::forward<_Func>(__f), std::forward<_Args>(__args)...)) {}
_LIBCPP_HIDE_FROM_ABI constexpr ~__union_t()
requires(is_trivially_destructible_v<_Err>)
@@ -1123,8 +1118,7 @@ class __expected_void_base {
{}
_LIBCPP_NO_UNIQUE_ADDRESS __empty_t __empty_;
- _LIBCPP_NO_UNIQUE_ADDRESS __expected_conditional_no_unique_address<
- __expected_union_member_no_unique_address<_Err>, _Err>::__type __unex_;
+ _LIBCPP_NO_UNIQUE_ADDRESS _Err __unex_;
};
static constexpr bool __can_stuff_tail = __expected_can_stuff_tail<__union_t>();
@@ -1220,7 +1214,7 @@ class __expected_void_base {
if (__has_val)
return __union_t(in_place);
else
- return __union_t(unexpect, std::forward<_OtherUnion>(__other).__unex_.__v);
+ return __union_t(unexpect, std::forward<_OtherUnion>(__other).__unex_);
}
_LIBCPP_NO_UNIQUE_ADDRESS __expected_conditional_no_unique_address<
@@ -1235,7 +1229,7 @@ class __expected_void_base {
if (__has_val)
return __repr(in_place);
else
- return __repr(unexpect, std::forward<_OtherUnion>(__other).__unex_.__v);
+ return __repr(unexpect, std::forward<_OtherUnion>(__other).__unex_);
}
protected:
@@ -1267,8 +1261,8 @@ class __expected_void_base {
_LIBCPP_HIDE_FROM_ABI constexpr bool __has_val() const { return __repr_.__v.__has_val_; }
_LIBCPP_HIDE_FROM_ABI constexpr __union_t& __union() { return __repr_.__v.__union_.__v; }
_LIBCPP_HIDE_FROM_ABI constexpr const __union_t& __union() const { return __repr_.__v.__union_.__v; }
- _LIBCPP_HIDE_FROM_ABI constexpr _Err& __unex() { return __repr_.__v.__union_.__v.__unex_.__v; }
- _LIBCPP_HIDE_FROM_ABI constexpr const _Err& __unex() const { return __repr_.__v.__union_.__v.__unex_.__v; }
+ _LIBCPP_HIDE_FROM_ABI constexpr _Err& __unex() { return __repr_.__v.__union_.__v.__unex_; }
+ _LIBCPP_HIDE_FROM_ABI constexpr const _Err& __unex() const { return __repr_.__v.__union_.__v.__unex_; }
private:
_LIBCPP_NO_UNIQUE_ADDRESS __expected_conditional_no_unique_address<
diff --git a/libcxx/test/libcxx/utilities/expected/expected.expected/transform_error.mandates.verify.cpp b/libcxx/test/libcxx/utilities/expected/expected.expected/transform_error.mandates.verify.cpp
index 965e82a7b4034..16faddb280d3a 100644
--- a/libcxx/test/libcxx/utilities/expected/expected.expected/transform_error.mandates.verify.cpp
+++ b/libcxx/test/libcxx/utilities/expected/expected.expected/transform_error.mandates.verify.cpp
@@ -48,6 +48,7 @@ void test() {
e.transform_error(return_unexpected<int&>); // expected-error-re@*:* {{static assertion failed {{.*}}The result of {{.*}} must be a valid template argument for unexpected}}
// expected-error-re@*:* {{{{(excess elements in struct initializer|no matching constructor for initialization of)}}{{.*}}}}
// expected-error-re@*:* {{static assertion failed {{.*}}[expected.object.general] A program that instantiates the definition of template expected<T, E> for {{.*}} is ill-formed.}}
+ // expected-error-re@*:* {{union member {{.*}} has reference type {{.*}}}}
e.transform_error(return_no_object<int&>); // expected-error-re@*:* {{static assertion failed {{.*}}The result of {{.*}} must be a valid template argument for unexpected}}
// expected-error-re@*:* {{{{(excess elements in struct initializer|no matching constructor for initialization of)}}{{.*}}}}
diff --git a/libcxx/test/libcxx/utilities/expected/expected.void/transform_error.mandates.verify.cpp b/libcxx/test/libcxx/utilities/expected/expected.void/transform_error.mandates.verify.cpp
index 9c8cbcdaaa6d6..c626739528987 100644
--- a/libcxx/test/libcxx/utilities/expected/expected.void/transform_error.mandates.verify.cpp
+++ b/libcxx/test/libcxx/utilities/expected/expected.void/transform_error.mandates.verify.cpp
@@ -49,11 +49,11 @@ void test() {
// expected-error-re@*:* {{{{(excess elements in struct initializer|no matching constructor for initialization of)}}{{.*}}}}
// expected-error-re@*:* {{static assertion failed {{.*}}A program that instantiates expected<T, E> with a E that is not a valid argument for unexpected<E> is ill-formed}}
// expected-error-re@*:* {{call to deleted constructor of {{.*}}}}
+ // expected-error-re@*:* {{union member {{.*}} has reference type {{.*}}}}
e.transform_error(return_no_object<int&>); // expected-error-re@*:* {{static assertion failed {{.*}}The result of {{.*}} must be a valid template argument for unexpected}}
// expected-error-re@*:* {{{{(excess elements in struct initializer|no matching constructor for initialization of)}}{{.*}}}}
// expected-error-re@*:* {{static assertion failed {{.*}}A program that instantiates expected<T, E> with a E that is not a valid argument for unexpected<E> is ill-formed}}
- // expected-error-re@*:* {{call to deleted constructor of {{.*}}}}
}
// Test const& overload
>From 3590b065bc512452d3d6600a8939535bd11962f8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jan=20Kokem=C3=BCller?= <jan.kokemueller at gmail.com>
Date: Thu, 26 Oct 2023 19:14:01 +0200
Subject: [PATCH 28/37] mark transform tests as failing for GCC
---
.../expected/expected.expected/monadic/transform.pass.cpp | 4 ++--
.../expected.expected/monadic/transform_error.pass.cpp | 4 ++--
.../expected/expected.void/monadic/transform_error.pass.cpp | 4 ++--
3 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/libcxx/test/std/utilities/expected/expected.expected/monadic/transform.pass.cpp b/libcxx/test/std/utilities/expected/expected.expected/monadic/transform.pass.cpp
index f443613fe7f34..424295bffdf2a 100644
--- a/libcxx/test/std/utilities/expected/expected.expected/monadic/transform.pass.cpp
+++ b/libcxx/test/std/utilities/expected/expected.expected/monadic/transform.pass.cpp
@@ -9,8 +9,8 @@
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
// GCC has a issue for `Guaranteed copy elision for potentially-overlapping non-static data members`,
-// please refer to: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108333, but we have a workaround to
-// avoid this issue.
+// please refer to: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108333
+// XFAIL: gcc
// <expected>
diff --git a/libcxx/test/std/utilities/expected/expected.expected/monadic/transform_error.pass.cpp b/libcxx/test/std/utilities/expected/expected.expected/monadic/transform_error.pass.cpp
index 84b57aea3cd23..23bf6783a14b1 100644
--- a/libcxx/test/std/utilities/expected/expected.expected/monadic/transform_error.pass.cpp
+++ b/libcxx/test/std/utilities/expected/expected.expected/monadic/transform_error.pass.cpp
@@ -9,8 +9,8 @@
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
// GCC has a issue for `Guaranteed copy elision for potentially-overlapping non-static data members`,
-// please refer to: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108333, but we have a workaround to
-// avoid this issue.
+// please refer to: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108333.
+// XFAIL: gcc
// <expected>
diff --git a/libcxx/test/std/utilities/expected/expected.void/monadic/transform_error.pass.cpp b/libcxx/test/std/utilities/expected/expected.void/monadic/transform_error.pass.cpp
index f0e19ac3c3982..0c41d11dd66fd 100644
--- a/libcxx/test/std/utilities/expected/expected.void/monadic/transform_error.pass.cpp
+++ b/libcxx/test/std/utilities/expected/expected.void/monadic/transform_error.pass.cpp
@@ -9,8 +9,8 @@
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
// GCC has a issue for `Guaranteed copy elision for potentially-overlapping non-static data members`,
-// please refer to: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108333, but we have a workaround to
-// avoid this issue.
+// please refer to: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108333
+// XFAIL: gcc
// <expected>
>From 4a6fdead8c2651ddb4b40863826d07e48c9855c4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jan=20Kokem=C3=BCller?= <jan.kokemueller at gmail.com>
Date: Thu, 2 Nov 2023 20:51:58 +0100
Subject: [PATCH 29/37] simplify __expected_conditional_no_unique_address and
rename to __conditional_no_unique_address
---
libcxx/include/__expected/expected.h | 67 +++++++++++++---------------
1 file changed, 31 insertions(+), 36 deletions(-)
diff --git a/libcxx/include/__expected/expected.h b/libcxx/include/__expected/expected.h
index d817a6bce9a45..5fab06095d467 100644
--- a/libcxx/include/__expected/expected.h
+++ b/libcxx/include/__expected/expected.h
@@ -88,38 +88,37 @@ _LIBCPP_HIDE_FROM_ABI void __throw_bad_expected_access(_Arg&& __arg) {
# endif
}
-struct __expected_invoke_tag {};
+struct __conditional_no_unique_address_invoke_tag {};
template <bool _NoUnique, class _Tp>
-class __expected_conditional_no_unique_address {
- struct __unique {
- template <class... _Args>
- _LIBCPP_HIDE_FROM_ABI constexpr explicit __unique(_Args&&... __args)
- : __v(std::forward<_Args>(__args)...) {}
+struct __conditional_no_unique_address;
- template <class _Func, class... _Args>
- _LIBCPP_HIDE_FROM_ABI constexpr explicit __unique(
- __expected_invoke_tag, _Func&& __f, _Args&&... __args)
- : __v(std::invoke(std::forward<_Func>(__f), std::forward<_Args>(__args)...)) {}
+template <class _Tp>
+struct __conditional_no_unique_address<true, _Tp> {
+ template <class... _Args>
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit __conditional_no_unique_address(_Args&&... __args)
+ : __v(std::forward<_Args>(__args)...) {}
- _Tp __v;
- };
+ template <class _Func, class... _Args>
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit __conditional_no_unique_address(
+ __conditional_no_unique_address_invoke_tag, _Func&& __f, _Args&&... __args)
+ : __v(std::invoke(std::forward<_Func>(__f), std::forward<_Args>(__args)...)) {}
- struct __no_unique {
- template <class... _Args>
- _LIBCPP_HIDE_FROM_ABI constexpr explicit __no_unique(_Args&&... __args)
- : __v(std::forward<_Args>(__args)...) {}
+ _LIBCPP_NO_UNIQUE_ADDRESS _Tp __v;
+};
- template <class _Func, class... _Args>
- _LIBCPP_HIDE_FROM_ABI constexpr explicit __no_unique(
- __expected_invoke_tag, _Func&& __f, _Args&&... __args)
- : __v(std::invoke(std::forward<_Func>(__f), std::forward<_Args>(__args)...)) {}
+template <class _Tp>
+struct __conditional_no_unique_address<false, _Tp> {
+ template <class... _Args>
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit __conditional_no_unique_address(_Args&&... __args)
+ : __v(std::forward<_Args>(__args)...) {}
- _LIBCPP_NO_UNIQUE_ADDRESS _Tp __v;
- };
+ template <class _Func, class... _Args>
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit __conditional_no_unique_address(
+ __conditional_no_unique_address_invoke_tag, _Func&& __f, _Args&&... __args)
+ : __v(std::invoke(std::forward<_Func>(__f), std::forward<_Args>(__args)...)) {}
-public:
- using __type = std::conditional<_NoUnique, __no_unique, __unique>::type;
+ _Tp __v;
};
template <class _Union>
@@ -208,7 +207,7 @@ class __expected_base {
template <class _OtherUnion>
_LIBCPP_HIDE_FROM_ABI constexpr explicit __repr(bool __has_val, _OtherUnion&& __other)
requires(!__can_stuff_tail)
- : __union_(__expected_invoke_tag{},
+ : __union_(__conditional_no_unique_address_invoke_tag{},
[&] { return __make_union(__has_val, std::forward<_OtherUnion>(__other)); }),
__has_val_(__has_val) {}
@@ -289,8 +288,7 @@ class __expected_base {
return __union_t(unexpect, std::forward<_OtherUnion>(__other).__unex_);
}
- _LIBCPP_NO_UNIQUE_ADDRESS __expected_conditional_no_unique_address<
- __can_stuff_tail, __union_t>::__type __union_;
+ _LIBCPP_NO_UNIQUE_ADDRESS __conditional_no_unique_address<__can_stuff_tail, __union_t> __union_;
_LIBCPP_NO_UNIQUE_ADDRESS bool __has_val_;
};
@@ -312,7 +310,7 @@ class __expected_base {
template <class _OtherUnion>
_LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_base(bool __has_val, _OtherUnion&& __other)
requires(__can_stuff_tail)
- : __repr_(__expected_invoke_tag{},
+ : __repr_(__conditional_no_unique_address_invoke_tag{},
[&] { return __make_repr(__has_val, std::forward<_OtherUnion>(__other)); }) {}
_LIBCPP_HIDE_FROM_ABI constexpr void __destroy() {
@@ -339,8 +337,7 @@ class __expected_base {
_LIBCPP_HIDE_FROM_ABI constexpr const _Err& __unex() const { return __repr_.__v.__union_.__v.__unex_; }
private:
- _LIBCPP_NO_UNIQUE_ADDRESS __expected_conditional_no_unique_address<
- !__can_stuff_tail, __repr>::__type __repr_;
+ _LIBCPP_NO_UNIQUE_ADDRESS __conditional_no_unique_address<!__can_stuff_tail, __repr> __repr_;
};
template <class _Tp, class _Err>
@@ -1142,7 +1139,7 @@ class __expected_void_base {
template <class _OtherUnion>
_LIBCPP_HIDE_FROM_ABI constexpr explicit __repr(bool __has_val, _OtherUnion&& __other)
requires(!__can_stuff_tail)
- : __union_(__expected_invoke_tag{},
+ : __union_(__conditional_no_unique_address_invoke_tag{},
[&] { return __make_union(__has_val, std::forward<_OtherUnion>(__other)); }),
__has_val_(__has_val) {}
@@ -1217,8 +1214,7 @@ class __expected_void_base {
return __union_t(unexpect, std::forward<_OtherUnion>(__other).__unex_);
}
- _LIBCPP_NO_UNIQUE_ADDRESS __expected_conditional_no_unique_address<
- __can_stuff_tail, __union_t>::__type __union_;
+ _LIBCPP_NO_UNIQUE_ADDRESS __conditional_no_unique_address<__can_stuff_tail, __union_t> __union_;
_LIBCPP_NO_UNIQUE_ADDRESS bool __has_val_;
};
@@ -1240,7 +1236,7 @@ class __expected_void_base {
template <class _OtherUnion>
_LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_void_base(bool __has_val, _OtherUnion&& __other)
requires(__can_stuff_tail)
- : __repr_(__expected_invoke_tag{},
+ : __repr_(__conditional_no_unique_address_invoke_tag{},
[&] { return __make_repr(__has_val, std::forward<_OtherUnion>(__other)); }) {}
_LIBCPP_HIDE_FROM_ABI constexpr void __destroy() {
@@ -1265,8 +1261,7 @@ class __expected_void_base {
_LIBCPP_HIDE_FROM_ABI constexpr const _Err& __unex() const { return __repr_.__v.__union_.__v.__unex_; }
private:
- _LIBCPP_NO_UNIQUE_ADDRESS __expected_conditional_no_unique_address<
- !__can_stuff_tail, __repr>::__type __repr_;
+ _LIBCPP_NO_UNIQUE_ADDRESS __conditional_no_unique_address<!__can_stuff_tail, __repr> __repr_;
};
template <class _Tp, class _Err>
>From 4b6c4daba00d6fa0ce59ea94d469bf272c0d1f5d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jan=20Kokem=C3=BCller?= <jan.kokemueller at gmail.com>
Date: Thu, 2 Nov 2023 20:53:19 +0100
Subject: [PATCH 30/37] add comment to __conditional_no_unique_address
suggested by ldionne
---
libcxx/include/__expected/expected.h | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/libcxx/include/__expected/expected.h b/libcxx/include/__expected/expected.h
index 5fab06095d467..ed8c247e71080 100644
--- a/libcxx/include/__expected/expected.h
+++ b/libcxx/include/__expected/expected.h
@@ -90,6 +90,10 @@ _LIBCPP_HIDE_FROM_ABI void __throw_bad_expected_access(_Arg&& __arg) {
struct __conditional_no_unique_address_invoke_tag {};
+// This class implements an object with `[[no_unique_address]]` conditionally applied to it,
+// based on the value of `_NoUnique`.
+//
+// If we had a language feature, this class would basically be replaced by `[[no_unique_address(condition)]]`.
template <bool _NoUnique, class _Tp>
struct __conditional_no_unique_address;
>From 63c7d52c38fbc6e9a76a387a1372bb32bb1c3e06 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jan=20Kokem=C3=BCller?= <jan.kokemueller at gmail.com>
Date: Thu, 2 Nov 2023 21:04:56 +0100
Subject: [PATCH 31/37] add another comment explaining usage of
__conditional_no_unique_address
---
libcxx/include/__expected/expected.h | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/libcxx/include/__expected/expected.h b/libcxx/include/__expected/expected.h
index ed8c247e71080..752233fa38180 100644
--- a/libcxx/include/__expected/expected.h
+++ b/libcxx/include/__expected/expected.h
@@ -93,6 +93,12 @@ struct __conditional_no_unique_address_invoke_tag {};
// This class implements an object with `[[no_unique_address]]` conditionally applied to it,
// based on the value of `_NoUnique`.
//
+// A member of this class must always have `[[no_unique_address]]` applied to
+// it. Otherwise, the `[[no_unique_address]]` in the "`_NoUnique == true`" case
+// would not have any effect. In the `false` case, the `__v` is not
+// `[[no_unique_address]]`, so nullifies the effects of the "outer"
+// `[[no_unique_address]]` regarding data layout.
+//
// If we had a language feature, this class would basically be replaced by `[[no_unique_address(condition)]]`.
template <bool _NoUnique, class _Tp>
struct __conditional_no_unique_address;
>From 89f7497804f49717ef420615a27b026e46c82610 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jan=20Kokem=C3=BCller?= <jan.kokemueller at gmail.com>
Date: Thu, 2 Nov 2023 21:18:07 +0100
Subject: [PATCH 32/37] rename __expected_can_stuff_tail to
__fits_in_tail_padding and make more general
Suggested by ldionne.
---
libcxx/include/__expected/expected.h | 68 ++++++++++++++--------------
1 file changed, 34 insertions(+), 34 deletions(-)
diff --git a/libcxx/include/__expected/expected.h b/libcxx/include/__expected/expected.h
index 752233fa38180..9d38795f71e6f 100644
--- a/libcxx/include/__expected/expected.h
+++ b/libcxx/include/__expected/expected.h
@@ -131,16 +131,16 @@ struct __conditional_no_unique_address<false, _Tp> {
_Tp __v;
};
-template <class _Union>
-_LIBCPP_HIDE_FROM_ABI constexpr bool __expected_can_stuff_tail()
-{
+// This function returns whether the type `_Second` can be stuffed into the tail padding
+// of the `_First` type if both of them are given `[[no_unique_address]]`.
+template <class _First, class _Second>
+inline constexpr bool __fits_in_tail_padding = []() {
struct __x {
- private:
- _LIBCPP_NO_UNIQUE_ADDRESS _Union __union_;
- _LIBCPP_NO_UNIQUE_ADDRESS bool __has_val_;
+ _LIBCPP_NO_UNIQUE_ADDRESS _First __first;
+ _LIBCPP_NO_UNIQUE_ADDRESS _Second __second;
};
- return sizeof(__x) == sizeof(_Union);
-}
+ return sizeof(__x) == sizeof(_First);
+}();
template <class _Tp, class _Err>
class __expected_base {
@@ -191,7 +191,7 @@ class __expected_base {
_LIBCPP_NO_UNIQUE_ADDRESS _Err __unex_;
};
- static constexpr bool __can_stuff_tail = __expected_can_stuff_tail<__union_t>();
+ static constexpr bool __put_flag_in_tail = __fits_in_tail_padding<__union_t, bool>;
struct __repr {
_LIBCPP_HIDE_FROM_ABI constexpr explicit __repr() = delete;
@@ -216,7 +216,7 @@ class __expected_base {
template <class _OtherUnion>
_LIBCPP_HIDE_FROM_ABI constexpr explicit __repr(bool __has_val, _OtherUnion&& __other)
- requires(!__can_stuff_tail)
+ requires(!__put_flag_in_tail)
: __union_(__conditional_no_unique_address_invoke_tag{},
[&] { return __make_union(__has_val, std::forward<_OtherUnion>(__other)); }),
__has_val_(__has_val) {}
@@ -246,13 +246,13 @@ class __expected_base {
}
_LIBCPP_HIDE_FROM_ABI constexpr void __destroy_union()
- requires(!__can_stuff_tail && (is_trivially_destructible_v<_Tp> && is_trivially_destructible_v<_Err>))
+ requires(!__put_flag_in_tail && (is_trivially_destructible_v<_Tp> && is_trivially_destructible_v<_Err>))
{
std::destroy_at(&__union_.__v);
}
_LIBCPP_HIDE_FROM_ABI constexpr void __destroy_union()
- requires(!__can_stuff_tail && (!is_trivially_destructible_v<_Tp> || !is_trivially_destructible_v<_Err>))
+ requires(!__put_flag_in_tail && (!is_trivially_destructible_v<_Tp> || !is_trivially_destructible_v<_Err>))
{
__destroy_union_member();
std::destroy_at(&__union_.__v);
@@ -260,7 +260,7 @@ class __expected_base {
template <class... _Args>
_LIBCPP_HIDE_FROM_ABI constexpr void __construct_union(in_place_t, _Args&&... __args)
- requires(!__can_stuff_tail)
+ requires(!__put_flag_in_tail)
{
std::construct_at(&__union_.__v, in_place, std::forward<_Args>(__args)...);
__has_val_ = true;
@@ -268,7 +268,7 @@ class __expected_base {
template <class... _Args>
_LIBCPP_HIDE_FROM_ABI constexpr void __construct_union(unexpect_t, _Args&&... __args)
- requires(!__can_stuff_tail)
+ requires(!__put_flag_in_tail)
{
std::construct_at(&__union_.__v, unexpect, std::forward<_Args>(__args)...);
__has_val_ = false;
@@ -290,7 +290,7 @@ class __expected_base {
template <class _OtherUnion>
_LIBCPP_HIDE_FROM_ABI static constexpr __union_t __make_union(bool __has_val, _OtherUnion&& __other)
- requires(!__can_stuff_tail)
+ requires(!__put_flag_in_tail)
{
if (__has_val)
return __union_t(in_place, std::forward<_OtherUnion>(__other).__val_);
@@ -298,13 +298,13 @@ class __expected_base {
return __union_t(unexpect, std::forward<_OtherUnion>(__other).__unex_);
}
- _LIBCPP_NO_UNIQUE_ADDRESS __conditional_no_unique_address<__can_stuff_tail, __union_t> __union_;
+ _LIBCPP_NO_UNIQUE_ADDRESS __conditional_no_unique_address<__put_flag_in_tail, __union_t> __union_;
_LIBCPP_NO_UNIQUE_ADDRESS bool __has_val_;
};
template <class _OtherUnion>
_LIBCPP_HIDE_FROM_ABI static constexpr __repr __make_repr(bool __has_val, _OtherUnion&& __other)
- requires(__can_stuff_tail)
+ requires(__put_flag_in_tail)
{
if (__has_val)
return __repr(in_place, std::forward<_OtherUnion>(__other).__val_);
@@ -319,12 +319,12 @@ class __expected_base {
template <class _OtherUnion>
_LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_base(bool __has_val, _OtherUnion&& __other)
- requires(__can_stuff_tail)
+ requires(__put_flag_in_tail)
: __repr_(__conditional_no_unique_address_invoke_tag{},
[&] { return __make_repr(__has_val, std::forward<_OtherUnion>(__other)); }) {}
_LIBCPP_HIDE_FROM_ABI constexpr void __destroy() {
- if constexpr (__can_stuff_tail)
+ if constexpr (__put_flag_in_tail)
std::destroy_at(&__repr_.__v);
else
__repr_.__v.__destroy_union();
@@ -332,7 +332,7 @@ class __expected_base {
template <class _Tag, class... _Args>
_LIBCPP_HIDE_FROM_ABI constexpr void __construct(_Tag __tag, _Args&&... __args) {
- if constexpr (__can_stuff_tail)
+ if constexpr (__put_flag_in_tail)
std::construct_at(&__repr_.__v, __tag, std::forward<_Args>(__args)...);
else
__repr_.__v.__construct_union(__tag, std::forward<_Args>(__args)...);
@@ -347,7 +347,7 @@ class __expected_base {
_LIBCPP_HIDE_FROM_ABI constexpr const _Err& __unex() const { return __repr_.__v.__union_.__v.__unex_; }
private:
- _LIBCPP_NO_UNIQUE_ADDRESS __conditional_no_unique_address<!__can_stuff_tail, __repr> __repr_;
+ _LIBCPP_NO_UNIQUE_ADDRESS __conditional_no_unique_address<!__put_flag_in_tail, __repr> __repr_;
};
template <class _Tp, class _Err>
@@ -1128,7 +1128,7 @@ class __expected_void_base {
_LIBCPP_NO_UNIQUE_ADDRESS _Err __unex_;
};
- static constexpr bool __can_stuff_tail = __expected_can_stuff_tail<__union_t>();
+ static constexpr bool __put_flag_in_tail = __fits_in_tail_padding<__union_t, bool>;
struct __repr {
_LIBCPP_HIDE_FROM_ABI constexpr explicit __repr() = delete;
@@ -1148,7 +1148,7 @@ class __expected_void_base {
template <class _OtherUnion>
_LIBCPP_HIDE_FROM_ABI constexpr explicit __repr(bool __has_val, _OtherUnion&& __other)
- requires(!__can_stuff_tail)
+ requires(!__put_flag_in_tail)
: __union_(__conditional_no_unique_address_invoke_tag{},
[&] { return __make_union(__has_val, std::forward<_OtherUnion>(__other)); }),
__has_val_(__has_val) {}
@@ -1176,20 +1176,20 @@ class __expected_void_base {
}
_LIBCPP_HIDE_FROM_ABI constexpr void __destroy_union()
- requires(!__can_stuff_tail && is_trivially_destructible_v<_Err>)
+ requires(!__put_flag_in_tail && is_trivially_destructible_v<_Err>)
{
std::destroy_at(&__union_.__v);
}
_LIBCPP_HIDE_FROM_ABI constexpr void __destroy_union()
- requires(!__can_stuff_tail && !is_trivially_destructible_v<_Err>)
+ requires(!__put_flag_in_tail && !is_trivially_destructible_v<_Err>)
{
__destroy_union_member();
std::destroy_at(&__union_.__v);
}
_LIBCPP_HIDE_FROM_ABI constexpr void __construct_union(in_place_t)
- requires(!__can_stuff_tail)
+ requires(!__put_flag_in_tail)
{
std::construct_at(&__union_.__v, in_place);
__has_val_ = true;
@@ -1197,7 +1197,7 @@ class __expected_void_base {
template <class... _Args>
_LIBCPP_HIDE_FROM_ABI constexpr void __construct_union(unexpect_t, _Args&&... __args)
- requires(!__can_stuff_tail)
+ requires(!__put_flag_in_tail)
{
std::construct_at(&__union_.__v, unexpect, std::forward<_Args>(__args)...);
__has_val_ = false;
@@ -1216,7 +1216,7 @@ class __expected_void_base {
template <class _OtherUnion>
_LIBCPP_HIDE_FROM_ABI static constexpr __union_t __make_union(bool __has_val, _OtherUnion&& __other)
- requires(!__can_stuff_tail)
+ requires(!__put_flag_in_tail)
{
if (__has_val)
return __union_t(in_place);
@@ -1224,13 +1224,13 @@ class __expected_void_base {
return __union_t(unexpect, std::forward<_OtherUnion>(__other).__unex_);
}
- _LIBCPP_NO_UNIQUE_ADDRESS __conditional_no_unique_address<__can_stuff_tail, __union_t> __union_;
+ _LIBCPP_NO_UNIQUE_ADDRESS __conditional_no_unique_address<__put_flag_in_tail, __union_t> __union_;
_LIBCPP_NO_UNIQUE_ADDRESS bool __has_val_;
};
template <class _OtherUnion>
_LIBCPP_HIDE_FROM_ABI static constexpr __repr __make_repr(bool __has_val, _OtherUnion&& __other)
- requires(__can_stuff_tail)
+ requires(__put_flag_in_tail)
{
if (__has_val)
return __repr(in_place);
@@ -1245,12 +1245,12 @@ class __expected_void_base {
template <class _OtherUnion>
_LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_void_base(bool __has_val, _OtherUnion&& __other)
- requires(__can_stuff_tail)
+ requires(__put_flag_in_tail)
: __repr_(__conditional_no_unique_address_invoke_tag{},
[&] { return __make_repr(__has_val, std::forward<_OtherUnion>(__other)); }) {}
_LIBCPP_HIDE_FROM_ABI constexpr void __destroy() {
- if constexpr (__can_stuff_tail)
+ if constexpr (__put_flag_in_tail)
std::destroy_at(&__repr_.__v);
else
__repr_.__v.__destroy_union();
@@ -1258,7 +1258,7 @@ class __expected_void_base {
template <class _Tag, class... _Args>
_LIBCPP_HIDE_FROM_ABI constexpr void __construct(_Tag __tag, _Args&&... __args) {
- if constexpr (__can_stuff_tail)
+ if constexpr (__put_flag_in_tail)
std::construct_at(&__repr_.__v, __tag, std::forward<_Args>(__args)...);
else
__repr_.__v.__construct_union(__tag, std::forward<_Args>(__args)...);
@@ -1271,7 +1271,7 @@ class __expected_void_base {
_LIBCPP_HIDE_FROM_ABI constexpr const _Err& __unex() const { return __repr_.__v.__union_.__v.__unex_; }
private:
- _LIBCPP_NO_UNIQUE_ADDRESS __conditional_no_unique_address<!__can_stuff_tail, __repr> __repr_;
+ _LIBCPP_NO_UNIQUE_ADDRESS __conditional_no_unique_address<!__put_flag_in_tail, __repr> __repr_;
};
template <class _Tp, class _Err>
>From f23c6b990d84e8aa18c305c40cf5082e2f4d058a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jan=20Kokem=C3=BCller?= <jan.kokemueller at gmail.com>
Date: Thu, 2 Nov 2023 21:47:05 +0100
Subject: [PATCH 33/37] add comment detailing the distinction between
__make_repr and __make_union
---
libcxx/include/__expected/expected.h | 19 +++++++++++++++++++
1 file changed, 19 insertions(+)
diff --git a/libcxx/include/__expected/expected.h b/libcxx/include/__expected/expected.h
index 9d38795f71e6f..4c709ba369ba8 100644
--- a/libcxx/include/__expected/expected.h
+++ b/libcxx/include/__expected/expected.h
@@ -317,6 +317,25 @@ class __expected_base {
_LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_base(_Args&&... __args)
: __repr_(std::forward<_Args>(__args)...) {}
+ // In case we copy/move construct from another `expected` we need to create
+ // our `expected` so that it either has a value or not, depending on the "has
+ // value" flag of the other `expected`. To do this without falling back on
+ // `std::construct_at` we rely on guaranteed copy elision using two helper
+ // functions `__make_repr` and `__make_union`. There have to be two since
+ // there are two data layouts with different members being
+ // `[[no_unique_address]]`. GCC (as of version 13) does not do guaranteed
+ // copy elision when initializing `[[no_unique_address]]` members. The two
+ // cases are:
+ //
+ // - `__make_repr`: This is used when the "has value" flag lives in the tail
+ // of the union. In this case, the `__repr` member is _not_
+ // `[[no_unique_address]]`.
+ // - `__make_union`: When the "has value" flag does _not_ fit in the tail of
+ // the union, the `__repr` member is `[[no_unique_address]]` and the union
+ // is not.
+ //
+ // This constructor "catches" the first case and leaves the second case to
+ // `__union_t`, its constructors and `__make_union`.
template <class _OtherUnion>
_LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_base(bool __has_val, _OtherUnion&& __other)
requires(__put_flag_in_tail)
>From db73b7829f72a496d24937b05d2d38cb3fa074a9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jan=20Kokem=C3=BCller?= <jan.kokemueller at gmail.com>
Date: Sat, 25 Nov 2023 14:48:40 +0100
Subject: [PATCH 34/37] apply clang-format to changes
---
libcxx/include/__expected/expected.h | 185 ++++++++++++++-------------
1 file changed, 93 insertions(+), 92 deletions(-)
diff --git a/libcxx/include/__expected/expected.h b/libcxx/include/__expected/expected.h
index 4c709ba369ba8..75eb88af51e57 100644
--- a/libcxx/include/__expected/expected.h
+++ b/libcxx/include/__expected/expected.h
@@ -160,7 +160,7 @@ class __expected_base {
is_trivially_move_constructible_v<_Tp> && is_trivially_move_constructible_v<_Err>)
= default;
_LIBCPP_HIDE_FROM_ABI constexpr __union_t& operator=(const __union_t&) = delete;
- _LIBCPP_HIDE_FROM_ABI constexpr __union_t& operator=(__union_t&&) = delete;
+ _LIBCPP_HIDE_FROM_ABI constexpr __union_t& operator=(__union_t&&) = delete;
template <class... _Args>
_LIBCPP_HIDE_FROM_ABI constexpr explicit __union_t(in_place_t, _Args&&... __args)
@@ -205,20 +205,20 @@ class __expected_base {
: __union_(__tag, std::forward<_Args>(__args)...), __has_val_(false) {}
template <class... _Args>
- _LIBCPP_HIDE_FROM_ABI constexpr explicit __repr(
- std::__expected_construct_in_place_from_invoke_tag __tag, _Args&&... __args)
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit __repr(std::__expected_construct_in_place_from_invoke_tag __tag,
+ _Args&&... __args)
: __union_(__tag, std::forward<_Args>(__args)...), __has_val_(true) {}
template <class... _Args>
- _LIBCPP_HIDE_FROM_ABI constexpr explicit __repr(
- std::__expected_construct_unexpected_from_invoke_tag __tag, _Args&&... __args)
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit __repr(std::__expected_construct_unexpected_from_invoke_tag __tag,
+ _Args&&... __args)
: __union_(__tag, std::forward<_Args>(__args)...), __has_val_(false) {}
template <class _OtherUnion>
_LIBCPP_HIDE_FROM_ABI constexpr explicit __repr(bool __has_val, _OtherUnion&& __other)
requires(!__put_flag_in_tail)
: __union_(__conditional_no_unique_address_invoke_tag{},
- [&] { return __make_union(__has_val, std::forward<_OtherUnion>(__other)); }),
+ [&] { return __make_union(__has_val, std::forward<_OtherUnion>(__other)); }),
__has_val_(__has_val) {}
_LIBCPP_HIDE_FROM_ABI constexpr __repr(const __repr&) = delete;
@@ -233,7 +233,7 @@ class __expected_base {
= default;
_LIBCPP_HIDE_FROM_ABI constexpr __repr& operator=(const __repr&) = delete;
- _LIBCPP_HIDE_FROM_ABI constexpr __repr& operator=(__repr&&) = delete;
+ _LIBCPP_HIDE_FROM_ABI constexpr __repr& operator=(__repr&&) = delete;
_LIBCPP_HIDE_FROM_ABI constexpr ~__repr()
requires(is_trivially_destructible_v<_Tp> && is_trivially_destructible_v<_Err>)
@@ -340,7 +340,7 @@ class __expected_base {
_LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_base(bool __has_val, _OtherUnion&& __other)
requires(__put_flag_in_tail)
: __repr_(__conditional_no_unique_address_invoke_tag{},
- [&] { return __make_repr(__has_val, std::forward<_OtherUnion>(__other)); }) {}
+ [&] { return __make_repr(__has_val, std::forward<_OtherUnion>(__other)); }) {}
_LIBCPP_HIDE_FROM_ABI constexpr void __destroy() {
if constexpr (__put_flag_in_tail)
@@ -399,34 +399,33 @@ class expected : private __expected_base<_Tp, _Err> {
using rebind = expected<_Up, error_type>;
// [expected.object.ctor], constructors
- _LIBCPP_HIDE_FROM_ABI constexpr expected()
- noexcept(is_nothrow_default_constructible_v<_Tp>) // strengthened
+ _LIBCPP_HIDE_FROM_ABI constexpr expected() noexcept(is_nothrow_default_constructible_v<_Tp>) // strengthened
requires is_default_constructible_v<_Tp>
: __base(in_place) {}
_LIBCPP_HIDE_FROM_ABI constexpr expected(const expected&) = delete;
_LIBCPP_HIDE_FROM_ABI constexpr expected(const expected&)
- requires(is_copy_constructible_v<_Tp> && is_copy_constructible_v<_Err> &&
- is_trivially_copy_constructible_v<_Tp> && is_trivially_copy_constructible_v<_Err>)
+ requires(is_copy_constructible_v<_Tp> && is_copy_constructible_v<_Err> && is_trivially_copy_constructible_v<_Tp> &&
+ is_trivially_copy_constructible_v<_Err>)
= default;
- _LIBCPP_HIDE_FROM_ABI constexpr expected(const expected& __other)
- noexcept(is_nothrow_copy_constructible_v<_Tp> && is_nothrow_copy_constructible_v<_Err>) // strengthened
+ _LIBCPP_HIDE_FROM_ABI constexpr expected(const expected& __other) noexcept(
+ is_nothrow_copy_constructible_v<_Tp> && is_nothrow_copy_constructible_v<_Err>) // strengthened
requires(is_copy_constructible_v<_Tp> && is_copy_constructible_v<_Err> &&
!(is_trivially_copy_constructible_v<_Tp> && is_trivially_copy_constructible_v<_Err>))
- : __base(__other.__has_val(), __other.__union()) { }
+ : __base(__other.__has_val(), __other.__union()) {}
_LIBCPP_HIDE_FROM_ABI constexpr expected(expected&&)
requires(is_move_constructible_v<_Tp> && is_move_constructible_v<_Err>
&& is_trivially_move_constructible_v<_Tp> && is_trivially_move_constructible_v<_Err>)
= default;
- _LIBCPP_HIDE_FROM_ABI constexpr expected(expected&& __other)
- noexcept(is_nothrow_move_constructible_v<_Tp> && is_nothrow_move_constructible_v<_Err>)
+ _LIBCPP_HIDE_FROM_ABI constexpr expected(expected&& __other) noexcept(
+ is_nothrow_move_constructible_v<_Tp> && is_nothrow_move_constructible_v<_Err>)
requires(is_move_constructible_v<_Tp> && is_move_constructible_v<_Err> &&
!(is_trivially_move_constructible_v<_Tp> && is_trivially_move_constructible_v<_Err>))
- : __base(__other.__has_val(), std::move(__other.__union())) { }
+ : __base(__other.__has_val(), std::move(__other.__union())) {}
private:
template <class _Up, class _OtherErr, class _UfQual, class _OtherErrQual>
@@ -463,16 +462,16 @@ class expected : private __expected_base<_Tp, _Err> {
requires __can_convert<_Up, _OtherErr, const _Up&, const _OtherErr&>::value
_LIBCPP_HIDE_FROM_ABI constexpr explicit(!is_convertible_v<const _Up&, _Tp> ||
!is_convertible_v<const _OtherErr&, _Err>)
- expected(const expected<_Up, _OtherErr>& __other)
- noexcept(is_nothrow_constructible_v<_Tp, const _Up&> &&
- is_nothrow_constructible_v<_Err, const _OtherErr&>) // strengthened
+ expected(const expected<_Up, _OtherErr>& __other) noexcept(
+ is_nothrow_constructible_v<_Tp, const _Up&> &&
+ is_nothrow_constructible_v<_Err, const _OtherErr&>) // strengthened
: __base(__other.__has_val(), __other.__union()) {}
template <class _Up, class _OtherErr>
requires __can_convert<_Up, _OtherErr, _Up, _OtherErr>::value
_LIBCPP_HIDE_FROM_ABI constexpr explicit(!is_convertible_v<_Up, _Tp> || !is_convertible_v<_OtherErr, _Err>)
- expected(expected<_Up, _OtherErr>&& __other)
- noexcept(is_nothrow_constructible_v<_Tp, _Up> && is_nothrow_constructible_v<_Err, _OtherErr>) // strengthened
+ expected(expected<_Up, _OtherErr>&& __other) noexcept(
+ is_nothrow_constructible_v<_Tp, _Up> && is_nothrow_constructible_v<_Err, _OtherErr>) // strengthened
: __base(__other.__has_val(), std::move(__other.__union())) {}
template <class _Up = _Tp>
@@ -485,42 +484,38 @@ class expected : private __expected_base<_Tp, _Err> {
template <class _OtherErr>
requires is_constructible_v<_Err, const _OtherErr&>
- _LIBCPP_HIDE_FROM_ABI constexpr explicit(!is_convertible_v<const _OtherErr&, _Err>)
- expected(const unexpected<_OtherErr>& __unex)
- noexcept(is_nothrow_constructible_v<_Err, const _OtherErr&>) // strengthened
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit(!is_convertible_v<const _OtherErr&, _Err>) expected(
+ const unexpected<_OtherErr>& __unex) noexcept(is_nothrow_constructible_v<_Err, const _OtherErr&>) // strengthened
: __base(unexpect, __unex.error()) {}
template <class _OtherErr>
requires is_constructible_v<_Err, _OtherErr>
_LIBCPP_HIDE_FROM_ABI constexpr explicit(!is_convertible_v<_OtherErr, _Err>)
- expected(unexpected<_OtherErr>&& __unex)
- noexcept(is_nothrow_constructible_v<_Err, _OtherErr>) // strengthened
+ expected(unexpected<_OtherErr>&& __unex) noexcept(is_nothrow_constructible_v<_Err, _OtherErr>) // strengthened
: __base(unexpect, std::move(__unex.error())) {}
template <class... _Args>
requires is_constructible_v<_Tp, _Args...>
- _LIBCPP_HIDE_FROM_ABI constexpr explicit expected(in_place_t, _Args&&... __args)
- noexcept(is_nothrow_constructible_v<_Tp, _Args...>) // strengthened
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit expected(in_place_t, _Args&&... __args) noexcept(
+ is_nothrow_constructible_v<_Tp, _Args...>) // strengthened
: __base(in_place, std::forward<_Args>(__args)...) {}
template <class _Up, class... _Args>
requires is_constructible_v< _Tp, initializer_list<_Up>&, _Args... >
- _LIBCPP_HIDE_FROM_ABI constexpr explicit
- expected(in_place_t, initializer_list<_Up> __il, _Args&&... __args)
- noexcept(is_nothrow_constructible_v<_Tp, initializer_list<_Up>&, _Args...>) // strengthened
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit expected(in_place_t, initializer_list<_Up> __il, _Args&&... __args) noexcept(
+ is_nothrow_constructible_v<_Tp, initializer_list<_Up>&, _Args...>) // strengthened
: __base(in_place, __il, std::forward<_Args>(__args)...) {}
template <class... _Args>
requires is_constructible_v<_Err, _Args...>
- _LIBCPP_HIDE_FROM_ABI constexpr explicit expected(unexpect_t, _Args&&... __args)
- noexcept(is_nothrow_constructible_v<_Err, _Args...>) // strengthened
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit expected(unexpect_t, _Args&&... __args) noexcept(
+ is_nothrow_constructible_v<_Err, _Args...>) // strengthened
: __base(unexpect, std::forward<_Args>(__args)...) {}
template <class _Up, class... _Args>
requires is_constructible_v< _Err, initializer_list<_Up>&, _Args... >
- _LIBCPP_HIDE_FROM_ABI constexpr explicit
- expected(unexpect_t, initializer_list<_Up> __il, _Args&&... __args)
- noexcept(is_nothrow_constructible_v<_Err, initializer_list<_Up>&, _Args...>) // strengthened
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit expected(unexpect_t, initializer_list<_Up> __il, _Args&&... __args) noexcept(
+ is_nothrow_constructible_v<_Err, initializer_list<_Up>&, _Args...>) // strengthened
: __base(unexpect, __il, std::forward<_Args>(__args)...) {}
// [expected.object.dtor], destructor
@@ -687,9 +682,7 @@ class expected : private __expected_base<_Tp, _Err> {
if constexpr (is_nothrow_move_constructible_v<_Err>) {
_Err __tmp(std::move(__with_err.__unex()));
__with_err.__destroy();
- auto __trans = std::__make_exception_guard([&] {
- __with_err.__construct(unexpect, std::move(__tmp));
- });
+ auto __trans = std::__make_exception_guard([&] { __with_err.__construct(unexpect, std::move(__tmp)); });
__with_err.__construct(in_place, std::move(__with_val.__val()));
__trans.__complete();
__with_val.__destroy();
@@ -700,9 +693,7 @@ class expected : private __expected_base<_Tp, _Err> {
"that it can be reverted to the previous state in case an exception is thrown during swap.");
_Tp __tmp(std::move(__with_val.__val()));
__with_val.__destroy();
- auto __trans = std::__make_exception_guard([&] {
- __with_val.__construct(in_place, std::move(__tmp));
- });
+ auto __trans = std::__make_exception_guard([&] { __with_val.__construct(in_place, std::move(__tmp)); });
__with_val.__construct(unexpect, std::move(__with_err.__unex()));
__trans.__complete();
__with_err.__destroy();
@@ -736,32 +727,38 @@ class expected : private __expected_base<_Tp, _Err> {
// [expected.object.obs], observers
_LIBCPP_HIDE_FROM_ABI constexpr const _Tp* operator->() const noexcept {
- _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(this->__has_val(), "expected::operator-> requires the expected to contain a value");
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
+ this->__has_val(), "expected::operator-> requires the expected to contain a value");
return std::addressof(this->__val());
}
_LIBCPP_HIDE_FROM_ABI constexpr _Tp* operator->() noexcept {
- _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(this->__has_val(), "expected::operator-> requires the expected to contain a value");
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
+ this->__has_val(), "expected::operator-> requires the expected to contain a value");
return std::addressof(this->__val());
}
_LIBCPP_HIDE_FROM_ABI constexpr const _Tp& operator*() const& noexcept {
- _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(this->__has_val(), "expected::operator* requires the expected to contain a value");
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
+ this->__has_val(), "expected::operator* requires the expected to contain a value");
return this->__val();
}
_LIBCPP_HIDE_FROM_ABI constexpr _Tp& operator*() & noexcept {
- _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(this->__has_val(), "expected::operator* requires the expected to contain a value");
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
+ this->__has_val(), "expected::operator* requires the expected to contain a value");
return this->__val();
}
_LIBCPP_HIDE_FROM_ABI constexpr const _Tp&& operator*() const&& noexcept {
- _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(this->__has_val(), "expected::operator* requires the expected to contain a value");
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
+ this->__has_val(), "expected::operator* requires the expected to contain a value");
return std::move(this->__val());
}
_LIBCPP_HIDE_FROM_ABI constexpr _Tp&& operator*() && noexcept {
- _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(this->__has_val(), "expected::operator* requires the expected to contain a value");
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
+ this->__has_val(), "expected::operator* requires the expected to contain a value");
return std::move(this->__val());
}
@@ -804,22 +801,26 @@ class expected : private __expected_base<_Tp, _Err> {
}
_LIBCPP_HIDE_FROM_ABI constexpr const _Err& error() const& noexcept {
- _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!this->__has_val(), "expected::error requires the expected to contain an error");
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
+ !this->__has_val(), "expected::error requires the expected to contain an error");
return this->__unex();
}
_LIBCPP_HIDE_FROM_ABI constexpr _Err& error() & noexcept {
- _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!this->__has_val(), "expected::error requires the expected to contain an error");
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
+ !this->__has_val(), "expected::error requires the expected to contain an error");
return this->__unex();
}
_LIBCPP_HIDE_FROM_ABI constexpr const _Err&& error() const&& noexcept {
- _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!this->__has_val(), "expected::error requires the expected to contain an error");
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
+ !this->__has_val(), "expected::error requires the expected to contain an error");
return std::move(this->__unex());
}
_LIBCPP_HIDE_FROM_ABI constexpr _Err&& error() && noexcept {
- _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!this->__has_val(), "expected::error requires the expected to contain an error");
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
+ !this->__has_val(), "expected::error requires the expected to contain an error");
return std::move(this->__unex());
}
@@ -972,8 +973,8 @@ class expected : private __expected_base<_Tp, _Err> {
return expected<_Up, _Err>(unexpect, error());
}
if constexpr (!is_void_v<_Up>) {
- return expected<_Up, _Err>(__expected_construct_in_place_from_invoke_tag{},
- std::forward<_Func>(__f), this->__val());
+ return expected<_Up, _Err>(
+ __expected_construct_in_place_from_invoke_tag{}, std::forward<_Func>(__f), this->__val());
} else {
std::invoke(std::forward<_Func>(__f), this->__val());
return expected<_Up, _Err>();
@@ -988,8 +989,8 @@ class expected : private __expected_base<_Tp, _Err> {
return expected<_Up, _Err>(unexpect, error());
}
if constexpr (!is_void_v<_Up>) {
- return expected<_Up, _Err>(__expected_construct_in_place_from_invoke_tag{},
- std::forward<_Func>(__f), this->__val());
+ return expected<_Up, _Err>(
+ __expected_construct_in_place_from_invoke_tag{}, std::forward<_Func>(__f), this->__val());
} else {
std::invoke(std::forward<_Func>(__f), this->__val());
return expected<_Up, _Err>();
@@ -1004,8 +1005,8 @@ class expected : private __expected_base<_Tp, _Err> {
return expected<_Up, _Err>(unexpect, std::move(error()));
}
if constexpr (!is_void_v<_Up>) {
- return expected<_Up, _Err>(__expected_construct_in_place_from_invoke_tag{},
- std::forward<_Func>(__f), std::move(this->__val()));
+ return expected<_Up, _Err>(
+ __expected_construct_in_place_from_invoke_tag{}, std::forward<_Func>(__f), std::move(this->__val()));
} else {
std::invoke(std::forward<_Func>(__f), std::move(this->__val()));
return expected<_Up, _Err>();
@@ -1020,8 +1021,8 @@ class expected : private __expected_base<_Tp, _Err> {
return expected<_Up, _Err>(unexpect, std::move(error()));
}
if constexpr (!is_void_v<_Up>) {
- return expected<_Up, _Err>(__expected_construct_in_place_from_invoke_tag{},
- std::forward<_Func>(__f), std::move(this->__val()));
+ return expected<_Up, _Err>(
+ __expected_construct_in_place_from_invoke_tag{}, std::forward<_Func>(__f), std::move(this->__val()));
} else {
std::invoke(std::forward<_Func>(__f), std::move(this->__val()));
return expected<_Up, _Err>();
@@ -1121,7 +1122,7 @@ class __expected_void_base {
requires(is_move_constructible_v<_Err> && is_trivially_move_constructible_v<_Err>)
= default;
_LIBCPP_HIDE_FROM_ABI constexpr __union_t& operator=(const __union_t&) = delete;
- _LIBCPP_HIDE_FROM_ABI constexpr __union_t& operator=(__union_t&&) = delete;
+ _LIBCPP_HIDE_FROM_ABI constexpr __union_t& operator=(__union_t&&) = delete;
_LIBCPP_HIDE_FROM_ABI constexpr explicit __union_t(in_place_t) : __empty_() {}
@@ -1153,23 +1154,22 @@ class __expected_void_base {
_LIBCPP_HIDE_FROM_ABI constexpr explicit __repr() = delete;
template <class... _Args>
- _LIBCPP_HIDE_FROM_ABI constexpr explicit __repr(in_place_t __tag)
- : __union_(__tag), __has_val_(true) {}
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit __repr(in_place_t __tag) : __union_(__tag), __has_val_(true) {}
template <class... _Args>
_LIBCPP_HIDE_FROM_ABI constexpr explicit __repr(unexpect_t __tag, _Args&&... __args)
: __union_(__tag, std::forward<_Args>(__args)...), __has_val_(false) {}
template <class... _Args>
- _LIBCPP_HIDE_FROM_ABI constexpr explicit __repr(
- std::__expected_construct_unexpected_from_invoke_tag __tag, _Args&&... __args)
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit __repr(std::__expected_construct_unexpected_from_invoke_tag __tag,
+ _Args&&... __args)
: __union_(__tag, std::forward<_Args>(__args)...), __has_val_(false) {}
template <class _OtherUnion>
_LIBCPP_HIDE_FROM_ABI constexpr explicit __repr(bool __has_val, _OtherUnion&& __other)
requires(!__put_flag_in_tail)
: __union_(__conditional_no_unique_address_invoke_tag{},
- [&] { return __make_union(__has_val, std::forward<_OtherUnion>(__other)); }),
+ [&] { return __make_union(__has_val, std::forward<_OtherUnion>(__other)); }),
__has_val_(__has_val) {}
_LIBCPP_HIDE_FROM_ABI constexpr __repr(const __repr&) = delete;
@@ -1182,7 +1182,7 @@ class __expected_void_base {
= default;
_LIBCPP_HIDE_FROM_ABI constexpr __repr& operator=(const __repr&) = delete;
- _LIBCPP_HIDE_FROM_ABI constexpr __repr& operator=(__repr&&) = delete;
+ _LIBCPP_HIDE_FROM_ABI constexpr __repr& operator=(__repr&&) = delete;
_LIBCPP_HIDE_FROM_ABI constexpr ~__repr()
requires(is_trivially_destructible_v<_Err>)
@@ -1266,7 +1266,7 @@ class __expected_void_base {
_LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_void_base(bool __has_val, _OtherUnion&& __other)
requires(__put_flag_in_tail)
: __repr_(__conditional_no_unique_address_invoke_tag{},
- [&] { return __make_repr(__has_val, std::forward<_OtherUnion>(__other)); }) {}
+ [&] { return __make_repr(__has_val, std::forward<_OtherUnion>(__other)); }) {}
_LIBCPP_HIDE_FROM_ABI constexpr void __destroy() {
if constexpr (__put_flag_in_tail)
@@ -1331,8 +1331,8 @@ class expected<_Tp, _Err> : private __expected_void_base<_Err> {
requires(is_copy_constructible_v<_Err> && is_trivially_copy_constructible_v<_Err>)
= default;
- _LIBCPP_HIDE_FROM_ABI constexpr expected(const expected& __rhs)
- noexcept(is_nothrow_copy_constructible_v<_Err>) // strengthened
+ _LIBCPP_HIDE_FROM_ABI constexpr expected(const expected& __rhs) noexcept(
+ is_nothrow_copy_constructible_v<_Err>) // strengthened
requires(is_copy_constructible_v<_Err> && !is_trivially_copy_constructible_v<_Err>)
: __base(__rhs.__has_val(), __rhs.__union()) {}
@@ -1340,51 +1340,47 @@ class expected<_Tp, _Err> : private __expected_void_base<_Err> {
requires(is_move_constructible_v<_Err> && is_trivially_move_constructible_v<_Err>)
= default;
- _LIBCPP_HIDE_FROM_ABI constexpr expected(expected&& __rhs)
- noexcept(is_nothrow_move_constructible_v<_Err>)
+ _LIBCPP_HIDE_FROM_ABI constexpr expected(expected&& __rhs) noexcept(is_nothrow_move_constructible_v<_Err>)
requires(is_move_constructible_v<_Err> && !is_trivially_move_constructible_v<_Err>)
: __base(__rhs.__has_val(), std::move(__rhs.__union())) {}
template <class _Up, class _OtherErr>
requires __can_convert<_Up, _OtherErr, const _OtherErr&>::value
_LIBCPP_HIDE_FROM_ABI constexpr explicit(!is_convertible_v<const _OtherErr&, _Err>)
- expected(const expected<_Up, _OtherErr>& __rhs)
- noexcept(is_nothrow_constructible_v<_Err, const _OtherErr&>) // strengthened
+ expected(const expected<_Up, _OtherErr>& __rhs) noexcept(
+ is_nothrow_constructible_v<_Err, const _OtherErr&>) // strengthened
: __base(__rhs.__has_val(), __rhs.__union()) {}
template <class _Up, class _OtherErr>
requires __can_convert<_Up, _OtherErr, _OtherErr>::value
_LIBCPP_HIDE_FROM_ABI constexpr explicit(!is_convertible_v<_OtherErr, _Err>)
- expected(expected<_Up, _OtherErr>&& __rhs)
- noexcept(is_nothrow_constructible_v<_Err, _OtherErr>) // strengthened
+ expected(expected<_Up, _OtherErr>&& __rhs) noexcept(is_nothrow_constructible_v<_Err, _OtherErr>) // strengthened
: __base(__rhs.__has_val(), std::move(__rhs.__union())) {}
template <class _OtherErr>
requires is_constructible_v<_Err, const _OtherErr&>
- _LIBCPP_HIDE_FROM_ABI constexpr explicit(!is_convertible_v<const _OtherErr&, _Err>)
- expected(const unexpected<_OtherErr>& __unex)
- noexcept(is_nothrow_constructible_v<_Err, const _OtherErr&>) // strengthened
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit(!is_convertible_v<const _OtherErr&, _Err>) expected(
+ const unexpected<_OtherErr>& __unex) noexcept(is_nothrow_constructible_v<_Err, const _OtherErr&>) // strengthened
: __base(unexpect, __unex.error()) {}
template <class _OtherErr>
requires is_constructible_v<_Err, _OtherErr>
_LIBCPP_HIDE_FROM_ABI constexpr explicit(!is_convertible_v<_OtherErr, _Err>)
- expected(unexpected<_OtherErr>&& __unex)
- noexcept(is_nothrow_constructible_v<_Err, _OtherErr>) // strengthened
+ expected(unexpected<_OtherErr>&& __unex) noexcept(is_nothrow_constructible_v<_Err, _OtherErr>) // strengthened
: __base(unexpect, std::move(__unex.error())) {}
_LIBCPP_HIDE_FROM_ABI constexpr explicit expected(in_place_t) noexcept : __base(in_place) {}
template <class... _Args>
requires is_constructible_v<_Err, _Args...>
- _LIBCPP_HIDE_FROM_ABI constexpr explicit expected(unexpect_t, _Args&&... __args)
- noexcept(is_nothrow_constructible_v<_Err, _Args...>) // strengthened
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit expected(unexpect_t, _Args&&... __args) noexcept(
+ is_nothrow_constructible_v<_Err, _Args...>) // strengthened
: __base(unexpect, std::forward<_Args>(__args)...) {}
template <class _Up, class... _Args>
requires is_constructible_v< _Err, initializer_list<_Up>&, _Args... >
- _LIBCPP_HIDE_FROM_ABI constexpr explicit expected(unexpect_t, initializer_list<_Up> __il, _Args&&... __args)
- noexcept(is_nothrow_constructible_v<_Err, initializer_list<_Up>&, _Args...>) // strengthened
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit expected(unexpect_t, initializer_list<_Up> __il, _Args&&... __args) noexcept(
+ is_nothrow_constructible_v<_Err, initializer_list<_Up>&, _Args...>) // strengthened
: __base(unexpect, __il, std::forward<_Args>(__args)...) {}
private:
@@ -1525,7 +1521,8 @@ class expected<_Tp, _Err> : private __expected_void_base<_Err> {
_LIBCPP_HIDE_FROM_ABI constexpr bool has_value() const noexcept { return this->__has_val(); }
_LIBCPP_HIDE_FROM_ABI constexpr void operator*() const noexcept {
- _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(this->__has_val(), "expected::operator* requires the expected to contain a value");
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
+ this->__has_val(), "expected::operator* requires the expected to contain a value");
}
_LIBCPP_HIDE_FROM_ABI constexpr void value() const& {
@@ -1541,22 +1538,26 @@ class expected<_Tp, _Err> : private __expected_void_base<_Err> {
}
_LIBCPP_HIDE_FROM_ABI constexpr const _Err& error() const& noexcept {
- _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!this->__has_val(), "expected::error requires the expected to contain an error");
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
+ !this->__has_val(), "expected::error requires the expected to contain an error");
return this->__unex();
}
_LIBCPP_HIDE_FROM_ABI constexpr _Err& error() & noexcept {
- _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!this->__has_val(), "expected::error requires the expected to contain an error");
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
+ !this->__has_val(), "expected::error requires the expected to contain an error");
return this->__unex();
}
_LIBCPP_HIDE_FROM_ABI constexpr const _Err&& error() const&& noexcept {
- _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!this->__has_val(), "expected::error requires the expected to contain an error");
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
+ !this->__has_val(), "expected::error requires the expected to contain an error");
return std::move(this->__unex());
}
_LIBCPP_HIDE_FROM_ABI constexpr _Err&& error() && noexcept {
- _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!this->__has_val(), "expected::error requires the expected to contain an error");
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
+ !this->__has_val(), "expected::error requires the expected to contain an error");
return std::move(this->__unex());
}
>From d2bb1ffc1c661ce1aeef9b218be7445000fc5afa Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jan=20Kokem=C3=BCller?= <jan.kokemueller at gmail.com>
Date: Sat, 2 Dec 2023 16:51:39 +0100
Subject: [PATCH 35/37] add tests that check for invalid writes to potential
tail padding
---
.../assign/assign.U.pass.cpp | 14 ++
.../assign/assign.copy.pass.cpp | 23 +++
.../assign/assign.move.pass.cpp | 23 +++
.../expected.expected/assign/emplace.pass.cpp | 14 ++
.../swap/member.swap.pass.cpp | 22 +++
.../expected.void/assign/assign.copy.pass.cpp | 22 +++
.../expected.void/assign/assign.move.pass.cpp | 22 +++
.../assign/assign.unexpected.copy.pass.cpp | 16 ++
.../assign/assign.unexpected.move.pass.cpp | 17 +++
.../expected.void/swap/member.swap.pass.cpp | 22 +++
libcxx/test/std/utilities/expected/types.h | 138 +++++++++++++++++-
11 files changed, 332 insertions(+), 1 deletion(-)
diff --git a/libcxx/test/std/utilities/expected/expected.expected/assign/assign.U.pass.cpp b/libcxx/test/std/utilities/expected/expected.expected/assign/assign.U.pass.cpp
index f9d07a7632665..df9f29f02cada 100644
--- a/libcxx/test/std/utilities/expected/expected.expected/assign/assign.U.pass.cpp
+++ b/libcxx/test/std/utilities/expected/expected.expected/assign/assign.U.pass.cpp
@@ -310,6 +310,20 @@ constexpr bool test() {
assert(e.value().j == 8);
}
+ // CheckForInvalidWrites
+ {
+ {
+ CheckForInvalidWrites<true> e1(std::unexpect);
+ e1 = 42;
+ assert(e1.check());
+ }
+ {
+ CheckForInvalidWrites<false> e1(std::unexpect);
+ e1 = true;
+ assert(e1.check());
+ }
+ }
+
return true;
}
diff --git a/libcxx/test/std/utilities/expected/expected.expected/assign/assign.copy.pass.cpp b/libcxx/test/std/utilities/expected/expected.expected/assign/assign.copy.pass.cpp
index 03fe888b0a5e7..2f5291332355c 100644
--- a/libcxx/test/std/utilities/expected/expected.expected/assign/assign.copy.pass.cpp
+++ b/libcxx/test/std/utilities/expected/expected.expected/assign/assign.copy.pass.cpp
@@ -240,6 +240,29 @@ constexpr bool test() {
assert(e1.error().data_ == 10);
assert(oldState.copyAssignCalled);
}
+
+ // CheckForInvalidWrites
+ {
+ {
+ CheckForInvalidWrites<true> e1(std::unexpect);
+ CheckForInvalidWrites<true> e2;
+
+ e1 = e2;
+
+ assert(e1.check());
+ assert(e2.check());
+ }
+ {
+ CheckForInvalidWrites<false> e1(std::unexpect);
+ CheckForInvalidWrites<false> e2;
+
+ e1 = e2;
+
+ assert(e1.check());
+ assert(e2.check());
+ }
+ }
+
return true;
}
diff --git a/libcxx/test/std/utilities/expected/expected.expected/assign/assign.move.pass.cpp b/libcxx/test/std/utilities/expected/expected.expected/assign/assign.move.pass.cpp
index 8c419afd10729..065827ae652c9 100644
--- a/libcxx/test/std/utilities/expected/expected.expected/assign/assign.move.pass.cpp
+++ b/libcxx/test/std/utilities/expected/expected.expected/assign/assign.move.pass.cpp
@@ -258,6 +258,29 @@ constexpr bool test() {
assert(e1.error().data_ == 10);
assert(oldState.moveAssignCalled);
}
+
+ // CheckForInvalidWrites
+ {
+ {
+ CheckForInvalidWrites<true> e1(std::unexpect);
+ CheckForInvalidWrites<true> e2;
+
+ e1 = std::move(e2);
+
+ assert(e1.check());
+ assert(e2.check());
+ }
+ {
+ CheckForInvalidWrites<false> e1(std::unexpect);
+ CheckForInvalidWrites<false> e2;
+
+ e1 = std::move(e2);
+
+ assert(e1.check());
+ assert(e2.check());
+ }
+ }
+
return true;
}
diff --git a/libcxx/test/std/utilities/expected/expected.expected/assign/emplace.pass.cpp b/libcxx/test/std/utilities/expected/expected.expected/assign/emplace.pass.cpp
index 491de2dff0331..7e37f8bdf4abc 100644
--- a/libcxx/test/std/utilities/expected/expected.expected/assign/emplace.pass.cpp
+++ b/libcxx/test/std/utilities/expected/expected.expected/assign/emplace.pass.cpp
@@ -80,6 +80,20 @@ constexpr bool test() {
assert(e.has_value());
}
+ // CheckForInvalidWrites
+ {
+ {
+ CheckForInvalidWrites<true> e;
+ e.emplace();
+ assert(e.check());
+ }
+ {
+ CheckForInvalidWrites<false> e;
+ e.emplace();
+ assert(e.check());
+ }
+ }
+
return true;
}
diff --git a/libcxx/test/std/utilities/expected/expected.expected/swap/member.swap.pass.cpp b/libcxx/test/std/utilities/expected/expected.expected/swap/member.swap.pass.cpp
index b6b112cfbeb8b..b878b11162e9d 100644
--- a/libcxx/test/std/utilities/expected/expected.expected/swap/member.swap.pass.cpp
+++ b/libcxx/test/std/utilities/expected/expected.expected/swap/member.swap.pass.cpp
@@ -227,6 +227,28 @@ constexpr bool test() {
}
}
+ // CheckForInvalidWrites
+ {
+ {
+ CheckForInvalidWrites<true> x(std::unexpect);
+ CheckForInvalidWrites<true> y;
+
+ x.swap(y);
+
+ assert(x.check());
+ assert(y.check());
+ }
+ {
+ CheckForInvalidWrites<false> x(std::unexpect);
+ CheckForInvalidWrites<false> y;
+
+ x.swap(y);
+
+ assert(x.check());
+ assert(y.check());
+ }
+ }
+
return true;
}
diff --git a/libcxx/test/std/utilities/expected/expected.void/assign/assign.copy.pass.cpp b/libcxx/test/std/utilities/expected/expected.void/assign/assign.copy.pass.cpp
index b1968bcc24240..a51916f874eea 100644
--- a/libcxx/test/std/utilities/expected/expected.void/assign/assign.copy.pass.cpp
+++ b/libcxx/test/std/utilities/expected/expected.void/assign/assign.copy.pass.cpp
@@ -99,6 +99,28 @@ constexpr bool test() {
assert(state.copyAssignCalled);
}
+ // CheckForInvalidWrites
+ {
+ {
+ CheckForInvalidWrites<true, true> e1;
+ CheckForInvalidWrites<true, true> e2(std::unexpect);
+
+ e1 = e2;
+
+ assert(e1.check());
+ assert(e2.check());
+ }
+ {
+ CheckForInvalidWrites<false, true> e1;
+ CheckForInvalidWrites<false, true> e2(std::unexpect);
+
+ e1 = e2;
+
+ assert(e1.check());
+ assert(e2.check());
+ }
+ }
+
return true;
}
diff --git a/libcxx/test/std/utilities/expected/expected.void/assign/assign.move.pass.cpp b/libcxx/test/std/utilities/expected/expected.void/assign/assign.move.pass.cpp
index e6a29cd62583b..60ae0346f7af1 100644
--- a/libcxx/test/std/utilities/expected/expected.void/assign/assign.move.pass.cpp
+++ b/libcxx/test/std/utilities/expected/expected.void/assign/assign.move.pass.cpp
@@ -125,6 +125,28 @@ constexpr bool test() {
assert(state.moveAssignCalled);
}
+ // CheckForInvalidWrites
+ {
+ {
+ CheckForInvalidWrites<true, true> e1;
+ CheckForInvalidWrites<true, true> e2(std::unexpect);
+
+ e1 = std::move(e2);
+
+ assert(e1.check());
+ assert(e2.check());
+ }
+ {
+ CheckForInvalidWrites<false, true> e1;
+ CheckForInvalidWrites<false, true> e2(std::unexpect);
+
+ e1 = std::move(e2);
+
+ assert(e1.check());
+ assert(e2.check());
+ }
+ }
+
return true;
}
diff --git a/libcxx/test/std/utilities/expected/expected.void/assign/assign.unexpected.copy.pass.cpp b/libcxx/test/std/utilities/expected/expected.void/assign/assign.unexpected.copy.pass.cpp
index 1ae96530e528e..699597d243c19 100644
--- a/libcxx/test/std/utilities/expected/expected.void/assign/assign.unexpected.copy.pass.cpp
+++ b/libcxx/test/std/utilities/expected/expected.void/assign/assign.unexpected.copy.pass.cpp
@@ -91,6 +91,22 @@ constexpr bool test() {
assert(state1.copyAssignCalled);
}
+ // CheckForInvalidWrites
+ {
+ {
+ CheckForInvalidWrites<true, true> e;
+ std::unexpected<int> un(std::in_place, 42);
+ e = un;
+ assert(e.check());
+ }
+ {
+ CheckForInvalidWrites<false, true> e;
+ std::unexpected<bool> un(std::in_place, true);
+ e = un;
+ assert(e.check());
+ }
+ }
+
return true;
}
diff --git a/libcxx/test/std/utilities/expected/expected.void/assign/assign.unexpected.move.pass.cpp b/libcxx/test/std/utilities/expected/expected.void/assign/assign.unexpected.move.pass.cpp
index ea947715af28f..641eb4927a724 100644
--- a/libcxx/test/std/utilities/expected/expected.void/assign/assign.unexpected.move.pass.cpp
+++ b/libcxx/test/std/utilities/expected/expected.void/assign/assign.unexpected.move.pass.cpp
@@ -172,6 +172,23 @@ constexpr bool test() {
assert(e1.error().data_ == 10);
assert(oldState.moveAssignCalled);
}
+
+ // CheckForInvalidWrites
+ {
+ {
+ CheckForInvalidWrites<true, true> e;
+ std::unexpected<int> un(std::in_place, 42);
+ e = std::move(un);
+ assert(e.check());
+ }
+ {
+ CheckForInvalidWrites<false, true> e;
+ std::unexpected<bool> un(std::in_place, true);
+ e = std::move(un);
+ assert(e.check());
+ }
+ }
+
return true;
}
diff --git a/libcxx/test/std/utilities/expected/expected.void/swap/member.swap.pass.cpp b/libcxx/test/std/utilities/expected/expected.void/swap/member.swap.pass.cpp
index 70e004abef684..866f0ef7912a8 100644
--- a/libcxx/test/std/utilities/expected/expected.void/swap/member.swap.pass.cpp
+++ b/libcxx/test/std/utilities/expected/expected.void/swap/member.swap.pass.cpp
@@ -139,6 +139,28 @@ constexpr bool test() {
assert(y.has_value());
}
+ // CheckForInvalidWrites
+ {
+ {
+ CheckForInvalidWrites<true, true> x(std::unexpect);
+ CheckForInvalidWrites<true, true> y;
+
+ x.swap(y);
+
+ assert(x.check());
+ assert(y.check());
+ }
+ {
+ CheckForInvalidWrites<false, true> x(std::unexpect);
+ CheckForInvalidWrites<false, true> y;
+
+ x.swap(y);
+
+ assert(x.check());
+ assert(y.check());
+ }
+ }
+
return true;
}
diff --git a/libcxx/test/std/utilities/expected/types.h b/libcxx/test/std/utilities/expected/types.h
index ac4a82f2baf78..fcb950c4b94b3 100644
--- a/libcxx/test/std/utilities/expected/types.h
+++ b/libcxx/test/std/utilities/expected/types.h
@@ -175,7 +175,7 @@ struct TailClobberer {
friend constexpr bool operator==(const TailClobberer&, const TailClobberer&) = default;
- friend constexpr void swap(TailClobberer&, TailClobberer&){};
+ friend constexpr void swap(TailClobberer&, TailClobberer&) {};
private:
alignas(2) bool b;
@@ -199,4 +199,140 @@ static_assert(!std::is_trivially_move_constructible_v<TailClobbererNonTrivialMov
static_assert(std::is_nothrow_move_constructible_v<TailClobbererNonTrivialMove<0, true>>);
static_assert(!std::is_nothrow_move_constructible_v<TailClobbererNonTrivialMove<0, false>>);
+// The `CheckForInvalidWrites` class recreates situations where other objects
+// may be placed into a `std::expected`'s tail padding. With a template
+// parameter `WithPaddedExpected` two cases can be tested:
+//
+// 1. The `std::expected<T, E>` itself has padding, because `T`/`E` _don't_
+// have tail padding. This is modelled by `CheckForInvalidWrites<true>`
+// which has a (potential) data layout like this:
+//
+// +- `expected`'s "has value" flag
+// |
+// | +- `please_dont_overwrite_me`
+// | |
+// /---int---\ | /----------^-------\
+// 00 00 00 00 01 01 01 01 01 01 01 01
+// \--v---/
+// |
+// |
+// +- `expected`'s tail padding which
+// gets repurposed by `please_dont_overwrite_me`
+//
+// 2. There is tail padding in the union of `T` and `E` which means the
+// "has value" flag can be put into this tail padding. In this case, the
+// `std::expected` itself _must not_ have any tail padding as it may get
+// overwritten on mutating operations such as `emplace()`. This case is
+// modelled by `CheckForInvalidWrites<false>` with a (potential) data
+// layout like this:
+//
+// +- bool
+// | +- please_dont_overwrite_me
+// | +- "has value" flag |
+// | | /--------^---------\
+// 00 00 00 00 00 00 00 00 01 01 01 01 01 01 01 00
+// \---padding-----/ |
+// +- `CheckForInvalidWrites`
+// padding
+//
+// Note that other implementation strategies are viable, including one that
+// doesn't make use of `[[no_unique_address]]`. But if an implementation uses
+// the strategy above, it must make sure that those tail padding bytes are not
+// overwritten improperly on operations such as `emplace()`.
+
+struct BoolWithPadding {
+ constexpr explicit BoolWithPadding() noexcept : BoolWithPadding(false) {}
+ constexpr BoolWithPadding(bool val) noexcept {
+ if (!std::is_constant_evaluated()) {
+ std::memset(this, 0, sizeof(*this));
+ }
+ val_ = val;
+ }
+ constexpr BoolWithPadding(const BoolWithPadding& other) noexcept : BoolWithPadding(other.val_) {}
+ constexpr BoolWithPadding& operator=(const BoolWithPadding& other) noexcept {
+ val_ = other.val_;
+ return *this;
+ }
+ // The previous data layout of libc++'s `expected` required `T` to be
+ // trivially move constructible to employ the `[[no_unique_address]]`
+ // optimization. To trigger bugs with the old implementation, make
+ // `BoolWithPadding` trivially move constructible.
+ constexpr BoolWithPadding(BoolWithPadding&&) = default;
+
+private:
+ alignas(8) bool val_;
+};
+
+struct IntWithoutPadding {
+ constexpr explicit IntWithoutPadding() noexcept : IntWithoutPadding(0) {}
+ constexpr IntWithoutPadding(int val) noexcept {
+ if (!std::is_constant_evaluated()) {
+ std::memset(this, 0, sizeof(*this));
+ }
+ val_ = val;
+ }
+ constexpr IntWithoutPadding(const IntWithoutPadding& other) noexcept : IntWithoutPadding(other.val_) {}
+ constexpr IntWithoutPadding& operator=(const IntWithoutPadding& other) noexcept {
+ val_ = other.val_;
+ return *this;
+ }
+ // See comment on `BoolWithPadding`.
+ constexpr IntWithoutPadding(IntWithoutPadding&&) = default;
+
+private:
+ int val_;
+};
+
+template <bool WithPaddedExpected, bool ExpectedVoid>
+struct CheckForInvalidWritesBaseImpl;
+template <>
+struct CheckForInvalidWritesBaseImpl<true, false> {
+ using type = std::expected<IntWithoutPadding, bool>;
+};
+template <>
+struct CheckForInvalidWritesBaseImpl<false, false> {
+ using type = std::expected<BoolWithPadding, bool>;
+};
+template <>
+struct CheckForInvalidWritesBaseImpl<true, true> {
+ using type = std::expected<void, IntWithoutPadding>;
+};
+template <>
+struct CheckForInvalidWritesBaseImpl<false, true> {
+ using type = std::expected<void, BoolWithPadding>;
+};
+
+template <bool WithPaddedExpected, bool ExpectedVoid>
+using CheckForInvalidWritesBase = typename CheckForInvalidWritesBaseImpl<WithPaddedExpected, ExpectedVoid>::type;
+
+template <bool WithPaddedExpected, bool ExpectedVoid = false>
+struct CheckForInvalidWrites : public CheckForInvalidWritesBase<WithPaddedExpected, ExpectedVoid> {
+ constexpr CheckForInvalidWrites() = default;
+ constexpr CheckForInvalidWrites(std::unexpect_t)
+ : CheckForInvalidWritesBase<WithPaddedExpected, ExpectedVoid>(std::unexpect) {}
+
+ constexpr CheckForInvalidWrites& operator=(const CheckForInvalidWrites& other) {
+ CheckForInvalidWritesBase<WithPaddedExpected, ExpectedVoid>::operator=(other);
+ return *this;
+ }
+
+ constexpr CheckForInvalidWrites& operator=(CheckForInvalidWrites&& other) {
+ CheckForInvalidWritesBase<WithPaddedExpected, ExpectedVoid>::operator=(std::move(other));
+ return *this;
+ }
+
+ using CheckForInvalidWritesBase<WithPaddedExpected, ExpectedVoid>::operator=;
+
+ const bool please_dont_overwrite_me[7] = {true, true, true, true, true, true, true};
+
+ constexpr bool check() {
+ for (bool i : please_dont_overwrite_me) {
+ if (!i) {
+ return false;
+ }
+ }
+ return true;
+ }
+};
+
#endif // TEST_STD_UTILITIES_EXPECTED_TYPES_H
>From 5481513ad16220b05d5454c6f108dba82f3ebbde Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jan=20Kokem=C3=BCller?= <jan.kokemueller at gmail.com>
Date: Sat, 2 Dec 2023 17:12:33 +0100
Subject: [PATCH 36/37] format
---
libcxx/test/std/utilities/expected/types.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/libcxx/test/std/utilities/expected/types.h b/libcxx/test/std/utilities/expected/types.h
index fcb950c4b94b3..996ab0709c28e 100644
--- a/libcxx/test/std/utilities/expected/types.h
+++ b/libcxx/test/std/utilities/expected/types.h
@@ -175,7 +175,7 @@ struct TailClobberer {
friend constexpr bool operator==(const TailClobberer&, const TailClobberer&) = default;
- friend constexpr void swap(TailClobberer&, TailClobberer&) {};
+ friend constexpr void swap(TailClobberer&, TailClobberer&){};
private:
alignas(2) bool b;
>From ad1fb2060bc9ddb58ab62b6ae00bcc444162bde6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jan=20Kokem=C3=BCller?= <jan.kokemueller at gmail.com>
Date: Sat, 2 Dec 2023 17:46:36 +0100
Subject: [PATCH 37/37] fix GCC warning about multiline comments
---
libcxx/test/std/utilities/expected/types.h | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/libcxx/test/std/utilities/expected/types.h b/libcxx/test/std/utilities/expected/types.h
index 996ab0709c28e..3102553ce97f8 100644
--- a/libcxx/test/std/utilities/expected/types.h
+++ b/libcxx/test/std/utilities/expected/types.h
@@ -211,7 +211,7 @@ static_assert(!std::is_nothrow_move_constructible_v<TailClobbererNonTrivialMove<
// |
// | +- `please_dont_overwrite_me`
// | |
-// /---int---\ | /----------^-------\
+// /---int---\ | /----------^-------\ //
// 00 00 00 00 01 01 01 01 01 01 01 01
// \--v---/
// |
@@ -229,7 +229,7 @@ static_assert(!std::is_nothrow_move_constructible_v<TailClobbererNonTrivialMove<
// +- bool
// | +- please_dont_overwrite_me
// | +- "has value" flag |
-// | | /--------^---------\
+// | | /--------^---------\ //
// 00 00 00 00 00 00 00 00 01 01 01 01 01 01 01 00
// \---padding-----/ |
// +- `CheckForInvalidWrites`
More information about the libcxx-commits
mailing list