[lld] [lldb] [compiler-rt] [libc] [llvm] [libcxx] [libclc] [flang] [clang-tools-extra] [clang] [libc++] Ensure that `std::expected` has no tail padding (PR #69673)

Louis Dionne via llvm-commits llvm-commits at lists.llvm.org
Mon Jan 22 06:03:45 PST 2024


Jan =?utf-8?q?Kokemüller?= <jan.kokemueller at gmail.com>,
Jan =?utf-8?q?Kokemüller?= <jan.kokemueller at gmail.com>,
Jan =?utf-8?q?Kokemüller?= <jan.kokemueller at gmail.com>,
Jan =?utf-8?q?Kokemüller?= <jan.kokemueller at gmail.com>,
Jan =?utf-8?q?Kokemüller?= <jan.kokemueller at gmail.com>,
Jan =?utf-8?q?Kokemüller?= <jan.kokemueller at gmail.com>,
Jan =?utf-8?q?Kokemüller?= <jan.kokemueller at gmail.com>,
Jan =?utf-8?q?Kokemüller?= <jan.kokemueller at gmail.com>,
Jan =?utf-8?q?Kokemüller?= <jan.kokemueller at gmail.com>,
Jan =?utf-8?q?Kokemüller?= <jan.kokemueller at gmail.com>,
Jan =?utf-8?q?Kokemüller?= <jan.kokemueller at gmail.com>,
Jan =?utf-8?q?Kokemüller?= <jan.kokemueller at gmail.com>,
Jan =?utf-8?q?Kokemüller?= <jan.kokemueller at gmail.com>,
Jan =?utf-8?q?Kokemüller?= <jan.kokemueller at gmail.com>,
Jan =?utf-8?q?Kokemüller?= <jan.kokemueller at gmail.com>,
Jan =?utf-8?q?Kokemüller?= <jan.kokemueller at gmail.com>,
Jan =?utf-8?q?Kokemüller?= <jan.kokemueller at gmail.com>,
Jan =?utf-8?q?Kokemüller?= <jan.kokemueller at gmail.com>,
Jan =?utf-8?q?Kokemüller?= <jan.kokemueller at gmail.com>,
Jan =?utf-8?q?Kokemüller?= <jan.kokemueller at gmail.com>,
Jan =?utf-8?q?Kokemüller?= <jan.kokemueller at gmail.com>,
Jan =?utf-8?q?Kokemüller?= <jan.kokemueller at gmail.com>,
Jan =?utf-8?q?Kokemüller?= <jan.kokemueller at gmail.com>,
Jan =?utf-8?q?Kokemüller?= <jan.kokemueller at gmail.com>,
Jan =?utf-8?q?Kokemüller?= <jan.kokemueller at gmail.com>,
Jan =?utf-8?q?Kokemüller?= <jan.kokemueller at gmail.com>,
Jan =?utf-8?q?Kokemüller?= <jan.kokemueller at gmail.com>,
Jan =?utf-8?q?Kokemüller?= <jan.kokemueller at gmail.com>,
Jan =?utf-8?q?Kokemüller?= <jan.kokemueller at gmail.com>,
Jan =?utf-8?q?Kokemüller?= <jan.kokemueller at gmail.com>,
Jan =?utf-8?q?Kokemüller?= <jan.kokemueller at gmail.com>,
Jan =?utf-8?q?Kokemüller?= <jan.kokemueller at gmail.com>,
Jan =?utf-8?q?Kokemüller?= <jan.kokemueller at gmail.com>,
Jan =?utf-8?q?Kokemüller?= <jan.kokemueller at gmail.com>,
Jan =?utf-8?q?Kokemüller?= <jan.kokemueller at gmail.com>,
Jan =?utf-8?q?Kokemüller?= <jan.kokemueller at gmail.com>,
Jan =?utf-8?q?Kokemüller?= <jan.kokemueller at gmail.com>,
Jan =?utf-8?q?Kokemüller?= <jan.kokemueller at gmail.com>,
Jan =?utf-8?q?Kokemüller?= <jan.kokemueller at gmail.com>,
Jan =?utf-8?q?Kokemüller?= <jan.kokemueller at gmail.com>,
Jan =?utf-8?q?Kokemüller?= <jan.kokemueller at gmail.com>,
Jan =?utf-8?q?Kokemüller?= <jan.kokemueller at gmail.com>,
Jan =?utf-8?q?Kokemüller?= <jan.kokemueller at gmail.com>,
Jan =?utf-8?q?Kokemüller?= <jan.kokemueller at gmail.com>,
Jan =?utf-8?q?Kokemüller?= <jan.kokemueller at gmail.com>,
Jan =?utf-8?q?Kokemüller?= <jan.kokemueller at gmail.com>,
Jan =?utf-8?q?Kokemüller?= <jan.kokemueller at gmail.com>,
Jan =?utf-8?q?Kokemüller?= <jan.kokemueller at gmail.com>,
Jan =?utf-8?q?Kokemüller?= <jan.kokemueller at gmail.com>,
Jan =?utf-8?q?Kokemüller?= <jan.kokemueller at gmail.com>,
Jan =?utf-8?q?Kokemüller?= <jan.kokemueller at gmail.com>,
Jan =?utf-8?q?Kokemüller?= <jan.kokemueller at gmail.com>,
Jan =?utf-8?q?Kokemüller?= <jan.kokemueller at gmail.com>,Louis Dionne
 <ldionne.2 at gmail.com>
Message-ID:
In-Reply-To: <llvm.org/llvm/llvm-project/pull/69673 at github.com>


https://github.com/ldionne updated https://github.com/llvm/llvm-project/pull/69673

>From 03e2f9a58a5ceb373527001083f805c71e91880c 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/55] ensure that expected has no tail padding

---
 libcxx/include/__expected/expected.h | 47 +++++++++++++++++++---------
 1 file changed, 33 insertions(+), 14 deletions(-)

diff --git a/libcxx/include/__expected/expected.h b/libcxx/include/__expected/expected.h
index 9f36c41b78edfd..c5ff588014bbbb 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>
@@ -123,7 +124,7 @@ class expected {
   = default;
 
   _LIBCPP_HIDE_FROM_ABI constexpr expected(const expected& __other) noexcept(
-      is_nothrow_copy_constructible_v<_Tp> && is_nothrow_copy_constructible_v<_Err>) // strengthened
+      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_) {}
@@ -134,7 +135,7 @@ class expected {
   = default;
 
   _LIBCPP_HIDE_FROM_ABI constexpr expected(expected&& __other) noexcept(
-      is_nothrow_move_constructible_v<_Tp> && is_nothrow_move_constructible_v<_Err>)
+      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_) {}
@@ -175,15 +176,15 @@ class expected {
   _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
+          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_) {}
 
   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
+          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_) {}
 
   template <class _Up = _Tp>
@@ -275,8 +276,8 @@ class expected {
   _LIBCPP_HIDE_FROM_ABI constexpr expected& operator=(const expected&) = delete;
 
   _LIBCPP_HIDE_FROM_ABI constexpr expected& operator=(const expected& __rhs) noexcept(
-      is_nothrow_copy_assignable_v<_Tp> && is_nothrow_copy_constructible_v<_Tp> && is_nothrow_copy_assignable_v<_Err> &&
-      is_nothrow_copy_constructible_v<_Err>) // strengthened
+      is_nothrow_copy_assignable_v<_Tp>&& is_nothrow_copy_constructible_v<_Tp>&& is_nothrow_copy_assignable_v<_Err>&&
+          is_nothrow_copy_constructible_v<_Err>) // strengthened
     requires(is_copy_assignable_v<_Tp> && is_copy_constructible_v<_Tp> && is_copy_assignable_v<_Err> &&
              is_copy_constructible_v<_Err> &&
              (is_nothrow_move_constructible_v<_Tp> || is_nothrow_move_constructible_v<_Err>))
@@ -296,8 +297,8 @@ class expected {
   }
 
   _LIBCPP_HIDE_FROM_ABI constexpr expected&
-  operator=(expected&& __rhs) noexcept(is_nothrow_move_assignable_v<_Tp> && is_nothrow_move_constructible_v<_Tp> &&
-                                       is_nothrow_move_assignable_v<_Err> && is_nothrow_move_constructible_v<_Err>)
+  operator=(expected&& __rhs) noexcept(is_nothrow_move_assignable_v<_Tp>&& is_nothrow_move_constructible_v<_Tp>&&
+                                           is_nothrow_move_assignable_v<_Err>&& is_nothrow_move_constructible_v<_Err>)
     requires(is_move_constructible_v<_Tp> && is_move_assignable_v<_Tp> && is_move_constructible_v<_Err> &&
              is_move_assignable_v<_Err> &&
              (is_nothrow_move_constructible_v<_Tp> || is_nothrow_move_constructible_v<_Err>))
@@ -396,8 +397,8 @@ class expected {
 public:
   // [expected.object.swap], swap
   _LIBCPP_HIDE_FROM_ABI constexpr void
-  swap(expected& __rhs) noexcept(is_nothrow_move_constructible_v<_Tp> && is_nothrow_swappable_v<_Tp> &&
-                                 is_nothrow_move_constructible_v<_Err> && is_nothrow_swappable_v<_Err>)
+  swap(expected& __rhs) noexcept(is_nothrow_move_constructible_v<_Tp>&& is_nothrow_swappable_v<_Tp>&&
+                                     is_nothrow_move_constructible_v<_Err>&& is_nothrow_swappable_v<_Err>)
     requires(is_swappable_v<_Tp> && is_swappable_v<_Err> && is_move_constructible_v<_Tp> &&
              is_move_constructible_v<_Err> &&
              (is_nothrow_move_constructible_v<_Tp> || is_nothrow_move_constructible_v<_Err>))
@@ -912,8 +913,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>
@@ -1036,7 +1046,7 @@ class expected<_Tp, _Err> {
   _LIBCPP_HIDE_FROM_ABI constexpr expected& operator=(const expected&) = delete;
 
   _LIBCPP_HIDE_FROM_ABI constexpr expected& operator=(const expected& __rhs) noexcept(
-      is_nothrow_copy_assignable_v<_Err> && is_nothrow_copy_constructible_v<_Err>) // strengthened
+      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_) {
@@ -1058,7 +1068,7 @@ class expected<_Tp, _Err> {
   _LIBCPP_HIDE_FROM_ABI constexpr expected& operator=(expected&&) = delete;
 
   _LIBCPP_HIDE_FROM_ABI constexpr expected&
-  operator=(expected&& __rhs) noexcept(is_nothrow_move_assignable_v<_Err> && is_nothrow_move_constructible_v<_Err>)
+  operator=(expected&& __rhs) noexcept(is_nothrow_move_assignable_v<_Err>&& is_nothrow_move_constructible_v<_Err>)
     requires(is_move_assignable_v<_Err> && is_move_constructible_v<_Err>)
   {
     if (__has_val_) {
@@ -1110,7 +1120,7 @@ class expected<_Tp, _Err> {
 
   // [expected.void.swap], swap
   _LIBCPP_HIDE_FROM_ABI constexpr void
-  swap(expected& __rhs) noexcept(is_nothrow_move_constructible_v<_Err> && is_nothrow_swappable_v<_Err>)
+  swap(expected& __rhs) 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) {
@@ -1504,8 +1514,17 @@ 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 83400babff821e0620148c16589f2046e420b441 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/55] 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 3a8b1516010731..197403ea0429dd 100644
--- a/libcxx/include/__type_traits/datasizeof.h
+++ b/libcxx/include/__type_traits/datasizeof.h
@@ -55,6 +55,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
 #endif   // __has_extension(datasizeof)

>From 115203b847d1145b1824e240abb98b99843219f3 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/55] 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 | 52 +++++++++++++++++-----------
 1 file changed, 32 insertions(+), 20 deletions(-)

diff --git a/libcxx/include/__expected/expected.h b/libcxx/include/__expected/expected.h
index c5ff588014bbbb..b8c06646804a1e 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(!is_reference_v<_Tp> && !is_function_v<_Tp> && !is_same_v<remove_cv_t<_Tp>, in_place_t> &&
@@ -913,17 +941,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>
@@ -1514,17 +1534,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 1d25139a2816bf61e431766844ef2c3959d241c1 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/55] 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 c8c217054ae6c4..06f597d54871ee 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 dc59a6228386bc..29cf8dff0d2b28 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 d2e4c35ed196729a5315d5126e547b04aa14dd78 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/55] implement repr/compact_pair approach

---
 libcxx/include/__expected/expected.h          | 468 +++++++++---------
 .../no_unique_address.compile.pass.cpp        |   1 +
 .../no_unique_address.compile.pass.cpp        |   1 +
 3 files changed, 237 insertions(+), 233 deletions(-)

diff --git a/libcxx/include/__expected/expected.h b/libcxx/include/__expected/expected.h
index b8c06646804a1e..8f859ee5d37aff 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 {
@@ -142,7 +120,7 @@ class expected {
   // [expected.object.ctor], constructors
   _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;
 
@@ -155,7 +133,8 @@ class expected {
       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> && is_trivially_move_constructible_v<_Tp> &&
@@ -166,7 +145,8 @@ class expected {
       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>
@@ -191,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)
-      : __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>
@@ -206,14 +186,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>> &&
@@ -221,43 +203,43 @@ 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
 
@@ -268,10 +250,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_));
     }
   }
 
@@ -310,17 +292,17 @@ class expected {
              is_copy_constructible_v<_Err> &&
              (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;
   }
 
@@ -331,17 +313,17 @@ class expected {
              is_move_assignable_v<_Err> &&
              (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;
   }
 
@@ -352,11 +334,11 @@ class expected {
              (is_nothrow_constructible_v<_Tp, _Up> || 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;
   }
@@ -375,11 +357,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;
   }
@@ -387,11 +369,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;
   }
@@ -399,27 +381,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_;
   }
 
 public:
@@ -433,46 +415,48 @@ 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_);
       }
     }
   }
@@ -485,105 +469,115 @@ 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>
@@ -613,7 +607,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());
   }
@@ -626,7 +620,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());
   }
@@ -640,7 +634,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()));
   }
@@ -654,7 +648,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()));
   }
@@ -667,7 +661,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());
   }
@@ -680,7 +674,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());
   }
@@ -694,7 +688,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()));
   }
@@ -708,7 +702,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()));
   }
@@ -722,9 +716,9 @@ class expected {
     }
     if constexpr (!is_void_v<_Up>) {
       return expected<_Up, _Err>(
-          __expected_construct_in_place_from_invoke_tag{}, std::forward<_Func>(__f), __union_.__val_);
+          __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>();
     }
   }
@@ -738,9 +732,9 @@ class expected {
     }
     if constexpr (!is_void_v<_Up>) {
       return expected<_Up, _Err>(
-          __expected_construct_in_place_from_invoke_tag{}, std::forward<_Func>(__f), __union_.__val_);
+          __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>();
     }
   }
@@ -754,9 +748,11 @@ 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>();
     }
   }
@@ -770,9 +766,11 @@ 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>();
     }
   }
@@ -784,7 +782,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());
   }
@@ -796,7 +794,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());
   }
@@ -808,7 +806,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()));
@@ -821,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()));
@@ -831,25 +829,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:
@@ -941,9 +939,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>
@@ -974,7 +970,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;
 
@@ -985,7 +981,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>)
@@ -993,58 +989,60 @@ 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
@@ -1056,8 +1054,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_));
     }
   }
 
@@ -1069,17 +1067,17 @@ class expected<_Tp, _Err> {
       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;
@@ -1091,17 +1089,17 @@ class expected<_Tp, _Err> {
   operator=(expected&& __rhs) noexcept(is_nothrow_move_assignable_v<_Err>&& is_nothrow_move_constructible_v<_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;
@@ -1110,11 +1108,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;
   }
@@ -1122,19 +1120,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;
     }
   }
 
@@ -1144,22 +1142,23 @@ 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_);
       }
     }
   }
@@ -1171,46 +1170,51 @@ 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& {
     static_assert(is_copy_constructible_v<_Err>);
-    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() && {
     static_assert(is_copy_constructible_v<_Err> && is_move_constructible_v<_Err>);
-    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>
@@ -1446,16 +1450,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:
@@ -1534,9 +1538,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 06f597d54871ee..80209db9045b50 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 29cf8dff0d2b28..db2e4259eb8c79 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 c48d1a6f5bb4125049ae4ad17170694990131d6a 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/55] 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, 121 insertions(+), 93 deletions(-)

diff --git a/libcxx/include/__expected/expected.h b/libcxx/include/__expected/expected.h
index 8f859ee5d37aff..6f19d1ed92a555 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(!is_reference_v<_Tp> && !is_function_v<_Tp> && !is_same_v<remove_cv_t<_Tp>, in_place_t> &&
@@ -120,7 +114,7 @@ class expected {
   // [expected.object.ctor], constructors
   _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;
 
@@ -133,8 +127,7 @@ class expected {
       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> && is_trivially_move_constructible_v<_Tp> &&
@@ -145,8 +138,7 @@ class expected {
       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>
@@ -171,12 +163,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>
@@ -186,16 +178,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>> &&
@@ -203,80 +193,67 @@ 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));
-      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::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)...);
       __trans.__complete();
     }
   }
@@ -295,14 +272,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;
   }
 
@@ -316,14 +293,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;
   }
 
@@ -337,8 +314,7 @@ 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;
   }
@@ -358,8 +334,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(__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();
     }
@@ -370,8 +345,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(__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());
     }
@@ -381,26 +355,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_;
   }
 
@@ -413,35 +377,31 @@ class expected {
              is_move_constructible_v<_Err> &&
              (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_) {
@@ -939,7 +899,73 @@ 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 80209db9045b50..8eeec70ff0e424 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 db2e4259eb8c79..2129aa7b2405c7 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 8c26bb75c1b1b30ae98f65157b39362dd7add380 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/55] do the same for 'expected<void>'

---
 libcxx/include/__expected/expected.h | 151 +++++++++++++++++----------
 1 file changed, 95 insertions(+), 56 deletions(-)

diff --git a/libcxx/include/__expected/expected.h b/libcxx/include/__expected/expected.h
index 6f19d1ed92a555..a2417d4802a079 100644
--- a/libcxx/include/__expected/expected.h
+++ b/libcxx/include/__expected/expected.h
@@ -843,7 +843,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_;
@@ -890,7 +890,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>)
     {}
@@ -952,7 +952,7 @@ class expected {
     }
 
   private:
-    template <class _Up, class _OtherErr>
+    template <class, class>
     friend class expected;
 
     [[no_unique_address]] __union_t<_Tp, _Err> __union_;
@@ -962,12 +962,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> {
@@ -996,7 +990,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;
 
@@ -1007,7 +1001,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>)
@@ -1015,78 +1009,82 @@ 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) noexcept(
@@ -1095,13 +1093,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_;
       }
@@ -1117,13 +1113,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_);
       }
@@ -1135,8 +1129,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();
     }
@@ -1147,8 +1140,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());
     }
@@ -1157,8 +1149,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);
     }
   }
 
@@ -1167,12 +1158,11 @@ class expected<_Tp, _Err> {
   swap(expected& __rhs) 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_) {
@@ -1516,7 +1506,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_;
@@ -1555,7 +1545,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>)
     {}
@@ -1564,7 +1554,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 eb5172b7d968fb884decfe46a05965378c537785 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/55] 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 a2417d4802a079..ac61807676b64f 100644
--- a/libcxx/include/__expected/expected.h
+++ b/libcxx/include/__expected/expected.h
@@ -1051,12 +1051,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 589554aeaafea57af2b4eaf6e7b219b87dfb5856 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/55] 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 ac61807676b64f..ac20983c828d49 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 ccea6f00503bf9e1b8ca33bb5b22503cd903db94 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/55] 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 ac20983c828d49..9a6dae442856f2 100644
--- a/libcxx/include/__expected/expected.h
+++ b/libcxx/include/__expected/expected.h
@@ -813,7 +813,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 2eb62a10b32c41ab9cf6ba57100fd487d75cd2a2 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/55] std::in_place -> in_place

---
 libcxx/include/__expected/expected.h | 59 ++++++++++++++--------------
 1 file changed, 29 insertions(+), 30 deletions(-)

diff --git a/libcxx/include/__expected/expected.h b/libcxx/include/__expected/expected.h
index 9a6dae442856f2..5ae0f637f71263 100644
--- a/libcxx/include/__expected/expected.h
+++ b/libcxx/include/__expected/expected.h
@@ -113,7 +113,7 @@ class expected {
   // [expected.object.ctor], constructors
   _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;
 
@@ -192,7 +192,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&>
@@ -210,13 +210,13 @@ 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...>
@@ -271,10 +271,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_;
@@ -292,10 +292,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_);
@@ -313,7 +313,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>(__repr_.__union_.__unex_, std::forward<_Up>(__v));
+      __reinit_expected<in_place_t, std::unexpect_t, _Tp, _Err>(__repr_.__union_.__unex_, std::forward<_Up>(__v));
     }
     return *this;
   }
@@ -333,7 +333,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>(__repr_.__union_.__val_, __un.error());
+      __reinit_expected<std::unexpect_t, in_place_t, _Err, _Tp>(__repr_.__union_.__val_, __un.error());
     } else {
       __repr_.__union_.__unex_ = __un.error();
     }
@@ -344,7 +344,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>(__repr_.__union_.__val_, std::move(__un.error()));
+      __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());
     }
@@ -355,7 +355,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_;
   }
 
@@ -363,7 +363,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_;
   }
 
@@ -383,7 +383,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));
@@ -393,13 +393,12 @@ class expected {
                       "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_);
-        auto __trans = std::__make_exception_guard([&] {
-          std::construct_at(&__with_val.__repr_, std::in_place, std::move(__tmp));
-        });
+        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_));
         __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));
       }
     };
 
@@ -860,7 +859,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>
@@ -902,7 +901,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>
@@ -989,7 +988,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;
 
@@ -1035,7 +1034,7 @@ class expected<_Tp, _Err> {
       expected(unexpected<_OtherErr>&& __unex) 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...>
@@ -1065,15 +1064,15 @@ class expected<_Tp, _Err> {
   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); });
+    auto __trans = 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:
@@ -1090,7 +1089,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_;
       }
@@ -1110,7 +1109,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_);
       }
@@ -1142,7 +1141,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);
     }
   }
 
@@ -1155,7 +1154,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_) {
@@ -1550,7 +1549,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 21eff0f0c31452482d90cbe0357da89edb033a9d 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/55] std::unexpect -> unexpect

---
 libcxx/include/__expected/expected.h | 67 +++++++++++++---------------
 1 file changed, 32 insertions(+), 35 deletions(-)

diff --git a/libcxx/include/__expected/expected.h b/libcxx/include/__expected/expected.h
index 5ae0f637f71263..5f18ffeaad81f8 100644
--- a/libcxx/include/__expected/expected.h
+++ b/libcxx/include/__expected/expected.h
@@ -198,13 +198,13 @@ class expected {
     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_(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...>
@@ -222,13 +222,13 @@ 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
 
@@ -271,11 +271,9 @@ 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>(
-          __repr_.__union_.__val_, __rhs.__repr_.__union_.__unex_);
+      __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>(
-          __repr_.__union_.__unex_, __rhs.__repr_.__union_.__val_);
+      __reinit_expected<in_place_t, unexpect_t, _Tp, _Err>(__repr_.__union_.__unex_, __rhs.__repr_.__union_.__val_);
     } else {
       __repr_.__union_.__unex_ = __rhs.__repr_.__union_.__unex_;
     }
@@ -292,10 +290,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_);
@@ -313,7 +311,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>(__repr_.__union_.__unex_, std::forward<_Up>(__v));
+      __reinit_expected<in_place_t, unexpect_t, _Tp, _Err>(__repr_.__union_.__unex_, std::forward<_Up>(__v));
     }
     return *this;
   }
@@ -333,7 +331,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>(__repr_.__union_.__val_, __un.error());
+      __reinit_expected<unexpect_t, in_place_t, _Err, _Tp>(__repr_.__union_.__val_, __un.error());
     } else {
       __repr_.__union_.__unex_ = __un.error();
     }
@@ -344,7 +342,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>(__repr_.__union_.__val_, std::move(__un.error()));
+      __reinit_expected<unexpect_t, in_place_t, _Err, _Tp>(__repr_.__union_.__val_, std::move(__un.error()));
     } else {
       __repr_.__union_.__unex_ = std::move(__un.error());
     }
@@ -380,13 +378,12 @@ class expected {
       if constexpr (is_nothrow_move_constructible_v<_Err>) {
         _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));
-        });
+        auto __trans =
+            std::__make_exception_guard([&] { 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 "
@@ -395,7 +392,7 @@ class expected {
         std::destroy_at(&__with_val.__repr_);
         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));
@@ -816,7 +813,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>
@@ -863,7 +860,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>
@@ -905,7 +902,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>
@@ -1026,13 +1023,13 @@ class expected<_Tp, _Err> {
     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_(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) {}
 
@@ -1040,13 +1037,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>
@@ -1062,10 +1059,10 @@ 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();
   }
 
@@ -1085,7 +1082,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_) {
@@ -1105,7 +1102,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_) {
@@ -1121,7 +1118,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();
     }
@@ -1132,7 +1129,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());
     }
@@ -1152,7 +1149,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);
     };
@@ -1478,7 +1475,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>
@@ -1517,7 +1514,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>
@@ -1552,7 +1549,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 94100c0a0fef693bbdbd988fecfe23567a9a2254 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/55] 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 5f18ffeaad81f8..409fcd995506d5 100644
--- a/libcxx/include/__expected/expected.h
+++ b/libcxx/include/__expected/expected.h
@@ -950,8 +950,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 848960f04e807e5d09cd5a2bba171370ff69184b 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/55] 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 409fcd995506d5..19d7620405df45 100644
--- a/libcxx/include/__expected/expected.h
+++ b/libcxx/include/__expected/expected.h
@@ -1588,8 +1588,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 ff611a22494663fba2e27bb8d86b6ff3013e3487 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/55] 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 197403ea0429dd..3a8b1516010731 100644
--- a/libcxx/include/__type_traits/datasizeof.h
+++ b/libcxx/include/__type_traits/datasizeof.h
@@ -55,7 +55,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
 #endif   // __has_extension(datasizeof)

>From a5cc76c8de32eb678eaaa82a26e3c805af0bee65 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/55] rename __expected_repr to __repr

---
 libcxx/include/__expected/expected.h | 72 ++++++++++++++--------------
 1 file changed, 36 insertions(+), 36 deletions(-)

diff --git a/libcxx/include/__expected/expected.h b/libcxx/include/__expected/expected.h
index 19d7620405df45..7e7e5c93e240ad 100644
--- a/libcxx/include/__expected/expected.h
+++ b/libcxx/include/__expected/expected.h
@@ -838,7 +838,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_;
@@ -885,7 +885,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>)
     {}
@@ -894,49 +894,49 @@ 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(
-        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 __expected_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... _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_) {
@@ -954,7 +954,7 @@ class expected {
     _LIBCPP_NO_UNIQUE_ADDRESS bool __has_val_;
   };
 
-  __expected_repr __repr_;
+  __repr __repr_;
 };
 
 template <class _Tp, class _Err>
@@ -1495,7 +1495,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_;
@@ -1534,7 +1534,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>)
     {}
@@ -1543,40 +1543,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(
-        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... _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_) {
@@ -1592,7 +1592,7 @@ class expected<_Tp, _Err> {
     _LIBCPP_NO_UNIQUE_ADDRESS bool __has_val_;
   };
 
-  __expected_repr __repr_;
+  __repr __repr_;
 };
 
 _LIBCPP_END_NAMESPACE_STD

>From 66eb9f17b68e783f071ef4a02e6f2900c218146c 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/55] implement optimized layout for types without tail
 padding

---
 libcxx/include/__expected/expected.h          | 1093 ++++++++++-------
 .../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, 704 insertions(+), 433 deletions(-)

diff --git a/libcxx/include/__expected/expected.h b/libcxx/include/__expected/expected.h
index 7e7e5c93e240ad..299575119a6b96 100644
--- a/libcxx/include/__expected/expected.h
+++ b/libcxx/include/__expected/expected.h
@@ -88,8 +88,277 @@ _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> && !is_same_v<remove_cv_t<_Tp>, in_place_t> &&
                     !is_same_v<remove_cv_t<_Tp>, unexpect_t> && !__is_std_unexpected<remove_cv_t<_Tp>>::value &&
                     __valid_std_unexpected<_Err>::value,
@@ -102,6 +371,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;
@@ -113,7 +384,7 @@ class expected {
   // [expected.object.ctor], constructors
   _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;
 
@@ -126,7 +397,7 @@ class expected {
       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> && is_trivially_move_constructible_v<_Tp> &&
@@ -137,7 +408,7 @@ class expected {
       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>
@@ -162,12 +433,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>
@@ -177,14 +448,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>> &&
@@ -192,43 +463,43 @@ 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
 
@@ -238,21 +509,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();
     }
   }
@@ -268,14 +539,16 @@ class expected {
              is_copy_constructible_v<_Err> &&
              (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_) {
-      __reinit_expected<unexpect_t, in_place_t, _Err, _Tp>(__repr_.__union_.__val_, __rhs.__repr_.__union_.__unex_);
+    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>(
+          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_);
+      __reinit_expected<in_place_t, unexpect_t, _Tp, _Err>(
+          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;
   }
@@ -287,16 +560,16 @@ class expected {
              is_move_assignable_v<_Err> &&
              (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;
   }
@@ -308,10 +581,10 @@ class expected {
              (is_nothrow_constructible_v<_Tp, _Up> || 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));
+      __reinit_expected<in_place_t, unexpect_t, _Tp, _Err>(this->__repr_.__union_.__unex_, std::forward<_Up>(__v));
     }
     return *this;
   }
@@ -330,10 +603,10 @@ 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_) {
-      __reinit_expected<unexpect_t, in_place_t, _Err, _Tp>(__repr_.__union_.__val_, __un.error());
+    if (this->__repr_.__has_val_) {
+      __reinit_expected<unexpect_t, in_place_t, _Err, _Tp>(this->__repr_.__union_.__val_, __un.error());
     } else {
-      __repr_.__union_.__unex_ = __un.error();
+      this->__repr_.__union_.__unex_ = __un.error();
     }
     return *this;
   }
@@ -341,10 +614,10 @@ 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_) {
-      __reinit_expected<unexpect_t, in_place_t, _Err, _Tp>(__repr_.__union_.__val_, std::move(__un.error()));
+    if (this->__repr_.__has_val_) {
+      __reinit_expected<unexpect_t, in_place_t, _Err, _Tp>(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;
   }
@@ -352,16 +625,16 @@ 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_;
   }
 
@@ -377,32 +650,30 @@ 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_);
-        auto __trans =
-            std::__make_exception_guard([&] { 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_));
+        __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_));
         __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_);
-        auto __trans =
-            std::__make_exception_guard([&] { std::construct_at(&__with_val.__repr_, in_place, std::move(__tmp)); });
-        std::construct_at(&__with_val.__repr_, unexpect, std::move(__with_err.__repr_.__union_.__unex_));
+        __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_));
         __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);
       }
@@ -411,7 +682,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_);
       }
     }
   }
@@ -425,114 +696,116 @@ 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_);
+        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_);
+        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_;
+        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_;
+        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_);
+        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_);
+        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_;
+        !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_;
+        !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_);
+        !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_);
+        !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>
@@ -562,7 +835,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());
   }
@@ -575,7 +848,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());
   }
@@ -589,7 +862,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()));
   }
@@ -603,7 +876,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()));
   }
@@ -616,7 +889,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());
   }
@@ -629,7 +902,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());
   }
@@ -643,7 +916,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()));
   }
@@ -657,7 +930,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()));
   }
@@ -671,9 +944,9 @@ class expected {
     }
     if constexpr (!is_void_v<_Up>) {
       return expected<_Up, _Err>(
-          __expected_construct_in_place_from_invoke_tag{}, std::forward<_Func>(__f), __repr_.__union_.__val_);
+          __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>();
     }
   }
@@ -687,9 +960,9 @@ class expected {
     }
     if constexpr (!is_void_v<_Up>) {
       return expected<_Up, _Err>(
-          __expected_construct_in_place_from_invoke_tag{}, std::forward<_Func>(__f), __repr_.__union_.__val_);
+          __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>();
     }
   }
@@ -705,9 +978,9 @@ class expected {
       return expected<_Up, _Err>(
           __expected_construct_in_place_from_invoke_tag{},
           std::forward<_Func>(__f),
-          std::move(__repr_.__union_.__val_));
+          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>();
     }
   }
@@ -723,9 +996,9 @@ class expected {
       return expected<_Up, _Err>(
           __expected_construct_in_place_from_invoke_tag{},
           std::forward<_Func>(__f),
-          std::move(__repr_.__union_.__val_));
+          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>();
     }
   }
@@ -737,7 +1010,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());
   }
@@ -749,7 +1022,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());
   }
@@ -761,7 +1034,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()));
@@ -774,7 +1047,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()));
@@ -804,162 +1077,249 @@ 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;
+private:
+  template <class, class>
+  friend class expected;
 
-    _LIBCPP_NO_UNIQUE_ADDRESS __union_t<_Tp, _Err> __union_;
-    _LIBCPP_NO_UNIQUE_ADDRESS bool __has_val_;
-  };
+  _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(); }
 
-  __repr __repr_;
+  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)...) {}
+
+  _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_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");
@@ -976,6 +1336,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;
@@ -985,7 +1347,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;
 
@@ -996,7 +1358,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>)
@@ -1004,52 +1366,52 @@ 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
@@ -1060,16 +1422,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:
@@ -1080,7 +1442,7 @@ class expected<_Tp, _Err> {
       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_);
       }
@@ -1088,7 +1450,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;
@@ -1100,7 +1462,7 @@ class expected<_Tp, _Err> {
   operator=(expected&& __rhs) noexcept(is_nothrow_move_assignable_v<_Err>&& is_nothrow_move_constructible_v<_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_));
       }
@@ -1108,7 +1470,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;
@@ -1117,10 +1479,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;
   }
@@ -1128,16 +1490,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);
     }
   }
@@ -1154,7 +1516,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);
       }
@@ -1163,7 +1525,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_);
       }
     }
   }
@@ -1175,51 +1537,51 @@ 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");
+        this->__repr_.__has_val_, "expected::operator* requires the expected to contain a value");
   }
 
   _LIBCPP_HIDE_FROM_ABI constexpr void value() const& {
     static_assert(is_copy_constructible_v<_Err>);
-    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() && {
     static_assert(is_copy_constructible_v<_Err> && is_move_constructible_v<_Err>);
-    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_;
+        !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_;
+        !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_);
+        !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_);
+        !this->__repr_.__has_val_, "expected::error requires the expected to contain an error");
+    return std::move(this->__repr_.__union_.__unex_);
   }
 
   template <class _Up = _Err>
@@ -1466,133 +1828,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 8eeec70ff0e424..a7ddd13e7930aa 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 82024a068f00d1..14c27c6286eb05 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
@@ -52,6 +52,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@*:* 0-1 {{{{(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@*:* 0-1 {{{{(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 2129aa7b2405c7..fe4ef4f1e0e238 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 0f2fb581ccd705..bc179b627a9a27 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
@@ -52,6 +52,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@*:* 0-1 {{{{(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@*:* 0-1 {{{{(excess elements in struct initializer|no matching constructor for initialization of)}}{{.*}}}}

>From 025c59cace3911cce10a70156bce93de59ed04a0 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/55] 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 | 88 +++++++++++++++++-----------
 1 file changed, 54 insertions(+), 34 deletions(-)

diff --git a/libcxx/include/__expected/expected.h b/libcxx/include/__expected/expected.h
index 299575119a6b96..d58fa49aa81c22 100644
--- a/libcxx/include/__expected/expected.h
+++ b/libcxx/include/__expected/expected.h
@@ -88,14 +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>
@@ -191,8 +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&)
@@ -256,6 +247,15 @@ 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_;
 };
@@ -282,11 +282,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> && is_trivially_copy_constructible_v<_Tp> &&
@@ -347,6 +342,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_); }
 
   template <class _Tag, class... _Args>
@@ -354,7 +353,19 @@ 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>
@@ -1081,14 +1092,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_() {}
@@ -1165,9 +1168,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&)
@@ -1226,6 +1227,15 @@ 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_;
 };
@@ -1245,12 +1255,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>)
@@ -1307,6 +1311,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_); }
 
   template <class _Tag, class... _Args>
@@ -1314,7 +1322,19 @@ 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 21887f76812ecb316b82b3a30e89fc9ed6bec455 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/55] 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 a7ddd13e7930aa..e316f7a0fc1b1e 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 fe4ef4f1e0e238..e764dbd66acaa9 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 901c065cf496d0253b8675ba77c98607f807986b 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/55] use std::conditional for conditional
 [[no_unique_address]]

---
 libcxx/include/__expected/expected.h          | 641 +++++++++---------
 .../no_unique_address.compile.pass.cpp        |   6 +-
 .../transform_error.mandates.verify.cpp       |   1 -
 3 files changed, 307 insertions(+), 341 deletions(-)

diff --git a/libcxx/include/__expected/expected.h b/libcxx/include/__expected/expected.h
index d58fa49aa81c22..55644648c35a2a 100644
--- a/libcxx/include/__expected/expected.h
+++ b/libcxx/include/__expected/expected.h
@@ -88,255 +88,204 @@ _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... _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 _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(in_place_t, _Args&&... __args)
-      : __val_(std::forward<_Args>(__args)...) {}
+struct __expected_wrap_invoke_tag {};
 
+template <class _Tp>
+struct __expected_wrap_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_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)...)) {}
+  _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 __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_;
+  _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 _Tp>
+struct __expected_wrap_no_unique {
   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_));
-    }
-  }
+  _LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_wrap_no_unique(_Args&&... __args)
+      : __v(std::forward<_Args>(__args)...) {}
 
-  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_);
-  }
+  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)...)) {}
 
-  __expected_union_t<_Tp, _Err> __union_;
-  _LIBCPP_NO_UNIQUE_ADDRESS bool __has_val_;
+  _LIBCPP_NO_UNIQUE_ADDRESS _Tp __v;
 };
 
-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>)
-  {
-    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 <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_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(); }
+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() {
+    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_));
+      }
+    }
 
-  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)
@@ -344,28 +293,38 @@ 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_); }
+  _LIBCPP_HIDE_FROM_ABI constexpr void __destroy() {
+    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)...);
+    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) {
+  _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>
@@ -408,7 +367,7 @@ class expected : private __expected_base<_Tp, _Err> {
       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> && is_trivially_move_constructible_v<_Tp> &&
@@ -419,7 +378,7 @@ class expected : private __expected_base<_Tp, _Err> {
       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>
@@ -459,14 +418,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>> &&
@@ -550,16 +509,16 @@ class expected : private __expected_base<_Tp, _Err> {
              is_copy_constructible_v<_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;
   }
@@ -571,16 +530,16 @@ class expected : private __expected_base<_Tp, _Err> {
              is_move_assignable_v<_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;
   }
@@ -592,10 +551,11 @@ class expected : private __expected_base<_Tp, _Err> {
              (is_nothrow_constructible_v<_Tp, _Up> || 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));
+      __reinit_expected<in_place_t, unexpect_t, _Tp, _Err>(
+          this->__repr_.__v.__union_.__v.__unex_.__v, std::forward<_Up>(__v));
     }
     return *this;
   }
@@ -614,10 +574,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_.__has_val_) {
-      __reinit_expected<unexpect_t, in_place_t, _Err, _Tp>(this->__repr_.__union_.__val_, __un.error());
+    if (this->__repr_.__v.__has_val_) {
+      __reinit_expected<unexpect_t, in_place_t, _Err, _Tp>(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;
   }
@@ -625,10 +585,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_) {
-      __reinit_expected<unexpect_t, in_place_t, _Err, _Tp>(this->__repr_.__union_.__val_, std::move(__un.error()));
+    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()));
     } else {
-      this->__repr_.__union_.__unex_ = std::move(__un.error());
+      this->__repr_.__v.__union_.__v.__unex_.__v = std::move(__un.error());
     }
     return *this;
   }
@@ -638,7 +599,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>
@@ -646,7 +607,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:
@@ -660,10 +621,10 @@ 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));
@@ -671,29 +632,29 @@ 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);
       }
     }
   }
@@ -707,115 +668,117 @@ 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_);
+        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_);
+        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_;
+        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_;
+        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_);
+        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_);
+        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_;
+        !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_;
+        !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_);
+        !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_);
+        !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_)
+    return this->__repr_.__v.__has_val_
+             ? std::move(this->__repr_.__v.__union_.__v.__val_.__v)
              : static_cast<_Tp>(std::forward<_Up>(__v));
   }
 
@@ -846,7 +809,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());
   }
@@ -859,7 +822,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());
   }
@@ -873,7 +836,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()));
   }
@@ -887,7 +850,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()));
   }
@@ -900,7 +863,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());
   }
@@ -913,7 +876,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());
   }
@@ -927,7 +890,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()));
   }
@@ -941,7 +904,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()));
   }
@@ -955,9 +918,11 @@ 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_.__union_.__val_);
+          __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>();
     }
   }
@@ -971,9 +936,11 @@ 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_.__union_.__val_);
+          __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>();
     }
   }
@@ -989,9 +956,9 @@ class expected : private __expected_base<_Tp, _Err> {
       return expected<_Up, _Err>(
           __expected_construct_in_place_from_invoke_tag{},
           std::forward<_Func>(__f),
-          std::move(this->__repr_.__union_.__val_));
+          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>();
     }
   }
@@ -1007,9 +974,9 @@ class expected : private __expected_base<_Tp, _Err> {
       return expected<_Up, _Err>(
           __expected_construct_in_place_from_invoke_tag{},
           std::forward<_Func>(__f),
-          std::move(this->__repr_.__union_.__val_));
+          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>();
     }
   }
@@ -1021,7 +988,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());
   }
@@ -1033,7 +1000,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());
   }
@@ -1045,7 +1012,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()));
@@ -1058,7 +1025,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()));
@@ -1068,25 +1035,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());
   }
 };
 
@@ -1109,7 +1076,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]]?
@@ -1142,7 +1109,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 e316f7a0fc1b1e..4d523d1ad69500 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 14c27c6286eb05..82024a068f00d1 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
@@ -52,7 +52,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@*:* 0-1 {{{{(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@*:* 0-1 {{{{(excess elements in struct initializer|no matching constructor for initialization of)}}{{.*}}}}

>From 285c342060a7254f28aa0034367598395ecab43c 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/55] slight refactoring

---
 libcxx/include/__expected/expected.h | 81 +++++++++++++---------------
 1 file changed, 36 insertions(+), 45 deletions(-)

diff --git a/libcxx/include/__expected/expected.h b/libcxx/include/__expected/expected.h
index 55644648c35a2a..d5d783290f80f8 100644
--- a/libcxx/include/__expected/expected.h
+++ b/libcxx/include/__expected/expected.h
@@ -91,44 +91,38 @@ _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
@@ -149,12 +143,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>)
@@ -202,7 +196,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) {}
 
@@ -286,6 +280,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)
@@ -294,8 +298,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{},
-                [&] { return __make_repr(__has_val, std::forward<_OtherUnion>(__other)); }) {}
+      : __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())
@@ -312,18 +315,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 8c2eb556a5c852d21c4fd85e8e3f39c6fca0d28a 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/55] more refactoring

---
 libcxx/include/__expected/expected.h | 43 +++++++++++++++-------------
 1 file changed, 23 insertions(+), 20 deletions(-)

diff --git a/libcxx/include/__expected/expected.h b/libcxx/include/__expected/expected.h
index d5d783290f80f8..cac3b6aa94887d 100644
--- a/libcxx/include/__expected/expected.h
+++ b/libcxx/include/__expected/expected.h
@@ -121,6 +121,16 @@ 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,
@@ -163,14 +173,7 @@ class __expected_base {
                                                                         _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;
@@ -195,7 +198,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) {}
@@ -224,13 +227,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);
@@ -238,7 +241,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;
@@ -246,7 +249,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;
@@ -268,7 +271,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);
@@ -276,13 +279,13 @@ class __expected_base {
         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 __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 __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);
@@ -297,11 +300,11 @@ 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();
@@ -309,13 +312,13 @@ 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_;
+  _LIBCPP_NO_UNIQUE_ADDRESS __expected_conditional_no_unique_address< !__can_stuff_tail, __repr>::__type __repr_;
 };
 
 template <class _Tp, class _Err>

>From 0fb34bfbe0242abbd11c47579535673aa11b5952 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/55] refactor expected<void>

---
 libcxx/include/__expected/expected.h          | 642 ++++++++----------
 .../no_unique_address.compile.pass.cpp        |   2 +-
 .../transform_error.mandates.verify.cpp       |   2 +-
 3 files changed, 285 insertions(+), 361 deletions(-)

diff --git a/libcxx/include/__expected/expected.h b/libcxx/include/__expected/expected.h
index cac3b6aa94887d..f691a4f5a7390c 100644
--- a/libcxx/include/__expected/expected.h
+++ b/libcxx/include/__expected/expected.h
@@ -257,7 +257,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>)
@@ -318,6 +318,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_;
 };
 
@@ -361,7 +370,7 @@ class expected : private __expected_base<_Tp, _Err> {
       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> && is_trivially_move_constructible_v<_Tp> &&
@@ -372,7 +381,7 @@ class expected : private __expected_base<_Tp, _Err> {
       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>
@@ -412,14 +421,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>> &&
@@ -503,16 +512,14 @@ class expected : private __expected_base<_Tp, _Err> {
              is_copy_constructible_v<_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;
   }
@@ -524,16 +531,14 @@ class expected : private __expected_base<_Tp, _Err> {
              is_move_assignable_v<_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;
   }
@@ -545,11 +550,10 @@ class expected : private __expected_base<_Tp, _Err> {
              (is_nothrow_constructible_v<_Tp, _Up> || 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;
   }
@@ -568,10 +572,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;
   }
@@ -579,11 +583,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;
   }
@@ -593,15 +596,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:
@@ -615,10 +618,10 @@ 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));
@@ -626,29 +629,29 @@ 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());
       }
     }
   }
@@ -662,118 +665,114 @@ 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);
+        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);
+        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;
+        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;
+        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);
+        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);
+        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;
+        !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;
+        !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);
+        !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);
+        !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>
@@ -803,7 +802,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());
   }
@@ -816,7 +815,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());
   }
@@ -830,7 +829,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()));
   }
@@ -844,7 +843,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()));
   }
@@ -857,7 +856,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());
   }
@@ -870,7 +869,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());
   }
@@ -884,7 +883,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()));
   }
@@ -898,7 +897,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()));
   }
@@ -912,11 +911,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);
+          __expected_construct_in_place_from_invoke_tag{}, 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>();
     }
   }
@@ -930,11 +927,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);
+          __expected_construct_in_place_from_invoke_tag{}, 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>();
     }
   }
@@ -948,11 +943,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));
+          __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->__repr_.__v.__union_.__v.__val_.__v));
+      std::invoke(std::forward<_Func>(__f), std::move(this->__val()));
       return expected<_Up, _Err>();
     }
   }
@@ -966,11 +959,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));
+          __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->__repr_.__v.__union_.__v.__val_.__v));
+      std::invoke(std::forward<_Func>(__f), std::move(this->__val()));
       return expected<_Up, _Err>();
     }
   }
@@ -982,7 +973,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());
   }
@@ -994,7 +985,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());
   }
@@ -1006,7 +997,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()));
@@ -1019,7 +1010,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()));
@@ -1029,244 +1020,173 @@ 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)
@@ -1274,28 +1194,32 @@ 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_); }
+  _LIBCPP_HIDE_FROM_ABI constexpr void __destroy() {
+    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);
+    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>
@@ -1339,7 +1263,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>)
@@ -1347,20 +1271,20 @@ 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&>
@@ -1423,15 +1347,15 @@ class expected<_Tp, _Err> : private __expected_void_base<_Err> {
       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;
@@ -1443,15 +1367,15 @@ class expected<_Tp, _Err> : private __expected_void_base<_Err> {
   operator=(expected&& __rhs) noexcept(is_nothrow_move_assignable_v<_Err>&& is_nothrow_move_constructible_v<_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;
@@ -1460,10 +1384,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;
   }
@@ -1471,16 +1395,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);
     }
   }
@@ -1492,21 +1416,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());
       }
     }
   }
@@ -1518,51 +1442,51 @@ 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");
+        this->__has_val(), "expected::operator* requires the expected to contain a value");
   }
 
   _LIBCPP_HIDE_FROM_ABI constexpr void value() const& {
     static_assert(is_copy_constructible_v<_Err>);
-    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() && {
     static_assert(is_copy_constructible_v<_Err> && is_move_constructible_v<_Err>);
-    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_;
+        !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_;
+        !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_);
+        !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_);
+        !this->__has_val(), "expected::error requires the expected to contain an error");
+    return std::move(this->__unex());
   }
 
   template <class _Up = _Err>
@@ -1798,16 +1722,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 e764dbd66acaa9..eab2acf1471842 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 bc179b627a9a27..cf78907f6b65ea 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
@@ -52,12 +52,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@*:* 0-1 {{{{(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@*:* 0-1 {{{{(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 734f5b058240e2c14f6b1d38d8d5ffce1e80a0dc 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/55] 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 f691a4f5a7390c..d7f7713006bb7a 100644
--- a/libcxx/include/__expected/expected.h
+++ b/libcxx/include/__expected/expected.h
@@ -138,9 +138,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)
@@ -215,6 +224,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>)
@@ -1050,9 +1060,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_() {}
 
@@ -1113,6 +1130,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 00fc6c5c21ec69d756ff6582490aae78757a9d04 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/55] 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 d7f7713006bb7a..704552bf18d262 100644
--- a/libcxx/include/__expected/expected.h
+++ b/libcxx/include/__expected/expected.h
@@ -125,8 +125,8 @@ 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;
+    _LIBCPP_NO_UNIQUE_ADDRESS _Union __union_;
+    _LIBCPP_NO_UNIQUE_ADDRESS bool __has_val_;
   };
   return sizeof(__x) == sizeof(_Union);
 }

>From 2727d6bf327195ae96a8c0d1ac9ed2df96256763 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/55] 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 4d523d1ad69500..cf1909b9287323 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 eab2acf1471842..d533762340d1c6 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 c7e9ba08a2a78a7cf9fd732ff5f30aa3429e77d0 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/55] 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 704552bf18d262..f9ac89ff35a4fe 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>
@@ -162,12 +159,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>)
@@ -176,10 +173,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>();
@@ -284,9 +279,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< __can_stuff_tail, __union_t>::__type __union_;
@@ -298,9 +293,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:
@@ -331,10 +326,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< !__can_stuff_tail, __repr>::__type __repr_;
@@ -1080,7 +1075,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>)
@@ -1092,8 +1087,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>();
@@ -1188,7 +1182,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< __can_stuff_tail, __union_t>::__type __union_;
@@ -1202,7 +1196,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:
@@ -1233,8 +1227,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< !__can_stuff_tail, __repr>::__type __repr_;
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 82024a068f00d1..14c27c6286eb05 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
@@ -52,6 +52,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@*:* 0-1 {{{{(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@*:* 0-1 {{{{(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 cf78907f6b65ea..5f3b0be0fb627b 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
@@ -53,11 +53,11 @@ void test() {
     // expected-error-re@*:* 0-1 {{{{(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@*:* 0-1 {{{{(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 f8cab00843e56f7ed1a7f891a1ee49fc3236cb0f 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/55] 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 f443613fe7f343..424295bffdf2a2 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 84b57aea3cd231..23bf6783a14b1d 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 f0e19ac3c39827..0c41d11dd66fdb 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 1d31aaed45cf394711d17c7d17a66ecc992b7af1 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/55] simplify __expected_conditional_no_unique_address and
 rename to __conditional_no_unique_address

---
 libcxx/include/__expected/expected.h | 61 +++++++++++++++-------------
 1 file changed, 33 insertions(+), 28 deletions(-)

diff --git a/libcxx/include/__expected/expected.h b/libcxx/include/__expected/expected.h
index f9ac89ff35a4fe..0c4f076c98c7fe 100644
--- a/libcxx/include/__expected/expected.h
+++ b/libcxx/include/__expected/expected.h
@@ -88,34 +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>
@@ -203,7 +206,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) {}
 
@@ -284,7 +287,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_;
   };
 
@@ -306,7 +309,8 @@ 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{}, [&] { return __make_repr(__has_val, std::forward<_OtherUnion>(__other)); }) {}
+      : __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)
@@ -332,7 +336,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>
@@ -1110,7 +1114,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) {}
 
@@ -1185,7 +1189,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_;
   };
 
@@ -1207,7 +1211,8 @@ 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{}, [&] { return __make_repr(__has_val, std::forward<_OtherUnion>(__other)); }) {}
+      : __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)
@@ -1231,7 +1236,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 fa5eacda7f5107c6211d7c86d0b485114c3f8a83 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/55] 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 0c4f076c98c7fe..d502dd87e1d4e3 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 126fb938ffef27d85acf9f4d23f1a36595d1a2fc 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/55] 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 d502dd87e1d4e3..1cd0a4144bd2a4 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 0109b25da3ff6db96b9451c4ac672017cdd25e0b 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/55] rename __expected_can_stuff_tail to
 __fits_in_tail_padding and make more general

Suggested by ldionne.
---
 libcxx/include/__expected/expected.h | 67 ++++++++++++++--------------
 1 file changed, 34 insertions(+), 33 deletions(-)

diff --git a/libcxx/include/__expected/expected.h b/libcxx/include/__expected/expected.h
index 1cd0a4144bd2a4..d07d031d9bf568 100644
--- a/libcxx/include/__expected/expected.h
+++ b/libcxx/include/__expected/expected.h
@@ -131,15 +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 {
@@ -190,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;
@@ -215,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) {}
@@ -245,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);
@@ -259,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;
@@ -267,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;
@@ -289,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_);
@@ -297,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_);
@@ -318,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();
@@ -331,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)...);
@@ -346,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>
@@ -1104,7 +1105,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;
@@ -1123,7 +1124,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) {}
@@ -1151,20 +1152,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;
@@ -1172,7 +1173,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;
@@ -1191,7 +1192,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);
@@ -1199,13 +1200,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);
@@ -1220,12 +1221,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();
@@ -1233,7 +1234,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)...);
@@ -1246,7 +1247,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 cb7a0b9152bc58919999a11bd399de51e2ab3135 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/55] 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 d07d031d9bf568..5b1d8e7b05549b 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 6cf38930ad8258fcb9d44654b8cc1cdaebc09362 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 34/55] 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    | 136 ++++++++++++++++++
 11 files changed, 331 insertions(+)

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 1c8750b7acd100..2d3b03689b1d91 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 03fe888b0a5e7f..2f5291332355ca 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 8c419afd10729f..065827ae652c98 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 491de2dff03312..7e37f8bdf4abc0 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 34782303909e2a..f19599d43b32df 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 b1968bcc242403..a51916f874eeab 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 e6a29cd62583be..60ae0346f7af1e 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 1ae96530e528e8..699597d243c19b 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 ea947715af28f1..641eb4927a724e 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 07980dee13c1e9..25601af39a3162 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 90768ed8e7520b..c576e79e16ceea 100644
--- a/libcxx/test/std/utilities/expected/types.h
+++ b/libcxx/test/std/utilities/expected/types.h
@@ -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 f6c673581e4cff9c3b39ac54e8e62c4ec3aa5e3f 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 35/55] 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 c576e79e16ceea..81e295aa1dcd76 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`

>From 41b9459f90e79d865cc22472e59c4ab4921f6a49 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jan=20Kokem=C3=BCller?= <jan.kokemueller at gmail.com>
Date: Sun, 3 Dec 2023 11:05:14 +0100
Subject: [PATCH 36/55] try to fix transform_error.mandates.verify.cpp test on
 clang-cl

---
 .../expected.expected/transform_error.mandates.verify.cpp     | 4 ++++
 1 file changed, 4 insertions(+)

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 14c27c6286eb05..960237574f59a9 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
@@ -52,7 +52,11 @@ 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@*:* 0-1 {{{{(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.}}
+#if defined(TEST_COMPILER_CLANG) && defined(_MSC_VER)
+    // expected-error-re@*:* {{union member {{.*}} has reference type {{.*}}, which is a Microsoft extension}}
+#else
     // expected-error-re@*:* {{union member {{.*}} has reference type {{.*}}}}
+#endif
 
     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@*:* 0-1 {{{{(excess elements in struct initializer|no matching constructor for initialization of)}}{{.*}}}}

>From e00e21e73bd4b9f15627266ed32088891f61b221 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jan=20Kokem=C3=BCller?= <jan.kokemueller at gmail.com>
Date: Fri, 12 Jan 2024 20:49:35 +0100
Subject: [PATCH 37/55] add in_place_t tag to __conditional_no_unique_address
 constructor

---
 libcxx/include/__expected/expected.h | 22 +++++++++++-----------
 1 file changed, 11 insertions(+), 11 deletions(-)

diff --git a/libcxx/include/__expected/expected.h b/libcxx/include/__expected/expected.h
index 5b1d8e7b05549b..b64dd0be8b604e 100644
--- a/libcxx/include/__expected/expected.h
+++ b/libcxx/include/__expected/expected.h
@@ -106,7 +106,7 @@ struct __conditional_no_unique_address;
 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)
+  _LIBCPP_HIDE_FROM_ABI constexpr explicit __conditional_no_unique_address(in_place_t, _Args&&... __args)
       : __v(std::forward<_Args>(__args)...) {}
 
   template <class _Func, class... _Args>
@@ -120,7 +120,7 @@ struct __conditional_no_unique_address<true, _Tp> {
 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)
+  _LIBCPP_HIDE_FROM_ABI constexpr explicit __conditional_no_unique_address(in_place_t, _Args&&... __args)
       : __v(std::forward<_Args>(__args)...) {}
 
   template <class _Func, class... _Args>
@@ -198,21 +198,21 @@ class __expected_base {
 
     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) {}
+        : __union_(in_place, __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) {}
+        : __union_(in_place, __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) {}
+        : __union_(in_place, __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) {}
+        : __union_(in_place, __tag, std::forward<_Args>(__args)...), __has_val_(false) {}
 
     template <class _OtherUnion>
     _LIBCPP_HIDE_FROM_ABI constexpr explicit __repr(bool __has_val, _OtherUnion&& __other)
@@ -315,7 +315,7 @@ class __expected_base {
 protected:
   template <class... _Args>
   _LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_base(_Args&&... __args)
-      : __repr_(std::forward<_Args>(__args)...) {}
+      : __repr_(in_place, 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
@@ -1130,16 +1130,16 @@ 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_(in_place, __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) {}
+        : __union_(in_place, __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) {}
+        : __union_(in_place, __tag, std::forward<_Args>(__args)...), __has_val_(false) {}
 
     template <class _OtherUnion>
     _LIBCPP_HIDE_FROM_ABI constexpr explicit __repr(bool __has_val, _OtherUnion&& __other)
@@ -1236,7 +1236,7 @@ class __expected_void_base {
 protected:
   template <class... _Args>
   _LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_void_base(_Args&&... __args)
-      : __repr_(std::forward<_Args>(__args)...) {}
+      : __repr_(in_place, std::forward<_Args>(__args)...) {}
 
   template <class _OtherUnion>
   _LIBCPP_HIDE_FROM_ABI constexpr explicit __expected_void_base(bool __has_val, _OtherUnion&& __other)

>From 27783715258a4c3ca1c14b40eafa091597ae7150 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jan=20Kokem=C3=BCller?= <jan.kokemueller at gmail.com>
Date: Sat, 13 Jan 2024 08:41:57 +0100
Subject: [PATCH 38/55] make __union_ unconditionally no_unique_address to see
 if everything works

---
 libcxx/include/__expected/expected.h | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/libcxx/include/__expected/expected.h b/libcxx/include/__expected/expected.h
index b64dd0be8b604e..37df01e3a5e17b 100644
--- a/libcxx/include/__expected/expected.h
+++ b/libcxx/include/__expected/expected.h
@@ -298,7 +298,10 @@ class __expected_base {
         return __union_t(unexpect, std::forward<_OtherUnion>(__other).__unex_);
     }
 
-    _LIBCPP_NO_UNIQUE_ADDRESS __conditional_no_unique_address<__put_flag_in_tail, __union_t> __union_;
+    // XXX: refactor before merge -- the condition is set to `true` in order
+    // to check if everything works if the `__union_` is unconditionally
+    // `[[no_unique_address]]`.
+    _LIBCPP_NO_UNIQUE_ADDRESS __conditional_no_unique_address<true, __union_t> __union_;
     _LIBCPP_NO_UNIQUE_ADDRESS bool __has_val_;
   };
 

>From 6363349bbeb6a1da23fc0d9d26f07bce367a3acb Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jan=20Kokem=C3=BCller?= <jan.kokemueller at gmail.com>
Date: Tue, 16 Jan 2024 20:39:30 +0100
Subject: [PATCH 39/55] Update
 libcxx/test/std/utilities/expected/expected.void/monadic/transform_error.pass.cpp

Co-authored-by: Louis Dionne <ldionne.2 at gmail.com>
---
 .../expected/expected.void/monadic/transform_error.pass.cpp     | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

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 0c41d11dd66fdb..cd6e5a5038d28d 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
@@ -10,7 +10,7 @@
 
 // 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
-// XFAIL: gcc
+// XFAIL: gcc-13
 
 // <expected>
 

>From e25009ea6113421c551d8af1efcada737d7db519 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jan=20Kokem=C3=BCller?= <jan.kokemueller at gmail.com>
Date: Wed, 17 Jan 2024 19:36:03 +0100
Subject: [PATCH 40/55] fix typo

---
 .../expected.expected/transform_error.mandates.verify.cpp       | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

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 960237574f59a9..c512ddc27ff63c 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
@@ -7,7 +7,7 @@
 //===----------------------------------------------------------------------===//
 
 // Clang-18 fixed some spurious clang diagnostics. Once clang-18 is the
-// minumum required version these obsolete tests can be removed.
+// minimum required version these obsolete tests can be removed.
 // TODO(LLVM-20) remove spurious clang diagnostic tests.
 
 // UNSUPPORTED: c++03, c++11, c++14, c++17, c++20

>From 3dafea336951309cce53f2192571148460bd4419 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jan=20Kokem=C3=BCller?= <jan.kokemueller at gmail.com>
Date: Wed, 17 Jan 2024 19:36:22 +0100
Subject: [PATCH 41/55] try to workaround clang-cl CI failure by excluding
 clang-cl from this test

---
 .../expected.expected/transform_error.mandates.verify.cpp | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

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 c512ddc27ff63c..5bf094bf37709d 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
@@ -12,6 +12,10 @@
 
 // UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
 
+// With clang-cl, some warnings have a 'which is a Microsoft extension' suffix
+// which break the tests.
+// XFAIL: msvc
+
 // Test the mandates
 
 // template<class F> constexpr auto transform_error(F&& f) &;
@@ -52,11 +56,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@*:* 0-1 {{{{(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.}}
-#if defined(TEST_COMPILER_CLANG) && defined(_MSC_VER)
-    // expected-error-re@*:* {{union member {{.*}} has reference type {{.*}}, which is a Microsoft extension}}
-#else
     // expected-error-re@*:* {{union member {{.*}} has reference type {{.*}}}}
-#endif
 
     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@*:* 0-1 {{{{(excess elements in struct initializer|no matching constructor for initialization of)}}{{.*}}}}

>From d9f648e573b9f14a0d4b9ce35b0f19b5c8ad205f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jan=20Kokem=C3=BCller?= <jan.kokemueller at gmail.com>
Date: Wed, 17 Jan 2024 19:37:27 +0100
Subject: [PATCH 42/55] Revert "make __union_ unconditionally no_unique_address
 to see if everything works"

This reverts commit 4bb1d3e3460c54f0f26a92ed9dbbfbcf4edad1fc.
---
 libcxx/include/__expected/expected.h | 5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)

diff --git a/libcxx/include/__expected/expected.h b/libcxx/include/__expected/expected.h
index 37df01e3a5e17b..b64dd0be8b604e 100644
--- a/libcxx/include/__expected/expected.h
+++ b/libcxx/include/__expected/expected.h
@@ -298,10 +298,7 @@ class __expected_base {
         return __union_t(unexpect, std::forward<_OtherUnion>(__other).__unex_);
     }
 
-    // XXX: refactor before merge -- the condition is set to `true` in order
-    // to check if everything works if the `__union_` is unconditionally
-    // `[[no_unique_address]]`.
-    _LIBCPP_NO_UNIQUE_ADDRESS __conditional_no_unique_address<true, __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_;
   };
 

>From 6e65e00193f719c0de22b57ec051fa43c3c30b71 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jan=20Kokem=C3=BCller?= <jan.kokemueller at gmail.com>
Date: Fri, 19 Jan 2024 05:59:31 +0100
Subject: [PATCH 43/55] add issue link to comment on
 libcxx/test/std/utilities/expected/types.h

---
 libcxx/test/std/utilities/expected/types.h | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/libcxx/test/std/utilities/expected/types.h b/libcxx/test/std/utilities/expected/types.h
index 81e295aa1dcd76..2b6983fb399c67 100644
--- a/libcxx/test/std/utilities/expected/types.h
+++ b/libcxx/test/std/utilities/expected/types.h
@@ -200,7 +200,8 @@ static_assert(std::is_nothrow_move_constructible_v<TailClobbererNonTrivialMove<0
 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
+// may be placed into a `std::expected`'s tail padding (see
+// https://github.com/llvm/llvm-project/issues/70494). With a template
 // parameter `WithPaddedExpected` two cases can be tested:
 //
 // 1. The `std::expected<T, E>` itself has padding, because `T`/`E` _don't_

>From 1d90c611f3e4da86440d692414920e841615667b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jan=20Kokem=C3=BCller?= <jan.kokemueller at gmail.com>
Date: Fri, 19 Jan 2024 06:09:01 +0100
Subject: [PATCH 44/55] replace precondition comments with
 _LIBCPP_ASSERT_INTERNAL

---
 libcxx/include/__expected/expected.h | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/libcxx/include/__expected/expected.h b/libcxx/include/__expected/expected.h
index b64dd0be8b604e..4a62794113fd92 100644
--- a/libcxx/include/__expected/expected.h
+++ b/libcxx/include/__expected/expected.h
@@ -1371,17 +1371,19 @@ class expected<_Tp, _Err> : private __expected_void_base<_Err> {
   _LIBCPP_HIDE_FROM_ABI constexpr ~expected() = default;
 
 private:
-  // precondition: has_value()
   template <class... _Args>
   _LIBCPP_HIDE_FROM_ABI constexpr void __reinit_expected(unexpect_t, _Args&&... __args) {
+    _LIBCPP_ASSERT_INTERNAL(this->__has_val(), "__reinit_expected(unexpect_t, ...) needs value to be set");
+
     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) {
+    _LIBCPP_ASSERT_INTERNAL(!this->__has_val(), "__reinit_expected(in_place_t, ...) needs value to be unset");
+
     this->__destroy();
     this->__construct(in_place);
   }

>From ba2d4cd8f3183c088f83b3ee6aca5e2889912620 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jan=20Kokem=C3=BCller?= <jan.kokemueller at gmail.com>
Date: Fri, 19 Jan 2024 06:38:33 +0100
Subject: [PATCH 45/55] add comment to the __expected_base class

---
 libcxx/include/__expected/expected.h | 64 ++++++++++++++++++++++++++++
 1 file changed, 64 insertions(+)

diff --git a/libcxx/include/__expected/expected.h b/libcxx/include/__expected/expected.h
index 4a62794113fd92..52cc1dc38f5a05 100644
--- a/libcxx/include/__expected/expected.h
+++ b/libcxx/include/__expected/expected.h
@@ -142,6 +142,70 @@ inline constexpr bool __fits_in_tail_padding = []() {
   return sizeof(__x) == sizeof(_First);
 }();
 
+// This class implements the storage used by `std::expected`. We have a few
+// goals for this storage:
+// 1. Whenever the underlying {_Tp | _Unex} combination has free bytes in its
+//    tail padding, we should reuse it to store the bool discriminator of the
+//    expected, so as to save space.
+// 2. Whenever the `expected<_Tp, _Unex>` as a whole has free bytes in its tail
+//    padding, we should allow an object following the expected to be stored in
+//    its tail padding.
+// 3. However, we never want a user object (say `X`) that would follow an
+//    `expected<_Tp, _Unex>` to be stored in the padding bytes of the
+//    underlying {_Tp | _Unex} union, if any. That is because we use
+//    `construct_at` on that union, which would end up overwriting the `X`
+//    member if it is stored in the tail padding of the union.
+//
+// To achieve this, `__expected_base`'s logic is implemented in an inner
+// `__repr` class. `__expected_base` holds one `__repr` member which is
+// conditionally `[[no_unique_address]]`. The `__repr` class holds the
+// underlying {_Tp | _Unex} union and a boolean "has value" flag.
+//
+// Which one of the `__repr_`/`__union_` members is `[[no_unique_address]]`
+// depends on whether the "has value" boolean fits into the tail padding of
+// the underlying {_Tp | _Unex} union:
+//
+// - In case the "has value" bool fits into the tail padding of the union, the
+//   whole `__repr_` member is _not_ `[[no_unique_address]]` as it needs to be
+//   transparently replaced on `emplace()`/`swap()` etc.
+// - In case the "has value" bool does not fit into the tail padding of the
+//   union, only the union member must be transparently replaced (therefore is
+//   _not_ `[[no_unique_address]]`) and the "has value" flag must be adjusted
+//   manually.
+//
+// This way, the member that is transparently replaced on mutating operations
+// is never `[[no_unique_address]]`, satisfying the requirements from
+// "[basic.life]" in the standard.
+//
+// Stripped away of all superfluous elements, the layout of `__expected_base`
+// then looks like this:
+//
+//     template <class Tp, class Err>
+//     class expected_base {
+//       union union_t {
+//         [[no_unique_address]] Tp val;
+//         [[no_unique_address]] Err unex;
+//       };
+//
+//       struct repr {
+//       private:
+//         // If "has value" fits into the tail, this should be
+//         // `[[no_unique_address]]`, otherwise not.
+//         [[no_unique_address]] conditional_no_unique_address<
+//             fits_in_tail_padding<union_t, bool>,
+//             union_t>::type union_;
+//         [[no_unique_address]] bool has_val_;
+//       };
+//
+//     protected:
+//       // If "has value" fits into the tail, this must _not_ be
+//       // `[[no_unique_address]]` so that we fill out the
+//       // complete `expected` object.
+//       [[no_unique_address]] conditional_no_unique_address<
+//           !fits_in_tail_padding<union_t, bool>,
+//           repr>::type repr_;
+//     };
+//
 template <class _Tp, class _Err>
 class __expected_base {
   // use named union because [[no_unique_address]] cannot be applied to an unnamed union,

>From b6727b6fe96c4a98cb6dcbe10d6d120c67e8c406 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jan=20Kokem=C3=BCller?= <jan.kokemueller at gmail.com>
Date: Fri, 19 Jan 2024 06:42:41 +0100
Subject: [PATCH 46/55] Update
 libcxx/test/libcxx/utilities/expected/expected.void/no_unique_address.compile.pass.cpp

Co-authored-by: Louis Dionne <ldionne.2 at gmail.com>
---
 .../expected/expected.void/no_unique_address.compile.pass.cpp   | 2 ++
 1 file changed, 2 insertions(+)

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 d533762340d1c6..fdee8b71e5d983 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
@@ -11,6 +11,8 @@
 // XFAIL: msvc
 
 // test [[no_unique_address]] is applied to the union
+// In particular, we ensure that we reuse tail padding in the T
+// to store the discriminator whenever we can.
 
 #include <__type_traits/datasizeof.h>
 #include <expected>

>From e37d5d8cfa009e69b8dbf9b2615148d7e615b44b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jan=20Kokem=C3=BCller?= <jan.kokemueller at gmail.com>
Date: Fri, 19 Jan 2024 19:05:20 +0100
Subject: [PATCH 47/55] add comment to
 __conditional_no_unique_address_invoke_tag

---
 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 52cc1dc38f5a05..205130fa11448a 100644
--- a/libcxx/include/__expected/expected.h
+++ b/libcxx/include/__expected/expected.h
@@ -88,6 +88,12 @@ _LIBCPP_HIDE_FROM_ABI void __throw_bad_expected_access(_Arg&& __arg) {
 #  endif
 }
 
+// If parameter type `_Tp` of `__conditional_no_unique_address` is neither
+// copyable nor movable, a constructor with this tag is provided. For that
+// constructor, the user has to provide a function and arguments. The function
+// must return an object of type `_Tp`. When the function is invoked by the
+// constructor, guaranteed copy elision kicks in and the `_Tp` is constructed
+// in place.
 struct __conditional_no_unique_address_invoke_tag {};
 
 // This class implements an object with `[[no_unique_address]]` conditionally applied to it,

>From c46e26f416b135cac400fb7d5cb315bf97b32091 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jan=20Kokem=C3=BCller?= <jan.kokemueller at gmail.com>
Date: Fri, 19 Jan 2024 19:23:15 +0100
Subject: [PATCH 48/55] add a comment to the __repr constructor that calls
 __make_union

---
 libcxx/include/__expected/expected.h | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/libcxx/include/__expected/expected.h b/libcxx/include/__expected/expected.h
index 205130fa11448a..fe132b2d4cdde0 100644
--- a/libcxx/include/__expected/expected.h
+++ b/libcxx/include/__expected/expected.h
@@ -284,6 +284,11 @@ class __expected_base {
                                                     _Args&&... __args)
         : __union_(in_place, __tag, std::forward<_Args>(__args)...), __has_val_(false) {}
 
+    // The return value of `__make_union` must be constructed in place in the
+    // `__v` member of `__union_`, relying on guaranteed copy elision. To do
+    // this, the `__conditional_no_unique_address_invoke_tag` constructor is
+    // called with a lambda that is immediately called inside
+    // `__conditional_no_unique_address`'s constructor.
     template <class _OtherUnion>
     _LIBCPP_HIDE_FROM_ABI constexpr explicit __repr(bool __has_val, _OtherUnion&& __other)
       requires(!__put_flag_in_tail)

>From a5ad48f316d23682253047c979a885387b009681 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jan=20Kokem=C3=BCller?= <jan.kokemueller at gmail.com>
Date: Fri, 19 Jan 2024 19:46:32 +0100
Subject: [PATCH 49/55] add comment to __destroy_union

---
 libcxx/include/__expected/expected.h | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/libcxx/include/__expected/expected.h b/libcxx/include/__expected/expected.h
index fe132b2d4cdde0..e96d06cfa35322 100644
--- a/libcxx/include/__expected/expected.h
+++ b/libcxx/include/__expected/expected.h
@@ -323,6 +323,8 @@ class __expected_base {
     _LIBCPP_HIDE_FROM_ABI constexpr void __destroy_union()
       requires(!__put_flag_in_tail && (is_trivially_destructible_v<_Tp> && is_trivially_destructible_v<_Err>))
     {
+      // Note: Since the destructor of the union is trivial, this does nothing
+      // except to end the lifetime of the union.
       std::destroy_at(&__union_.__v);
     }
 

>From bd65b2a8d97b06b08eae7d1f706ee2c503f04f81 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jan=20Kokem=C3=BCller?= <jan.kokemueller at gmail.com>
Date: Sat, 20 Jan 2024 12:10:54 +0100
Subject: [PATCH 50/55] introduce bool __allow_reusing_expected_tail_padding as
 negation of __put_flag_in_tail for better readability

---
 libcxx/include/__expected/expected.h | 36 +++++++++++++++-------------
 1 file changed, 20 insertions(+), 16 deletions(-)

diff --git a/libcxx/include/__expected/expected.h b/libcxx/include/__expected/expected.h
index e96d06cfa35322..893f838db3ee7c 100644
--- a/libcxx/include/__expected/expected.h
+++ b/libcxx/include/__expected/expected.h
@@ -261,7 +261,8 @@ class __expected_base {
     _LIBCPP_NO_UNIQUE_ADDRESS _Err __unex_;
   };
 
-  static constexpr bool __put_flag_in_tail = __fits_in_tail_padding<__union_t, bool>;
+  static constexpr bool __put_flag_in_tail                    = __fits_in_tail_padding<__union_t, bool>;
+  static constexpr bool __allow_reusing_expected_tail_padding = !__put_flag_in_tail;
 
   struct __repr {
     _LIBCPP_HIDE_FROM_ABI constexpr explicit __repr() = delete;
@@ -291,7 +292,7 @@ class __expected_base {
     // `__conditional_no_unique_address`'s constructor.
     template <class _OtherUnion>
     _LIBCPP_HIDE_FROM_ABI constexpr explicit __repr(bool __has_val, _OtherUnion&& __other)
-      requires(!__put_flag_in_tail)
+      requires(__allow_reusing_expected_tail_padding)
         : __union_(__conditional_no_unique_address_invoke_tag{},
                    [&] { return __make_union(__has_val, std::forward<_OtherUnion>(__other)); }),
           __has_val_(__has_val) {}
@@ -321,7 +322,8 @@ class __expected_base {
     }
 
     _LIBCPP_HIDE_FROM_ABI constexpr void __destroy_union()
-      requires(!__put_flag_in_tail && (is_trivially_destructible_v<_Tp> && is_trivially_destructible_v<_Err>))
+      requires(__allow_reusing_expected_tail_padding &&
+               (is_trivially_destructible_v<_Tp> && is_trivially_destructible_v<_Err>))
     {
       // Note: Since the destructor of the union is trivial, this does nothing
       // except to end the lifetime of the union.
@@ -329,7 +331,8 @@ class __expected_base {
     }
 
     _LIBCPP_HIDE_FROM_ABI constexpr void __destroy_union()
-      requires(!__put_flag_in_tail && (!is_trivially_destructible_v<_Tp> || !is_trivially_destructible_v<_Err>))
+      requires(__allow_reusing_expected_tail_padding &&
+               (!is_trivially_destructible_v<_Tp> || !is_trivially_destructible_v<_Err>))
     {
       __destroy_union_member();
       std::destroy_at(&__union_.__v);
@@ -337,7 +340,7 @@ class __expected_base {
 
     template <class... _Args>
     _LIBCPP_HIDE_FROM_ABI constexpr void __construct_union(in_place_t, _Args&&... __args)
-      requires(!__put_flag_in_tail)
+      requires(__allow_reusing_expected_tail_padding)
     {
       std::construct_at(&__union_.__v, in_place, std::forward<_Args>(__args)...);
       __has_val_ = true;
@@ -345,7 +348,7 @@ class __expected_base {
 
     template <class... _Args>
     _LIBCPP_HIDE_FROM_ABI constexpr void __construct_union(unexpect_t, _Args&&... __args)
-      requires(!__put_flag_in_tail)
+      requires(__allow_reusing_expected_tail_padding)
     {
       std::construct_at(&__union_.__v, unexpect, std::forward<_Args>(__args)...);
       __has_val_ = false;
@@ -367,7 +370,7 @@ class __expected_base {
 
     template <class _OtherUnion>
     _LIBCPP_HIDE_FROM_ABI static constexpr __union_t __make_union(bool __has_val, _OtherUnion&& __other)
-      requires(!__put_flag_in_tail)
+      requires(__allow_reusing_expected_tail_padding)
     {
       if (__has_val)
         return __union_t(in_place, std::forward<_OtherUnion>(__other).__val_);
@@ -443,7 +446,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<!__put_flag_in_tail, __repr> __repr_;
+  _LIBCPP_NO_UNIQUE_ADDRESS __conditional_no_unique_address<__allow_reusing_expected_tail_padding, __repr> __repr_;
 };
 
 template <class _Tp, class _Err>
@@ -1201,7 +1204,8 @@ class __expected_void_base {
     _LIBCPP_NO_UNIQUE_ADDRESS _Err __unex_;
   };
 
-  static constexpr bool __put_flag_in_tail = __fits_in_tail_padding<__union_t, bool>;
+  static constexpr bool __put_flag_in_tail                    = __fits_in_tail_padding<__union_t, bool>;
+  static constexpr bool __allow_reusing_expected_tail_padding = !__put_flag_in_tail;
 
   struct __repr {
     _LIBCPP_HIDE_FROM_ABI constexpr explicit __repr() = delete;
@@ -1220,7 +1224,7 @@ class __expected_void_base {
 
     template <class _OtherUnion>
     _LIBCPP_HIDE_FROM_ABI constexpr explicit __repr(bool __has_val, _OtherUnion&& __other)
-      requires(!__put_flag_in_tail)
+      requires(__allow_reusing_expected_tail_padding)
         : __union_(__conditional_no_unique_address_invoke_tag{},
                    [&] { return __make_union(__has_val, std::forward<_OtherUnion>(__other)); }),
           __has_val_(__has_val) {}
@@ -1248,20 +1252,20 @@ class __expected_void_base {
     }
 
     _LIBCPP_HIDE_FROM_ABI constexpr void __destroy_union()
-      requires(!__put_flag_in_tail && is_trivially_destructible_v<_Err>)
+      requires(__allow_reusing_expected_tail_padding && is_trivially_destructible_v<_Err>)
     {
       std::destroy_at(&__union_.__v);
     }
 
     _LIBCPP_HIDE_FROM_ABI constexpr void __destroy_union()
-      requires(!__put_flag_in_tail && !is_trivially_destructible_v<_Err>)
+      requires(__allow_reusing_expected_tail_padding && !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(!__put_flag_in_tail)
+      requires(__allow_reusing_expected_tail_padding)
     {
       std::construct_at(&__union_.__v, in_place);
       __has_val_ = true;
@@ -1269,7 +1273,7 @@ class __expected_void_base {
 
     template <class... _Args>
     _LIBCPP_HIDE_FROM_ABI constexpr void __construct_union(unexpect_t, _Args&&... __args)
-      requires(!__put_flag_in_tail)
+      requires(__allow_reusing_expected_tail_padding)
     {
       std::construct_at(&__union_.__v, unexpect, std::forward<_Args>(__args)...);
       __has_val_ = false;
@@ -1288,7 +1292,7 @@ class __expected_void_base {
 
     template <class _OtherUnion>
     _LIBCPP_HIDE_FROM_ABI static constexpr __union_t __make_union(bool __has_val, _OtherUnion&& __other)
-      requires(!__put_flag_in_tail)
+      requires(__allow_reusing_expected_tail_padding)
     {
       if (__has_val)
         return __union_t(in_place);
@@ -1343,7 +1347,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<!__put_flag_in_tail, __repr> __repr_;
+  _LIBCPP_NO_UNIQUE_ADDRESS __conditional_no_unique_address<__allow_reusing_expected_tail_padding, __repr> __repr_;
 };
 
 template <class _Tp, class _Err>

>From b5a179824312791b9bb5d7e9e70413feb45ea2e4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jan=20Kokem=C3=BCller?= <jan.kokemueller at gmail.com>
Date: Sat, 20 Jan 2024 12:14:08 +0100
Subject: [PATCH 51/55] use
 put_flag_in_tail/allow_reusing_expected_tail_padding in synopsis

---
 libcxx/include/__expected/expected.h | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/libcxx/include/__expected/expected.h b/libcxx/include/__expected/expected.h
index 893f838db3ee7c..689de14e165360 100644
--- a/libcxx/include/__expected/expected.h
+++ b/libcxx/include/__expected/expected.h
@@ -193,12 +193,15 @@ inline constexpr bool __fits_in_tail_padding = []() {
 //         [[no_unique_address]] Err unex;
 //       };
 //
+//       static constexpr bool put_flag_in_tail                    = fits_in_tail_padding<union_t, bool>;
+//       static constexpr bool allow_reusing_expected_tail_padding = !put_flag_in_tail;
+//
 //       struct repr {
 //       private:
 //         // If "has value" fits into the tail, this should be
 //         // `[[no_unique_address]]`, otherwise not.
 //         [[no_unique_address]] conditional_no_unique_address<
-//             fits_in_tail_padding<union_t, bool>,
+//             put_flag_in_tail,
 //             union_t>::type union_;
 //         [[no_unique_address]] bool has_val_;
 //       };
@@ -208,7 +211,7 @@ inline constexpr bool __fits_in_tail_padding = []() {
 //       // `[[no_unique_address]]` so that we fill out the
 //       // complete `expected` object.
 //       [[no_unique_address]] conditional_no_unique_address<
-//           !fits_in_tail_padding<union_t, bool>,
+//           allow_reusing_expected_tail_padding,
 //           repr>::type repr_;
 //     };
 //

>From 9664d71ec1b0e182e34b6a95a9513c36d10edb60 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jan=20Kokem=C3=BCller?= <jan.kokemueller at gmail.com>
Date: Sat, 20 Jan 2024 12:21:27 +0100
Subject: [PATCH 52/55] autoformat

---
 libcxx/include/__expected/expected.h | 28 ++++++++++++++--------------
 1 file changed, 14 insertions(+), 14 deletions(-)

diff --git a/libcxx/include/__expected/expected.h b/libcxx/include/__expected/expected.h
index 689de14e165360..443d9257dc598d 100644
--- a/libcxx/include/__expected/expected.h
+++ b/libcxx/include/__expected/expected.h
@@ -489,7 +489,7 @@ class expected : private __expected_base<_Tp, _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
+      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()) {}
@@ -500,7 +500,7 @@ class expected : private __expected_base<_Tp, _Err> {
   = default;
 
   _LIBCPP_HIDE_FROM_ABI constexpr expected(expected&& __other) noexcept(
-      is_nothrow_move_constructible_v<_Tp>&& is_nothrow_move_constructible_v<_Err>)
+      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())) {}
@@ -541,15 +541,15 @@ class expected : private __expected_base<_Tp, _Err> {
   _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
+          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
+          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>
@@ -628,8 +628,8 @@ class expected : private __expected_base<_Tp, _Err> {
   _LIBCPP_HIDE_FROM_ABI constexpr expected& operator=(const expected&) = delete;
 
   _LIBCPP_HIDE_FROM_ABI constexpr expected& operator=(const expected& __rhs) noexcept(
-      is_nothrow_copy_assignable_v<_Tp>&& is_nothrow_copy_constructible_v<_Tp>&& is_nothrow_copy_assignable_v<_Err>&&
-          is_nothrow_copy_constructible_v<_Err>) // strengthened
+      is_nothrow_copy_assignable_v<_Tp> && is_nothrow_copy_constructible_v<_Tp> && is_nothrow_copy_assignable_v<_Err> &&
+      is_nothrow_copy_constructible_v<_Err>) // strengthened
     requires(is_copy_assignable_v<_Tp> && is_copy_constructible_v<_Tp> && is_copy_assignable_v<_Err> &&
              is_copy_constructible_v<_Err> &&
              (is_nothrow_move_constructible_v<_Tp> || is_nothrow_move_constructible_v<_Err>))
@@ -647,8 +647,8 @@ class expected : private __expected_base<_Tp, _Err> {
   }
 
   _LIBCPP_HIDE_FROM_ABI constexpr expected&
-  operator=(expected&& __rhs) noexcept(is_nothrow_move_assignable_v<_Tp>&& is_nothrow_move_constructible_v<_Tp>&&
-                                           is_nothrow_move_assignable_v<_Err>&& is_nothrow_move_constructible_v<_Err>)
+  operator=(expected&& __rhs) noexcept(is_nothrow_move_assignable_v<_Tp> && is_nothrow_move_constructible_v<_Tp> &&
+                                       is_nothrow_move_assignable_v<_Err> && is_nothrow_move_constructible_v<_Err>)
     requires(is_move_constructible_v<_Tp> && is_move_assignable_v<_Tp> && is_move_constructible_v<_Err> &&
              is_move_assignable_v<_Err> &&
              (is_nothrow_move_constructible_v<_Tp> || is_nothrow_move_constructible_v<_Err>))
@@ -732,8 +732,8 @@ class expected : private __expected_base<_Tp, _Err> {
 public:
   // [expected.object.swap], swap
   _LIBCPP_HIDE_FROM_ABI constexpr void
-  swap(expected& __rhs) noexcept(is_nothrow_move_constructible_v<_Tp>&& is_nothrow_swappable_v<_Tp>&&
-                                     is_nothrow_move_constructible_v<_Err>&& is_nothrow_swappable_v<_Err>)
+  swap(expected& __rhs) noexcept(is_nothrow_move_constructible_v<_Tp> && is_nothrow_swappable_v<_Tp> &&
+                                 is_nothrow_move_constructible_v<_Err> && is_nothrow_swappable_v<_Err>)
     requires(is_swappable_v<_Tp> && is_swappable_v<_Err> && is_move_constructible_v<_Tp> &&
              is_move_constructible_v<_Err> &&
              (is_nothrow_move_constructible_v<_Tp> || is_nothrow_move_constructible_v<_Err>))
@@ -1477,7 +1477,7 @@ class expected<_Tp, _Err> : private __expected_void_base<_Err> {
   _LIBCPP_HIDE_FROM_ABI constexpr expected& operator=(const expected&) = delete;
 
   _LIBCPP_HIDE_FROM_ABI constexpr expected& operator=(const expected& __rhs) noexcept(
-      is_nothrow_copy_assignable_v<_Err>&& is_nothrow_copy_constructible_v<_Err>) // strengthened
+      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->__has_val()) {
@@ -1497,7 +1497,7 @@ class expected<_Tp, _Err> : private __expected_void_base<_Err> {
   _LIBCPP_HIDE_FROM_ABI constexpr expected& operator=(expected&&) = delete;
 
   _LIBCPP_HIDE_FROM_ABI constexpr expected&
-  operator=(expected&& __rhs) noexcept(is_nothrow_move_assignable_v<_Err>&& is_nothrow_move_constructible_v<_Err>)
+  operator=(expected&& __rhs) noexcept(is_nothrow_move_assignable_v<_Err> && is_nothrow_move_constructible_v<_Err>)
     requires(is_move_assignable_v<_Err> && is_move_constructible_v<_Err>)
   {
     if (this->__has_val()) {
@@ -1544,7 +1544,7 @@ class expected<_Tp, _Err> : private __expected_void_base<_Err> {
 
   // [expected.void.swap], swap
   _LIBCPP_HIDE_FROM_ABI constexpr void
-  swap(expected& __rhs) noexcept(is_nothrow_move_constructible_v<_Err>&& is_nothrow_swappable_v<_Err>)
+  swap(expected& __rhs) 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) {

>From e82f622c950b9361e2be41c56f09ef718c77495b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jan=20Kokem=C3=BCller?= <jan.kokemueller at gmail.com>
Date: Sun, 21 Jan 2024 05:40:07 +0100
Subject: [PATCH 53/55] add 'XFAIL: msvc' to
 expected.void/transform_error.mandates.verify.cpp test

---
 .../expected.void/transform_error.mandates.verify.cpp         | 4 ++++
 1 file changed, 4 insertions(+)

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 5f3b0be0fb627b..4f4f5839361e2a 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
@@ -12,6 +12,10 @@
 
 // UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
 
+// With clang-cl, some warnings have a 'which is a Microsoft extension' suffix
+// which break the tests.
+// XFAIL: msvc
+
 // Test the mandates
 
 // template<class F> constexpr auto transform_error(F&& f) &;

>From f4df3f9daf9f9260a219ced85883bab185f623f9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jan=20Kokem=C3=BCller?= <jan.kokemueller at gmail.com>
Date: Mon, 22 Jan 2024 06:10:05 +0100
Subject: [PATCH 54/55] use 'XFAIL: gcc-13' instead of 'XFAIL: gcc'

---
 .../expected/expected.expected/monadic/transform.pass.cpp       | 2 +-
 .../expected/expected.expected/monadic/transform_error.pass.cpp | 2 +-
 2 files changed, 2 insertions(+), 2 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 424295bffdf2a2..d38a46f0452485 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
@@ -10,7 +10,7 @@
 
 // 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
-// XFAIL: gcc
+// XFAIL: gcc-13
 
 // <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 23bf6783a14b1d..ec55f637f02020 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
@@ -10,7 +10,7 @@
 
 // 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.
-// XFAIL: gcc
+// XFAIL: gcc-13
 
 // <expected>
 

>From 89290d5cbd801b43f1e30fc26d531f5da6d25ef3 Mon Sep 17 00:00:00 2001
From: Louis Dionne <ldionne.2 at gmail.com>
Date: Mon, 22 Jan 2024 08:49:44 -0500
Subject: [PATCH 55/55] Add release note

---
 libcxx/docs/ReleaseNotes/18.rst | 22 ++++++++++++++++++++++
 1 file changed, 22 insertions(+)

diff --git a/libcxx/docs/ReleaseNotes/18.rst b/libcxx/docs/ReleaseNotes/18.rst
index 311a06e34c49d2..8044584919f60e 100644
--- a/libcxx/docs/ReleaseNotes/18.rst
+++ b/libcxx/docs/ReleaseNotes/18.rst
@@ -219,6 +219,28 @@ ABI Affecting Changes
   should not be a major problem for most users. However it is probably worth auditing ranges-heavy code for ABI boundaries that 
   would contain these views, or for types that contain these views as members and which are passed across ABI boundaries.
 
+- The amount of padding bytes available for use at the end of certain ``std::expected`` instantiations has changed in this
+  release. This is an ABI break for any code that held a ``std::expected`` member with ``[[no_unique_address]]`` in an
+  ABI-facing type. In those cases, the layout of the enclosing type will change, breaking the ABI. However, the
+  ``std::expected<T, E>`` member requires a few characteristics in order to be affected by this change:
+
+  - A type equivalent to ``union {T ; E}`` needs to have more than one byte of padding available.
+  - The ``std::expected<T, E>`` member must have been in a situation where its padding bytes were previously reused by
+    another object, which can happen in a few cases (this is probably not exhaustive):
+
+    - It is a member with ``[[no_unique_address]]`` applied to it, and it is followed by another data member, or
+    - It is a member with ``[[no_unique_address]]`` applied to it, and it is the last member of the user-defined type,
+      and that user-defined type is used in ways that its padding bytes can be reused, or
+    - It is inherited from
+
+  We expect that this will not be a very frequent occurrence. However, there is unfortunately no technique we can use
+  in the library to catch such misuse. Indeed, even applying an ABI tag to ``std::expected`` would not help since ABI
+  tags are not propagated to containing types. As a result, if you notice very difficult to explain bugs around the
+  usage of a ``std::expected``, you should consider checking whether you are hitting this ABI break. This change was
+  done to fix `#70494 <https://github.com/llvm/llvm-project/issues/70494>`_ and the vendor communication is handled
+  in `#70820 <https://github.com/llvm/llvm-project/issues/70820>`_.
+
+
 Build System Changes
 --------------------
 



More information about the llvm-commits mailing list