[libcxx-commits] [libcxx] [libc++] Replace `__compressed_pair` with `[[no_unique_address]]` (PR #76756)

Nikolas Klauser via libcxx-commits libcxx-commits at lists.llvm.org
Mon Jun 24 12:28:18 PDT 2024


https://github.com/philnik777 updated https://github.com/llvm/llvm-project/pull/76756

>From 9f7a8778eb4eaf1c82848d57049b486f6a88d8c1 Mon Sep 17 00:00:00 2001
From: Nikolas Klauser <nikolasklauser at berlin.de>
Date: Mon, 1 Jan 2024 18:47:45 +0100
Subject: [PATCH] [libc++] Replace `__compressed_pair` with
 `[[no_unique_address]]`

---
 libcxx/docs/ReleaseNotes/19.rst               |   3 +
 libcxx/docs/ReleaseNotes/20.rst               |  77 +++++++
 libcxx/include/__config                       |   1 +
 libcxx/include/__configuration/abi.h          |   7 +
 libcxx/include/__functional/function.h        |  27 +--
 libcxx/include/__hash_table                   | 155 ++++++++------
 libcxx/include/__memory/compressed_pair.h     | 200 ++++++------------
 libcxx/include/__memory/shared_ptr.h          |  44 ++--
 libcxx/include/__memory/unique_ptr.h          | 124 ++++++-----
 libcxx/include/__split_buffer                 |  27 ++-
 libcxx/include/__tree                         |  53 ++---
 libcxx/include/__type_traits/datasizeof.h     |   4 +
 libcxx/include/deque                          |  45 ++--
 libcxx/include/forward_list                   |  21 +-
 libcxx/include/future                         |  22 +-
 libcxx/include/list                           |  21 +-
 libcxx/include/string                         | 147 +++++++------
 libcxx/include/vector                         |  89 ++++----
 .../missing_hash_specialization.verify.cpp    |   9 +-
 .../compressed_pair/compressed_pair.pass.cpp  |  52 -----
 .../libcxx.control_block_layout.pass.cpp      | 113 +++++++---
 21 files changed, 645 insertions(+), 596 deletions(-)
 create mode 100644 libcxx/docs/ReleaseNotes/20.rst
 delete mode 100644 libcxx/test/libcxx/memory/compressed_pair/compressed_pair.pass.cpp

diff --git a/libcxx/docs/ReleaseNotes/19.rst b/libcxx/docs/ReleaseNotes/19.rst
index 71de10abb6eaa..e355893edc90a 100644
--- a/libcxx/docs/ReleaseNotes/19.rst
+++ b/libcxx/docs/ReleaseNotes/19.rst
@@ -143,6 +143,9 @@ ABI Affecting Changes
   ``random_device`` could throw a ``system_error`` with this value. It now
   throws ``ENOMSG``.
 
+- The internal structure ``__compressed_pair`` has been replaced with ``[[no_unique_address]]``. This change results in
+  empty final types being placed at the beginning of the object instead of where the beginning of the
+  ``__compressed_pair`` subobject was. This is only observable by checking the address of the subobject.
 
 Build System Changes
 --------------------
diff --git a/libcxx/docs/ReleaseNotes/20.rst b/libcxx/docs/ReleaseNotes/20.rst
new file mode 100644
index 0000000000000..93b19df8cd167
--- /dev/null
+++ b/libcxx/docs/ReleaseNotes/20.rst
@@ -0,0 +1,77 @@
+===========================================
+Libc++ 20.0.0 (In-Progress) Release Notes
+===========================================
+
+.. contents::
+   :local:
+   :depth: 2
+
+Written by the `Libc++ Team <https://libcxx.llvm.org>`_
+
+.. warning::
+
+   These are in-progress notes for the upcoming libc++ 20.0.0 release.
+   Release notes for previous releases can be found on
+   `the Download Page <https://releases.llvm.org/download.html>`_.
+
+Introduction
+============
+
+This document contains the release notes for the libc++ C++ Standard Library,
+part of the LLVM Compiler Infrastructure, release 19.0.0. Here we describe the
+status of libc++ in some detail, including major improvements from the previous
+release and new feature work. For the general LLVM release notes, see `the LLVM
+documentation <https://llvm.org/docs/ReleaseNotes.html>`_. All LLVM releases may
+be downloaded from the `LLVM releases web site <https://llvm.org/releases/>`_.
+
+For more information about libc++, please see the `Libc++ Web Site
+<https://libcxx.llvm.org>`_ or the `LLVM Web Site <https://llvm.org>`_.
+
+Note that if you are reading this file from a Git checkout or the
+main Libc++ web page, this document applies to the *next* release, not
+the current one. To see the release notes for a specific release, please
+see the `releases page <https://llvm.org/releases/>`_.
+
+What's New in Libc++ 20.0.0?
+==============================
+
+Implemented Papers
+------------------
+
+Improvements and New Features
+-----------------------------
+
+- The internal structure ``__compressed_pair`` has been replaced with ``[[no_unique_address]]``, resulting in reduced
+  compile times and smaller debug information as well as better code gen if optimizations are disabled.
+
+Deprecations and Removals
+-------------------------
+
+- TODO: The ``LIBCXX_ENABLE_ASSERTIONS`` CMake variable and the ``_LIBCPP_ENABLE_ASSERTIONS`` macro that were used to
+  enable the safe mode will be removed in LLVM 20.
+
+Upcoming Deprecations and Removals
+----------------------------------
+
+LLVM 21
+~~~~~~~
+TODO
+
+
+ABI Affecting Changes
+---------------------
+
+- The internal structure ``__compressed_pair`` has been replaced with ``[[no_unique_address]]``. This change results in
+  empty final types being placed at the beginning of the object instead of where the beginning of the
+  ``__compressed_pair`` subobject was. This is only observable by checking the address of the subobject.
+
+Build System Changes
+--------------------
+
+- The ``LIBCXX_EXECUTOR`` and ``LIBCXXABI_EXECUTOR`` CMake variables have been removed. Please
+  set ``LIBCXX_TEST_PARAMS`` to ``executor=<...>`` instead.
+
+- The Cmake variable ``LIBCXX_ENABLE_CLANG_TIDY`` has been removed. The build system has been changed
+  to automatically detect the presence of ``clang-tidy`` and the required ``Clang`` libraries.
+
+- The CMake options ``LIBCXX_INSTALL_MODULES`` now defaults to ``ON``.
diff --git a/libcxx/include/__config b/libcxx/include/__config
index dfb14fd6a380c..54d0d1addeeb0 100644
--- a/libcxx/include/__config
+++ b/libcxx/include/__config
@@ -31,6 +31,7 @@
 
 #  define _LIBCPP_CONCAT_IMPL(_X, _Y) _X##_Y
 #  define _LIBCPP_CONCAT(_X, _Y) _LIBCPP_CONCAT_IMPL(_X, _Y)
+#  define _LIBCPP_CONCAT3(X, Y, Z) _LIBCPP_CONCAT(X, _LIBCPP_CONCAT(Y, Z))
 
 #  if __STDC_HOSTED__ == 0
 #    define _LIBCPP_FREESTANDING
diff --git a/libcxx/include/__configuration/abi.h b/libcxx/include/__configuration/abi.h
index 513da6e3b81b6..f4e57ba67e486 100644
--- a/libcxx/include/__configuration/abi.h
+++ b/libcxx/include/__configuration/abi.h
@@ -91,6 +91,13 @@
 #  define _LIBCPP_ABI_USE_WRAP_ITER_IN_STD_STRING_VIEW
 // Dont' add an inline namespace for `std::filesystem`
 #  define _LIBCPP_ABI_NO_FILESYSTEM_INLINE_NAMESPACE
+// Historically, libc++ used a type called `__compressed_pair` to reduce storage need in cases of empty types (e.g. an
+// empty allocator in std::vector). We switched to using `[[no_unique_address]]`. However, for ABI compatibility reasons
+// we had to add artificial padding in a few places.
+//
+// This setting disables the addition of such artificial padding, leading to a more optimal
+// representation for several types.
+#  define _LIBCPP_ABI_NO_COMPRESSED_PAIR_PADDING
 #elif _LIBCPP_ABI_VERSION == 1
 #  if !(defined(_LIBCPP_OBJECT_FORMAT_COFF) || defined(_LIBCPP_OBJECT_FORMAT_XCOFF))
 // Enable compiling copies of now inline methods into the dylib to support
diff --git a/libcxx/include/__functional/function.h b/libcxx/include/__functional/function.h
index c7b98035e34bf..b073af4f64ab5 100644
--- a/libcxx/include/__functional/function.h
+++ b/libcxx/include/__functional/function.h
@@ -143,45 +143,46 @@ class __default_alloc_func;
 
 template <class _Fp, class _Ap, class _Rp, class... _ArgTypes>
 class __alloc_func<_Fp, _Ap, _Rp(_ArgTypes...)> {
-  __compressed_pair<_Fp, _Ap> __f_;
+  _LIBCPP_COMPRESSED_PAIR(_Fp, __func_, _Ap, __alloc_);
 
 public:
   typedef _LIBCPP_NODEBUG _Fp _Target;
   typedef _LIBCPP_NODEBUG _Ap _Alloc;
 
-  _LIBCPP_HIDE_FROM_ABI const _Target& __target() const { return __f_.first(); }
+  _LIBCPP_HIDE_FROM_ABI const _Target& __target() const { return __func_; }
 
   // WIN32 APIs may define __allocator, so use __get_allocator instead.
-  _LIBCPP_HIDE_FROM_ABI const _Alloc& __get_allocator() const { return __f_.second(); }
+  _LIBCPP_HIDE_FROM_ABI const _Alloc& __get_allocator() const { return __alloc_; }
 
-  _LIBCPP_HIDE_FROM_ABI explicit __alloc_func(_Target&& __f)
-      : __f_(piecewise_construct, std::forward_as_tuple(std::move(__f)), std::forward_as_tuple()) {}
+  _LIBCPP_HIDE_FROM_ABI explicit __alloc_func(_Target&& __f) : __func_(std::move(__f)), __alloc_() {}
 
-  _LIBCPP_HIDE_FROM_ABI explicit __alloc_func(const _Target& __f, const _Alloc& __a)
-      : __f_(piecewise_construct, std::forward_as_tuple(__f), std::forward_as_tuple(__a)) {}
+  _LIBCPP_HIDE_FROM_ABI explicit __alloc_func(const _Target& __f, const _Alloc& __a) : __func_(__f), __alloc_(__a) {}
 
   _LIBCPP_HIDE_FROM_ABI explicit __alloc_func(const _Target& __f, _Alloc&& __a)
-      : __f_(piecewise_construct, std::forward_as_tuple(__f), std::forward_as_tuple(std::move(__a))) {}
+      : __func_(__f), __alloc_(std::move(__a)) {}
 
   _LIBCPP_HIDE_FROM_ABI explicit __alloc_func(_Target&& __f, _Alloc&& __a)
-      : __f_(piecewise_construct, std::forward_as_tuple(std::move(__f)), std::forward_as_tuple(std::move(__a))) {}
+      : __func_(std::move(__f)), __alloc_(std::move(__a)) {}
 
   _LIBCPP_HIDE_FROM_ABI _Rp operator()(_ArgTypes&&... __arg) {
     typedef __invoke_void_return_wrapper<_Rp> _Invoker;
-    return _Invoker::__call(__f_.first(), std::forward<_ArgTypes>(__arg)...);
+    return _Invoker::__call(__func_, std::forward<_ArgTypes>(__arg)...);
   }
 
   _LIBCPP_HIDE_FROM_ABI __alloc_func* __clone() const {
     typedef allocator_traits<_Alloc> __alloc_traits;
     typedef __rebind_alloc<__alloc_traits, __alloc_func> _AA;
-    _AA __a(__f_.second());
+    _AA __a(__alloc_);
     typedef __allocator_destructor<_AA> _Dp;
     unique_ptr<__alloc_func, _Dp> __hold(__a.allocate(1), _Dp(__a, 1));
-    ::new ((void*)__hold.get()) __alloc_func(__f_.first(), _Alloc(__a));
+    ::new ((void*)__hold.get()) __alloc_func(__func_, _Alloc(__a));
     return __hold.release();
   }
 
-  _LIBCPP_HIDE_FROM_ABI void destroy() _NOEXCEPT { __f_.~__compressed_pair<_Target, _Alloc>(); }
+  _LIBCPP_HIDE_FROM_ABI void destroy() _NOEXCEPT {
+    __func_.~_Fp();
+    __alloc_.~_Alloc();
+  }
 
   _LIBCPP_HIDE_FROM_ABI static void __destroy_and_delete(__alloc_func* __f) {
     typedef allocator_traits<_Alloc> __alloc_traits;
diff --git a/libcxx/include/__hash_table b/libcxx/include/__hash_table
index 025758528573f..10a7ceec6c412 100644
--- a/libcxx/include/__hash_table
+++ b/libcxx/include/__hash_table
@@ -554,29 +554,29 @@ class __bucket_list_deallocator {
   typedef allocator_traits<allocator_type> __alloc_traits;
   typedef typename __alloc_traits::size_type size_type;
 
-  __compressed_pair<size_type, allocator_type> __data_;
+  _LIBCPP_COMPRESSED_PAIR(size_type, __size_, allocator_type, __alloc_);
 
 public:
   typedef typename __alloc_traits::pointer pointer;
 
   _LIBCPP_HIDE_FROM_ABI __bucket_list_deallocator() _NOEXCEPT_(is_nothrow_default_constructible<allocator_type>::value)
-      : __data_(0, __default_init_tag()) {}
+      : __size_(0) {}
 
   _LIBCPP_HIDE_FROM_ABI __bucket_list_deallocator(const allocator_type& __a, size_type __size)
       _NOEXCEPT_(is_nothrow_copy_constructible<allocator_type>::value)
-      : __data_(__size, __a) {}
+      : __size_(__size), __alloc_(__a) {}
 
   _LIBCPP_HIDE_FROM_ABI __bucket_list_deallocator(__bucket_list_deallocator&& __x)
       _NOEXCEPT_(is_nothrow_move_constructible<allocator_type>::value)
-      : __data_(std::move(__x.__data_)) {
+      : __size_(std::move(__x.__size_)), __alloc_(std::move(__x.__alloc_)) {
     __x.size() = 0;
   }
 
-  _LIBCPP_HIDE_FROM_ABI size_type& size() _NOEXCEPT { return __data_.first(); }
-  _LIBCPP_HIDE_FROM_ABI size_type size() const _NOEXCEPT { return __data_.first(); }
+  _LIBCPP_HIDE_FROM_ABI size_type& size() _NOEXCEPT { return __size_; }
+  _LIBCPP_HIDE_FROM_ABI size_type size() const _NOEXCEPT { return __size_; }
 
-  _LIBCPP_HIDE_FROM_ABI allocator_type& __alloc() _NOEXCEPT { return __data_.second(); }
-  _LIBCPP_HIDE_FROM_ABI const allocator_type& __alloc() const _NOEXCEPT { return __data_.second(); }
+  _LIBCPP_HIDE_FROM_ABI allocator_type& __alloc() _NOEXCEPT { return __alloc_; }
+  _LIBCPP_HIDE_FROM_ABI const allocator_type& __alloc() const _NOEXCEPT { return __alloc_; }
 
   _LIBCPP_HIDE_FROM_ABI void operator()(pointer __p) _NOEXCEPT { __alloc_traits::deallocate(__alloc(), __p, size()); }
 };
@@ -716,27 +716,27 @@ private:
 
   // --- Member data begin ---
   __bucket_list __bucket_list_;
-  __compressed_pair<__first_node, __node_allocator> __p1_;
-  __compressed_pair<size_type, hasher> __p2_;
-  __compressed_pair<float, key_equal> __p3_;
+  _LIBCPP_COMPRESSED_PAIR(__first_node, __first_node_, __node_allocator, __node_alloc_);
+  _LIBCPP_COMPRESSED_PAIR(size_type, __size_, hasher, __hasher_);
+  _LIBCPP_COMPRESSED_PAIR(float, __max_load_factor_, key_equal, __key_eq_);
   // --- Member data end ---
 
-  _LIBCPP_HIDE_FROM_ABI size_type& size() _NOEXCEPT { return __p2_.first(); }
+  _LIBCPP_HIDE_FROM_ABI size_type& size() _NOEXCEPT { return __size_; }
 
 public:
-  _LIBCPP_HIDE_FROM_ABI size_type size() const _NOEXCEPT { return __p2_.first(); }
+  _LIBCPP_HIDE_FROM_ABI size_type size() const _NOEXCEPT { return __size_; }
 
-  _LIBCPP_HIDE_FROM_ABI hasher& hash_function() _NOEXCEPT { return __p2_.second(); }
-  _LIBCPP_HIDE_FROM_ABI const hasher& hash_function() const _NOEXCEPT { return __p2_.second(); }
+  _LIBCPP_HIDE_FROM_ABI hasher& hash_function() _NOEXCEPT { return __hasher_; }
+  _LIBCPP_HIDE_FROM_ABI const hasher& hash_function() const _NOEXCEPT { return __hasher_; }
 
-  _LIBCPP_HIDE_FROM_ABI float& max_load_factor() _NOEXCEPT { return __p3_.first(); }
-  _LIBCPP_HIDE_FROM_ABI float max_load_factor() const _NOEXCEPT { return __p3_.first(); }
+  _LIBCPP_HIDE_FROM_ABI float& max_load_factor() _NOEXCEPT { return __max_load_factor_; }
+  _LIBCPP_HIDE_FROM_ABI float max_load_factor() const _NOEXCEPT { return __max_load_factor_; }
 
-  _LIBCPP_HIDE_FROM_ABI key_equal& key_eq() _NOEXCEPT { return __p3_.second(); }
-  _LIBCPP_HIDE_FROM_ABI const key_equal& key_eq() const _NOEXCEPT { return __p3_.second(); }
+  _LIBCPP_HIDE_FROM_ABI key_equal& key_eq() _NOEXCEPT { return __key_eq_; }
+  _LIBCPP_HIDE_FROM_ABI const key_equal& key_eq() const _NOEXCEPT { return __key_eq_; }
 
-  _LIBCPP_HIDE_FROM_ABI __node_allocator& __node_alloc() _NOEXCEPT { return __p1_.second(); }
-  _LIBCPP_HIDE_FROM_ABI const __node_allocator& __node_alloc() const _NOEXCEPT { return __p1_.second(); }
+  _LIBCPP_HIDE_FROM_ABI __node_allocator& __node_alloc() _NOEXCEPT { return __node_alloc_; }
+  _LIBCPP_HIDE_FROM_ABI const __node_allocator& __node_alloc() const _NOEXCEPT { return __node_alloc_; }
 
 public:
   typedef __hash_iterator<__node_pointer> iterator;
@@ -1022,26 +1022,34 @@ inline __hash_table<_Tp, _Hash, _Equal, _Alloc>::__hash_table() _NOEXCEPT_(
     is_nothrow_default_constructible<__bucket_list>::value&& is_nothrow_default_constructible<__first_node>::value&&
         is_nothrow_default_constructible<__node_allocator>::value&& is_nothrow_default_constructible<hasher>::value&&
             is_nothrow_default_constructible<key_equal>::value)
-    : __p2_(0, __default_init_tag()), __p3_(1.0f, __default_init_tag()) {}
+    : __size_(0), __max_load_factor_(1.0f) {}
 
 template <class _Tp, class _Hash, class _Equal, class _Alloc>
 inline __hash_table<_Tp, _Hash, _Equal, _Alloc>::__hash_table(const hasher& __hf, const key_equal& __eql)
-    : __bucket_list_(nullptr, __bucket_list_deleter()), __p1_(), __p2_(0, __hf), __p3_(1.0f, __eql) {}
+    : __bucket_list_(nullptr, __bucket_list_deleter()),
+      __first_node_(),
+      __node_alloc_(),
+      __size_(0),
+      __hasher_(__hf),
+      __max_load_factor_(1.0f),
+      __key_eq_(__eql) {}
 
 template <class _Tp, class _Hash, class _Equal, class _Alloc>
 __hash_table<_Tp, _Hash, _Equal, _Alloc>::__hash_table(
     const hasher& __hf, const key_equal& __eql, const allocator_type& __a)
     : __bucket_list_(nullptr, __bucket_list_deleter(__pointer_allocator(__a), 0)),
-      __p1_(__default_init_tag(), __node_allocator(__a)),
-      __p2_(0, __hf),
-      __p3_(1.0f, __eql) {}
+      __node_alloc_(__node_allocator(__a)),
+      __size_(0),
+      __hasher_(__hf),
+      __max_load_factor_(1.0f),
+      __key_eq_(__eql) {}
 
 template <class _Tp, class _Hash, class _Equal, class _Alloc>
 __hash_table<_Tp, _Hash, _Equal, _Alloc>::__hash_table(const allocator_type& __a)
     : __bucket_list_(nullptr, __bucket_list_deleter(__pointer_allocator(__a), 0)),
-      __p1_(__default_init_tag(), __node_allocator(__a)),
-      __p2_(0, __default_init_tag()),
-      __p3_(1.0f, __default_init_tag()) {}
+      __node_alloc_(__node_allocator(__a)),
+      __size_(0),
+      __max_load_factor_(1.0f) {}
 
 template <class _Tp, class _Hash, class _Equal, class _Alloc>
 __hash_table<_Tp, _Hash, _Equal, _Alloc>::__hash_table(const __hash_table& __u)
@@ -1049,17 +1057,20 @@ __hash_table<_Tp, _Hash, _Equal, _Alloc>::__hash_table(const __hash_table& __u)
                      __bucket_list_deleter(allocator_traits<__pointer_allocator>::select_on_container_copy_construction(
                                                __u.__bucket_list_.get_deleter().__alloc()),
                                            0)),
-      __p1_(__default_init_tag(),
-            allocator_traits<__node_allocator>::select_on_container_copy_construction(__u.__node_alloc())),
-      __p2_(0, __u.hash_function()),
-      __p3_(__u.__p3_) {}
+      __node_alloc_(allocator_traits<__node_allocator>::select_on_container_copy_construction(__u.__node_alloc())),
+      __size_(0),
+      __hasher_(__u.hash_function()),
+      __max_load_factor_(__u.__max_load_factor_),
+      __key_eq_(__u.__key_eq_) {}
 
 template <class _Tp, class _Hash, class _Equal, class _Alloc>
 __hash_table<_Tp, _Hash, _Equal, _Alloc>::__hash_table(const __hash_table& __u, const allocator_type& __a)
     : __bucket_list_(nullptr, __bucket_list_deleter(__pointer_allocator(__a), 0)),
-      __p1_(__default_init_tag(), __node_allocator(__a)),
-      __p2_(0, __u.hash_function()),
-      __p3_(__u.__p3_) {}
+      __node_alloc_(__node_allocator(__a)),
+      __size_(0),
+      __hasher_(__u.hash_function()),
+      __max_load_factor_(__u.__max_load_factor_),
+      __key_eq_(__u.__key_eq_) {}
 
 template <class _Tp, class _Hash, class _Equal, class _Alloc>
 __hash_table<_Tp, _Hash, _Equal, _Alloc>::__hash_table(__hash_table&& __u) _NOEXCEPT_(
@@ -1067,12 +1078,15 @@ __hash_table<_Tp, _Hash, _Equal, _Alloc>::__hash_table(__hash_table&& __u) _NOEX
         is_nothrow_move_constructible<__node_allocator>::value&& is_nothrow_move_constructible<hasher>::value&&
             is_nothrow_move_constructible<key_equal>::value)
     : __bucket_list_(std::move(__u.__bucket_list_)),
-      __p1_(std::move(__u.__p1_)),
-      __p2_(std::move(__u.__p2_)),
-      __p3_(std::move(__u.__p3_)) {
+      __first_node_(std::move(__u.__first_node_)),
+      __node_alloc_(std::move(__u.__node_alloc_)),
+      __size_(std::move(__u.__size_)),
+      __hasher_(std::move(__u.__hasher_)),
+      __max_load_factor_(__u.__max_load_factor_),
+      __key_eq_(std::move(__u.__key_eq_)) {
   if (size() > 0) {
-    __bucket_list_[std::__constrain_hash(__p1_.first().__next_->__hash(), bucket_count())] = __p1_.first().__ptr();
-    __u.__p1_.first().__next_                                                              = nullptr;
+    __bucket_list_[std::__constrain_hash(__first_node_.__next_->__hash(), bucket_count())] = __first_node_.__ptr();
+    __u.__first_node_.__next_                                                              = nullptr;
     __u.size()                                                                             = 0;
   }
 }
@@ -1080,17 +1094,19 @@ __hash_table<_Tp, _Hash, _Equal, _Alloc>::__hash_table(__hash_table&& __u) _NOEX
 template <class _Tp, class _Hash, class _Equal, class _Alloc>
 __hash_table<_Tp, _Hash, _Equal, _Alloc>::__hash_table(__hash_table&& __u, const allocator_type& __a)
     : __bucket_list_(nullptr, __bucket_list_deleter(__pointer_allocator(__a), 0)),
-      __p1_(__default_init_tag(), __node_allocator(__a)),
-      __p2_(0, std::move(__u.hash_function())),
-      __p3_(std::move(__u.__p3_)) {
+      __node_alloc_(__node_allocator(__a)),
+      __size_(0),
+      __hasher_(std::move(__u.__hasher_)),
+      __max_load_factor_(__u.__max_load_factor_),
+      __key_eq_(std::move(__u.__key_eq_)) {
   if (__a == allocator_type(__u.__node_alloc())) {
     __bucket_list_.reset(__u.__bucket_list_.release());
     __bucket_list_.get_deleter().size()     = __u.__bucket_list_.get_deleter().size();
     __u.__bucket_list_.get_deleter().size() = 0;
     if (__u.size() > 0) {
-      __p1_.first().__next_     = __u.__p1_.first().__next_;
-      __u.__p1_.first().__next_ = nullptr;
-      __bucket_list_[std::__constrain_hash(__p1_.first().__next_->__hash(), bucket_count())] = __p1_.first().__ptr();
+      __first_node_.__next_     = __u.__first_node_.__next_;
+      __u.__first_node_.__next_ = nullptr;
+      __bucket_list_[std::__constrain_hash(__first_node_.__next_->__hash(), bucket_count())] = __first_node_.__ptr();
       size()                                                                                 = __u.size();
       __u.size()                                                                             = 0;
     }
@@ -1104,7 +1120,7 @@ __hash_table<_Tp, _Hash, _Equal, _Alloc>::~__hash_table() {
   static_assert(is_copy_constructible<hasher>::value, "Hasher must be copy-constructible.");
 #endif
 
-  __deallocate_node(__p1_.first().__next_);
+  __deallocate_node(__first_node_.__next_);
 }
 
 template <class _Tp, class _Hash, class _Equal, class _Alloc>
@@ -1150,8 +1166,8 @@ __hash_table<_Tp, _Hash, _Equal, _Alloc>::__detach() _NOEXCEPT {
   for (size_type __i = 0; __i < __bc; ++__i)
     __bucket_list_[__i] = nullptr;
   size()                 = 0;
-  __next_pointer __cache = __p1_.first().__next_;
-  __p1_.first().__next_  = nullptr;
+  __next_pointer __cache = __first_node_.__next_;
+  __first_node_.__next_  = nullptr;
   return __cache;
 }
 
@@ -1168,10 +1184,10 @@ void __hash_table<_Tp, _Hash, _Equal, _Alloc>::__move_assign(__hash_table& __u,
   hash_function()       = std::move(__u.hash_function());
   max_load_factor()     = __u.max_load_factor();
   key_eq()              = std::move(__u.key_eq());
-  __p1_.first().__next_ = __u.__p1_.first().__next_;
+  __first_node_.__next_ = __u.__first_node_.__next_;
   if (size() > 0) {
-    __bucket_list_[std::__constrain_hash(__p1_.first().__next_->__hash(), bucket_count())] = __p1_.first().__ptr();
-    __u.__p1_.first().__next_                                                              = nullptr;
+    __bucket_list_[std::__constrain_hash(__first_node_.__next_->__hash(), bucket_count())] = __first_node_.__ptr();
+    __u.__first_node_.__next_                                                              = nullptr;
     __u.size()                                                                             = 0;
   }
 }
@@ -1288,7 +1304,7 @@ void __hash_table<_Tp, _Hash, _Equal, _Alloc>::__assign_multi(_InputIterator __f
 template <class _Tp, class _Hash, class _Equal, class _Alloc>
 inline typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::iterator
 __hash_table<_Tp, _Hash, _Equal, _Alloc>::begin() _NOEXCEPT {
-  return iterator(__p1_.first().__next_);
+  return iterator(__first_node_.__next_);
 }
 
 template <class _Tp, class _Hash, class _Equal, class _Alloc>
@@ -1300,7 +1316,7 @@ __hash_table<_Tp, _Hash, _Equal, _Alloc>::end() _NOEXCEPT {
 template <class _Tp, class _Hash, class _Equal, class _Alloc>
 inline typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::const_iterator
 __hash_table<_Tp, _Hash, _Equal, _Alloc>::begin() const _NOEXCEPT {
-  return const_iterator(__p1_.first().__next_);
+  return const_iterator(__first_node_.__next_);
 }
 
 template <class _Tp, class _Hash, class _Equal, class _Alloc>
@@ -1312,8 +1328,8 @@ __hash_table<_Tp, _Hash, _Equal, _Alloc>::end() const _NOEXCEPT {
 template <class _Tp, class _Hash, class _Equal, class _Alloc>
 void __hash_table<_Tp, _Hash, _Equal, _Alloc>::clear() _NOEXCEPT {
   if (size() > 0) {
-    __deallocate_node(__p1_.first().__next_);
-    __p1_.first().__next_ = nullptr;
+    __deallocate_node(__first_node_.__next_);
+    __first_node_.__next_ = nullptr;
     size_type __bc        = bucket_count();
     for (size_type __i = 0; __i < __bc; ++__i)
       __bucket_list_[__i] = nullptr;
@@ -1365,7 +1381,7 @@ __hash_table<_Tp, _Hash, _Equal, _Alloc>::__node_insert_unique_perform(__node_po
   // insert_after __bucket_list_[__chash], or __first_node if bucket is null
   __next_pointer __pn = __bucket_list_[__chash];
   if (__pn == nullptr) {
-    __pn          = __p1_.first().__ptr();
+    __pn          = __first_node_.__ptr();
     __nd->__next_ = __pn->__next_;
     __pn->__next_ = __nd->__ptr();
     // fix up __bucket_list_
@@ -1445,7 +1461,7 @@ void __hash_table<_Tp, _Hash, _Equal, _Alloc>::__node_insert_multi_perform(
   size_type __bc = bucket_count();
   size_t __chash = std::__constrain_hash(__cp->__hash_, __bc);
   if (__pn == nullptr) {
-    __pn          = __p1_.first().__ptr();
+    __pn          = __first_node_.__ptr();
     __cp->__next_ = __pn->__next_;
     __pn->__next_ = __cp->__ptr();
     // fix up __bucket_list_
@@ -1530,7 +1546,7 @@ __hash_table<_Tp, _Hash, _Equal, _Alloc>::__emplace_unique_key_args(_Key const&
     // insert_after __bucket_list_[__chash], or __first_node if bucket is null
     __next_pointer __pn = __bucket_list_[__chash];
     if (__pn == nullptr) {
-      __pn          = __p1_.first().__ptr();
+      __pn          = __first_node_.__ptr();
       __h->__next_  = __pn->__next_;
       __pn->__next_ = __h.get()->__ptr();
       // fix up __bucket_list_
@@ -1708,7 +1724,7 @@ void __hash_table<_Tp, _Hash, _Equal, _Alloc>::__do_rehash(size_type __nbc) {
   if (__nbc > 0) {
     for (size_type __i = 0; __i < __nbc; ++__i)
       __bucket_list_[__i] = nullptr;
-    __next_pointer __pp = __p1_.first().__ptr();
+    __next_pointer __pp = __first_node_.__ptr();
     __next_pointer __cp = __pp->__next_;
     if (__cp != nullptr) {
       size_type __chash       = std::__constrain_hash(__cp->__hash(), __nbc);
@@ -1885,7 +1901,7 @@ __hash_table<_Tp, _Hash, _Equal, _Alloc>::remove(const_iterator __p) _NOEXCEPT {
   // Fix up __bucket_list_
   // if __pn is not in same bucket (before begin is not in same bucket) &&
   //    if __cn->__next_ is not in same bucket (nullptr is not in same bucket)
-  if (__pn == __p1_.first().__ptr() || std::__constrain_hash(__pn->__hash(), __bc) != __chash) {
+  if (__pn == __first_node_.__ptr() || std::__constrain_hash(__pn->__hash(), __bc) != __chash) {
     if (__cn->__next_ == nullptr || std::__constrain_hash(__cn->__next_->__hash(), __bc) != __chash)
       __bucket_list_[__chash] = nullptr;
   }
@@ -2004,14 +2020,17 @@ void __hash_table<_Tp, _Hash, _Equal, _Alloc>::swap(__hash_table& __u)
   std::swap(__bucket_list_.get_deleter().size(), __u.__bucket_list_.get_deleter().size());
   std::__swap_allocator(__bucket_list_.get_deleter().__alloc(), __u.__bucket_list_.get_deleter().__alloc());
   std::__swap_allocator(__node_alloc(), __u.__node_alloc());
-  std::swap(__p1_.first().__next_, __u.__p1_.first().__next_);
-  __p2_.swap(__u.__p2_);
-  __p3_.swap(__u.__p3_);
+  std::swap(__first_node_.__next_, __u.__first_node_.__next_);
+  using std::swap;
+  swap(__size_, __u.__size_);
+  swap(__hasher_, __u.__hasher_);
+  swap(__max_load_factor_, __u.__max_load_factor_);
+  swap(__key_eq_, __u.__key_eq_);
   if (size() > 0)
-    __bucket_list_[std::__constrain_hash(__p1_.first().__next_->__hash(), bucket_count())] = __p1_.first().__ptr();
+    __bucket_list_[std::__constrain_hash(__first_node_.__next_->__hash(), bucket_count())] = __first_node_.__ptr();
   if (__u.size() > 0)
-    __u.__bucket_list_[std::__constrain_hash(__u.__p1_.first().__next_->__hash(), __u.bucket_count())] =
-        __u.__p1_.first().__ptr();
+    __u.__bucket_list_[std::__constrain_hash(__u.__first_node_.__next_->__hash(), __u.bucket_count())] =
+        __u.__first_node_.__ptr();
 }
 
 template <class _Tp, class _Hash, class _Equal, class _Alloc>
diff --git a/libcxx/include/__memory/compressed_pair.h b/libcxx/include/__memory/compressed_pair.h
index 40e5cfc35fb04..3a6947dab4b59 100644
--- a/libcxx/include/__memory/compressed_pair.h
+++ b/libcxx/include/__memory/compressed_pair.h
@@ -11,161 +11,79 @@
 #define _LIBCPP___MEMORY_COMPRESSED_PAIR_H
 
 #include <__config>
-#include <__fwd/tuple.h>
-#include <__tuple/tuple_indices.h>
-#include <__type_traits/decay.h>
-#include <__type_traits/dependent_type.h>
-#include <__type_traits/enable_if.h>
-#include <__type_traits/is_constructible.h>
+#include <__type_traits/datasizeof.h>
 #include <__type_traits/is_empty.h>
 #include <__type_traits/is_final.h>
-#include <__type_traits/is_same.h>
-#include <__type_traits/is_swappable.h>
-#include <__utility/forward.h>
-#include <__utility/move.h>
-#include <__utility/piecewise_construct.h>
-#include <cstddef>
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #  pragma GCC system_header
 #endif
 
-_LIBCPP_PUSH_MACROS
-#include <__undef_macros>
-
 _LIBCPP_BEGIN_NAMESPACE_STD
 
-// Tag used to default initialize one or both of the pair's elements.
-struct __default_init_tag {};
-struct __value_init_tag {};
-
-template <class _Tp, int _Idx, bool _CanBeEmptyBase = is_empty<_Tp>::value && !__libcpp_is_final<_Tp>::value>
-struct __compressed_pair_elem {
-  using _ParamT         = _Tp;
-  using reference       = _Tp&;
-  using const_reference = const _Tp&;
-
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR explicit __compressed_pair_elem(__default_init_tag) {}
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR explicit __compressed_pair_elem(__value_init_tag) : __value_() {}
-
-  template <class _Up, __enable_if_t<!is_same<__compressed_pair_elem, __decay_t<_Up> >::value, int> = 0>
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR explicit __compressed_pair_elem(_Up&& __u)
-      : __value_(std::forward<_Up>(__u)) {}
-
-#ifndef _LIBCPP_CXX03_LANG
-  template <class... _Args, size_t... _Indices>
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 explicit __compressed_pair_elem(
-      piecewise_construct_t, tuple<_Args...> __args, __tuple_indices<_Indices...>)
-      : __value_(std::forward<_Args>(std::get<_Indices>(__args))...) {}
-#endif
-
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 reference __get() _NOEXCEPT { return __value_; }
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR const_reference __get() const _NOEXCEPT { return __value_; }
-
-private:
-  _Tp __value_;
-};
-
-template <class _Tp, int _Idx>
-struct __compressed_pair_elem<_Tp, _Idx, true> : private _Tp {
-  using _ParamT         = _Tp;
-  using reference       = _Tp&;
-  using const_reference = const _Tp&;
-  using __value_type    = _Tp;
-
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR explicit __compressed_pair_elem() = default;
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR explicit __compressed_pair_elem(__default_init_tag) {}
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR explicit __compressed_pair_elem(__value_init_tag) : __value_type() {}
-
-  template <class _Up, __enable_if_t<!is_same<__compressed_pair_elem, __decay_t<_Up> >::value, int> = 0>
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR explicit __compressed_pair_elem(_Up&& __u)
-      : __value_type(std::forward<_Up>(__u)) {}
-
-#ifndef _LIBCPP_CXX03_LANG
-  template <class... _Args, size_t... _Indices>
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17
-  __compressed_pair_elem(piecewise_construct_t, tuple<_Args...> __args, __tuple_indices<_Indices...>)
-      : __value_type(std::forward<_Args>(std::get<_Indices>(__args))...) {}
-#endif
-
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 reference __get() _NOEXCEPT { return *this; }
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR const_reference __get() const _NOEXCEPT { return *this; }
-};
-
-template <class _T1, class _T2>
-class __compressed_pair : private __compressed_pair_elem<_T1, 0>, private __compressed_pair_elem<_T2, 1> {
-public:
-  // NOTE: This static assert should never fire because __compressed_pair
-  // is *almost never* used in a scenario where it's possible for T1 == T2.
-  // (The exception is std::function where it is possible that the function
-  //  object and the allocator have the same type).
-  static_assert(
-      (!is_same<_T1, _T2>::value),
-      "__compressed_pair cannot be instantiated when T1 and T2 are the same type; "
-      "The current implementation is NOT ABI-compatible with the previous implementation for this configuration");
-
-  using _Base1 _LIBCPP_NODEBUG = __compressed_pair_elem<_T1, 0>;
-  using _Base2 _LIBCPP_NODEBUG = __compressed_pair_elem<_T2, 1>;
-
-  template <bool _Dummy         = true,
-            __enable_if_t< __dependent_type<is_default_constructible<_T1>, _Dummy>::value &&
-                               __dependent_type<is_default_constructible<_T2>, _Dummy>::value,
-                           int> = 0>
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR explicit __compressed_pair()
-      : _Base1(__value_init_tag()), _Base2(__value_init_tag()) {}
-
-  template <class _U1, class _U2>
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR explicit __compressed_pair(_U1&& __t1, _U2&& __t2)
-      : _Base1(std::forward<_U1>(__t1)), _Base2(std::forward<_U2>(__t2)) {}
-
-#ifndef _LIBCPP_CXX03_LANG
-  template <class... _Args1, class... _Args2>
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 explicit __compressed_pair(
-      piecewise_construct_t __pc, tuple<_Args1...> __first_args, tuple<_Args2...> __second_args)
-      : _Base1(__pc, std::move(__first_args), typename __make_tuple_indices<sizeof...(_Args1)>::type()),
-        _Base2(__pc, std::move(__second_args), typename __make_tuple_indices<sizeof...(_Args2)>::type()) {}
-#endif
-
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 typename _Base1::reference first() _NOEXCEPT {
-    return static_cast<_Base1&>(*this).__get();
-  }
+#ifndef _LIBCPP_ABI_NO_COMPRESSED_PAIR_PADDING
 
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR typename _Base1::const_reference first() const _NOEXCEPT {
-    return static_cast<_Base1 const&>(*this).__get();
-  }
+// ================================================================================================================== //
+// The utilites here are for staying ABI compatible with the legacy `__compressed_pair`. They should not be used      //
+// for new data structures. Use `_LIBCPP_NO_UNIQUE_ADDRESS` for new data structures instead (but make sure you        //
+// understand how it works).                                                                                          //
+// ================================================================================================================== //
 
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 typename _Base2::reference second() _NOEXCEPT {
-    return static_cast<_Base2&>(*this).__get();
-  }
-
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR typename _Base2::const_reference second() const _NOEXCEPT {
-    return static_cast<_Base2 const&>(*this).__get();
-  }
-
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR static _Base1* __get_first_base(__compressed_pair* __pair) _NOEXCEPT {
-    return static_cast<_Base1*>(__pair);
-  }
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR static _Base2* __get_second_base(__compressed_pair* __pair) _NOEXCEPT {
-    return static_cast<_Base2*>(__pair);
-  }
-
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 void swap(__compressed_pair& __x)
-      _NOEXCEPT_(__is_nothrow_swappable_v<_T1>&& __is_nothrow_swappable_v<_T2>) {
-    using std::swap;
-    swap(first(), __x.first());
-    swap(second(), __x.second());
-  }
+// The first member is aligned to the alignment of the second member to force padding in front of the compressed pair
+// in case there are members before it.
+//
+// For example:
+// (assuming x86-64 linux)
+// class SomeClass {
+//   uint32_t member1;
+//   _LIBCPP_COMPRESSED_PAIR(uint32_t, member2, uint64_t, member3);
+// }
+//
+// The layout with __compressed_pair is:
+// member1 - offset: 0,  size: 4
+// padding - offset: 4,  size: 4
+// member2 - offset: 8,  size: 4
+// padding - offset: 12, size: 4
+// member3 - offset: 16, size: 8
+//
+// If the [[gnu::aligned]] wasn't there, the layout would instead be:
+// member1 - offset: 0, size: 4
+// member2 - offset: 4, size: 4
+// member3 - offset: 8, size: 8
+
+template <class _ToPad>
+class __compressed_pair_padding {
+  char __padding_[(is_empty<_ToPad>::value && !__libcpp_is_final<_ToPad>::value)
+                      ? 0
+                      : sizeof(_ToPad) - __datasizeof_v<_ToPad>];
 };
 
-template <class _T1, class _T2>
-inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 void
-swap(__compressed_pair<_T1, _T2>& __x, __compressed_pair<_T1, _T2>& __y)
-    _NOEXCEPT_(__is_nothrow_swappable_v<_T1>&& __is_nothrow_swappable_v<_T2>) {
-  __x.swap(__y);
-}
+#  define _LIBCPP_COMPRESSED_PAIR(T1, Initializer1, T2, Initializer2)                                                  \
+    [[__gnu__::__aligned__(_LIBCPP_ALIGNOF(T2))]] _LIBCPP_NO_UNIQUE_ADDRESS T1 Initializer1;                           \
+    _LIBCPP_NO_UNIQUE_ADDRESS __compressed_pair_padding<T1> _LIBCPP_CONCAT3(__padding1_, __LINE__, _);                 \
+    _LIBCPP_NO_UNIQUE_ADDRESS T2 Initializer2;                                                                         \
+    _LIBCPP_NO_UNIQUE_ADDRESS __compressed_pair_padding<T2> _LIBCPP_CONCAT3(__padding2_, __LINE__, _)
+
+#  define _LIBCPP_COMPRESSED_TRIPLE(T1, Initializer1, T2, Initializer2, T3, Initializer3)                              \
+    [[using __gnu__: __aligned__(_LIBCPP_ALIGNOF(T2)), __aligned__(_LIBCPP_ALIGNOF(T3))]]                              \
+    _LIBCPP_NO_UNIQUE_ADDRESS T1 Initializer1;                                                                         \
+    _LIBCPP_NO_UNIQUE_ADDRESS __compressed_pair_padding<T1> _LIBCPP_CONCAT3(__padding1_, __LINE__, _);                 \
+    _LIBCPP_NO_UNIQUE_ADDRESS T2 Initializer2;                                                                         \
+    _LIBCPP_NO_UNIQUE_ADDRESS __compressed_pair_padding<T2> _LIBCPP_CONCAT3(__padding2_, __LINE__, _);                 \
+    _LIBCPP_NO_UNIQUE_ADDRESS T3 Initializer3;                                                                         \
+    _LIBCPP_NO_UNIQUE_ADDRESS __compressed_pair_padding<T3> _LIBCPP_CONCAT3(__padding3_, __LINE__, _)
+
+#else
+#  define _LIBCPP_COMPRESSED_PAIR(T1, Name1, T2, Name2)                                                                \
+    _LIBCPP_NO_UNIQUE_ADDRESS T1 Name1;                                                                                \
+    _LIBCPP_NO_UNIQUE_ADDRESS T2 Name2
+
+#  define _LIBCPP_COMPRESSED_TRIPLE(T1, Name1, T2, Name2, T3, Name3)                                                   \
+    _LIBCPP_NO_UNIQUE_ADDRESS T1 Name1;                                                                                \
+    _LIBCPP_NO_UNIQUE_ADDRESS T2 Name2;                                                                                \
+    _LIBCPP_NO_UNIQUE_ADDRESS T3 Name3
+#endif // _LIBCPP_ABI_NO_COMPRESSED_PAIR_PADDING
 
 _LIBCPP_END_NAMESPACE_STD
 
-_LIBCPP_POP_MACROS
-
 #endif // _LIBCPP___MEMORY_COMPRESSED_PAIR_H
diff --git a/libcxx/include/__memory/shared_ptr.h b/libcxx/include/__memory/shared_ptr.h
index 358a851958db1..c5362ce42b752 100644
--- a/libcxx/include/__memory/shared_ptr.h
+++ b/libcxx/include/__memory/shared_ptr.h
@@ -198,11 +198,11 @@ class _LIBCPP_EXPORTED_FROM_ABI __shared_weak_count : private __shared_count {
 
 template <class _Tp, class _Dp, class _Alloc>
 class __shared_ptr_pointer : public __shared_weak_count {
-  __compressed_pair<__compressed_pair<_Tp, _Dp>, _Alloc> __data_;
+  _LIBCPP_COMPRESSED_TRIPLE(_Tp, __ptr_, _Dp, __deleter_, _Alloc, __alloc_);
 
 public:
   _LIBCPP_HIDE_FROM_ABI __shared_ptr_pointer(_Tp __p, _Dp __d, _Alloc __a)
-      : __data_(__compressed_pair<_Tp, _Dp>(__p, std::move(__d)), std::move(__a)) {}
+      : __ptr_(__p), __deleter_(std::move(__d)), __alloc_(std::move(__a)) {}
 
 #ifndef _LIBCPP_HAS_NO_RTTI
   _LIBCPP_HIDE_FROM_ABI_VIRTUAL const void* __get_deleter(const type_info&) const _NOEXCEPT override;
@@ -217,15 +217,15 @@ class __shared_ptr_pointer : public __shared_weak_count {
 
 template <class _Tp, class _Dp, class _Alloc>
 const void* __shared_ptr_pointer<_Tp, _Dp, _Alloc>::__get_deleter(const type_info& __t) const _NOEXCEPT {
-  return __t == typeid(_Dp) ? std::addressof(__data_.first().second()) : nullptr;
+  return __t == typeid(_Dp) ? std::addressof(__deleter_) : nullptr;
 }
 
 #endif // _LIBCPP_HAS_NO_RTTI
 
 template <class _Tp, class _Dp, class _Alloc>
 void __shared_ptr_pointer<_Tp, _Dp, _Alloc>::__on_zero_shared() _NOEXCEPT {
-  __data_.first().second()(__data_.first().first());
-  __data_.first().second().~_Dp();
+  __deleter_(__ptr_);
+  __deleter_.~_Dp();
 }
 
 template <class _Tp, class _Dp, class _Alloc>
@@ -234,8 +234,8 @@ void __shared_ptr_pointer<_Tp, _Dp, _Alloc>::__on_zero_shared_weak() _NOEXCEPT {
   typedef allocator_traits<_Al> _ATraits;
   typedef pointer_traits<typename _ATraits::pointer> _PTraits;
 
-  _Al __a(__data_.second());
-  __data_.second().~_Alloc();
+  _Al __a(__alloc_);
+  __alloc_.~_Alloc();
   __a.deallocate(_PTraits::pointer_to(*this), 1);
 }
 
@@ -293,36 +293,28 @@ struct __shared_ptr_emplace : __shared_weak_count {
     allocator_traits<_ControlBlockAlloc>::deallocate(__tmp, pointer_traits<_ControlBlockPointer>::pointer_to(*this), 1);
   }
 
+  // TODO: It should be possible to refactor this to remove `_Storage` entirely.
   // This class implements the control block for non-array shared pointers created
   // through `std::allocate_shared` and `std::make_shared`.
-  //
-  // In previous versions of the library, we used a compressed pair to store
-  // both the _Alloc and the _Tp. This implies using EBO, which is incompatible
-  // with Allocator construction for _Tp. To allow implementing P0674 in C++20,
-  // we now use a properly aligned char buffer while making sure that we maintain
-  // the same layout that we had when we used a compressed pair.
-  using _CompressedPair = __compressed_pair<_Alloc, _Tp>;
-  struct _ALIGNAS_TYPE(_CompressedPair) _Storage {
-    char __blob_[sizeof(_CompressedPair)];
+  struct _Storage {
+    struct _Data {
+      _LIBCPP_COMPRESSED_PAIR(_Alloc, __alloc_, _Tp, __elem_);
+    };
+
+    _ALIGNAS_TYPE(_Data) char __buffer_[sizeof(_Data)];
 
     _LIBCPP_HIDE_FROM_ABI explicit _Storage(_Alloc&& __a) { ::new ((void*)__get_alloc()) _Alloc(std::move(__a)); }
     _LIBCPP_HIDE_FROM_ABI ~_Storage() { __get_alloc()->~_Alloc(); }
+
     _LIBCPP_HIDE_FROM_ABI _Alloc* __get_alloc() _NOEXCEPT {
-      _CompressedPair* __as_pair                = reinterpret_cast<_CompressedPair*>(__blob_);
-      typename _CompressedPair::_Base1* __first = _CompressedPair::__get_first_base(__as_pair);
-      _Alloc* __alloc                           = reinterpret_cast<_Alloc*>(__first);
-      return __alloc;
+      return std::addressof(reinterpret_cast<_Data*>(__buffer_)->__alloc_);
     }
+
     _LIBCPP_HIDE_FROM_ABI _LIBCPP_NO_CFI _Tp* __get_elem() _NOEXCEPT {
-      _CompressedPair* __as_pair                 = reinterpret_cast<_CompressedPair*>(__blob_);
-      typename _CompressedPair::_Base2* __second = _CompressedPair::__get_second_base(__as_pair);
-      _Tp* __elem                                = reinterpret_cast<_Tp*>(__second);
-      return __elem;
+      return std::addressof(reinterpret_cast<_Data*>(__buffer_)->__elem_);
     }
   };
 
-  static_assert(_LIBCPP_ALIGNOF(_Storage) == _LIBCPP_ALIGNOF(_CompressedPair), "");
-  static_assert(sizeof(_Storage) == sizeof(_CompressedPair), "");
   _Storage __storage_;
 };
 
diff --git a/libcxx/include/__memory/unique_ptr.h b/libcxx/include/__memory/unique_ptr.h
index 9519e4283868b..76cdcd83c2c5d 100644
--- a/libcxx/include/__memory/unique_ptr.h
+++ b/libcxx/include/__memory/unique_ptr.h
@@ -142,7 +142,7 @@ class _LIBCPP_UNIQUE_PTR_TRIVIAL_ABI _LIBCPP_TEMPLATE_VIS unique_ptr {
       void>;
 
 private:
-  __compressed_pair<pointer, deleter_type> __ptr_;
+  _LIBCPP_COMPRESSED_PAIR(pointer, __ptr_, deleter_type, __deleter_);
 
   typedef _LIBCPP_NODEBUG __unique_ptr_deleter_sfinae<_Dp> _DeleterSFINAE;
 
@@ -176,23 +176,25 @@ class _LIBCPP_UNIQUE_PTR_TRIVIAL_ABI _LIBCPP_TEMPLATE_VIS unique_ptr {
 
 public:
   template <bool _Dummy = true, class = _EnableIfDeleterDefaultConstructible<_Dummy> >
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR unique_ptr() _NOEXCEPT : __ptr_(__value_init_tag(), __value_init_tag()) {}
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR unique_ptr() _NOEXCEPT : __ptr_(), __deleter_() {}
 
   template <bool _Dummy = true, class = _EnableIfDeleterDefaultConstructible<_Dummy> >
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR unique_ptr(nullptr_t) _NOEXCEPT
-      : __ptr_(__value_init_tag(), __value_init_tag()) {}
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR unique_ptr(nullptr_t) _NOEXCEPT : __ptr_(), __deleter_() {}
 
   template <bool _Dummy = true, class = _EnableIfDeleterDefaultConstructible<_Dummy> >
-  _LIBCPP_HIDE_FROM_ABI
-  _LIBCPP_CONSTEXPR_SINCE_CXX23 explicit unique_ptr(pointer __p) _NOEXCEPT : __ptr_(__p, __value_init_tag()) {}
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 explicit unique_ptr(pointer __p) _NOEXCEPT
+      : __ptr_(__p),
+        __deleter_() {}
 
   template <bool _Dummy = true, class = _EnableIfDeleterConstructible<_LValRefType<_Dummy> > >
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unique_ptr(pointer __p, _LValRefType<_Dummy> __d) _NOEXCEPT
-      : __ptr_(__p, __d) {}
+      : __ptr_(__p),
+        __deleter_(__d) {}
 
   template <bool _Dummy = true, class = _EnableIfDeleterConstructible<_GoodRValRefType<_Dummy> > >
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unique_ptr(pointer __p, _GoodRValRefType<_Dummy> __d) _NOEXCEPT
-      : __ptr_(__p, std::move(__d)) {
+      : __ptr_(__p),
+        __deleter_(std::move(__d)) {
     static_assert(!is_reference<deleter_type>::value, "rvalue deleter bound to reference");
   }
 
@@ -200,24 +202,26 @@ class _LIBCPP_UNIQUE_PTR_TRIVIAL_ABI _LIBCPP_TEMPLATE_VIS unique_ptr {
   _LIBCPP_HIDE_FROM_ABI unique_ptr(pointer __p, _BadRValRefType<_Dummy> __d) = delete;
 
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unique_ptr(unique_ptr&& __u) _NOEXCEPT
-      : __ptr_(__u.release(), std::forward<deleter_type>(__u.get_deleter())) {}
+      : __ptr_(__u.release()),
+        __deleter_(std::forward<deleter_type>(__u.get_deleter())) {}
 
   template <class _Up,
             class _Ep,
             class = _EnableIfMoveConvertible<unique_ptr<_Up, _Ep>, _Up>,
             class = _EnableIfDeleterConvertible<_Ep> >
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unique_ptr(unique_ptr<_Up, _Ep>&& __u) _NOEXCEPT
-      : __ptr_(__u.release(), std::forward<_Ep>(__u.get_deleter())) {}
+      : __ptr_(__u.release()),
+        __deleter_(std::forward<_Ep>(__u.get_deleter())) {}
 
 #if _LIBCPP_STD_VER <= 14 || defined(_LIBCPP_ENABLE_CXX17_REMOVED_AUTO_PTR)
   template <class _Up,
             __enable_if_t<is_convertible<_Up*, _Tp*>::value && is_same<_Dp, default_delete<_Tp> >::value, int> = 0>
-  _LIBCPP_HIDE_FROM_ABI unique_ptr(auto_ptr<_Up>&& __p) _NOEXCEPT : __ptr_(__p.release(), __value_init_tag()) {}
+  _LIBCPP_HIDE_FROM_ABI unique_ptr(auto_ptr<_Up>&& __p) _NOEXCEPT : __ptr_(__p.release()), __deleter_() {}
 #endif
 
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unique_ptr& operator=(unique_ptr&& __u) _NOEXCEPT {
     reset(__u.release());
-    __ptr_.second() = std::forward<deleter_type>(__u.get_deleter());
+    __deleter_ = std::forward<deleter_type>(__u.get_deleter());
     return *this;
   }
 
@@ -227,7 +231,7 @@ class _LIBCPP_UNIQUE_PTR_TRIVIAL_ABI _LIBCPP_TEMPLATE_VIS unique_ptr {
             class = _EnableIfDeleterAssignable<_Ep> >
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unique_ptr& operator=(unique_ptr<_Up, _Ep>&& __u) _NOEXCEPT {
     reset(__u.release());
-    __ptr_.second() = std::forward<_Ep>(__u.get_deleter());
+    __deleter_ = std::forward<_Ep>(__u.get_deleter());
     return *this;
   }
 
@@ -253,32 +257,36 @@ class _LIBCPP_UNIQUE_PTR_TRIVIAL_ABI _LIBCPP_TEMPLATE_VIS unique_ptr {
   }
 
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 __add_lvalue_reference_t<_Tp> operator*() const {
-    return *__ptr_.first();
+    return *__ptr_;
   }
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 pointer operator->() const _NOEXCEPT { return __ptr_.first(); }
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 pointer get() const _NOEXCEPT { return __ptr_.first(); }
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 deleter_type& get_deleter() _NOEXCEPT { return __ptr_.second(); }
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 pointer operator->() const _NOEXCEPT { return __ptr_; }
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 pointer get() const _NOEXCEPT { return __ptr_; }
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 deleter_type& get_deleter() _NOEXCEPT { return __deleter_; }
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 const deleter_type& get_deleter() const _NOEXCEPT {
-    return __ptr_.second();
+    return __deleter_;
   }
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 explicit operator bool() const _NOEXCEPT {
-    return __ptr_.first() != nullptr;
+    return __ptr_ != nullptr;
   }
 
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 pointer release() _NOEXCEPT {
-    pointer __t    = __ptr_.first();
-    __ptr_.first() = pointer();
+    pointer __t = __ptr_;
+    __ptr_      = pointer();
     return __t;
   }
 
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 void reset(pointer __p = pointer()) _NOEXCEPT {
-    pointer __tmp  = __ptr_.first();
-    __ptr_.first() = __p;
+    pointer __tmp = __ptr_;
+    __ptr_        = __p;
     if (__tmp)
-      __ptr_.second()(__tmp);
+      __deleter_(__tmp);
   }
 
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 void swap(unique_ptr& __u) _NOEXCEPT { __ptr_.swap(__u.__ptr_); }
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 void swap(unique_ptr& __u) _NOEXCEPT {
+    using std::swap;
+    swap(__ptr_, __u.__ptr_);
+    swap(__deleter_, __u.__deleter_);
+  }
 };
 
 template <class _Tp, class _Dp>
@@ -300,7 +308,7 @@ class _LIBCPP_UNIQUE_PTR_TRIVIAL_ABI _LIBCPP_TEMPLATE_VIS unique_ptr<_Tp[], _Dp>
       void>;
 
 private:
-  __compressed_pair<pointer, deleter_type> __ptr_;
+  _LIBCPP_COMPRESSED_PAIR(pointer, __ptr_, deleter_type, __deleter_);
 
   template <class _From>
   struct _CheckArrayPointerConversion : is_same<_From, pointer> {};
@@ -349,42 +357,46 @@ class _LIBCPP_UNIQUE_PTR_TRIVIAL_ABI _LIBCPP_TEMPLATE_VIS unique_ptr<_Tp[], _Dp>
 
 public:
   template <bool _Dummy = true, class = _EnableIfDeleterDefaultConstructible<_Dummy> >
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR unique_ptr() _NOEXCEPT : __ptr_(__value_init_tag(), __value_init_tag()) {}
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR unique_ptr() _NOEXCEPT : __ptr_(), __deleter_() {}
 
   template <bool _Dummy = true, class = _EnableIfDeleterDefaultConstructible<_Dummy> >
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR unique_ptr(nullptr_t) _NOEXCEPT
-      : __ptr_(__value_init_tag(), __value_init_tag()) {}
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR unique_ptr(nullptr_t) _NOEXCEPT : __ptr_(), __deleter_() {}
 
   template <class _Pp,
             bool _Dummy = true,
             class       = _EnableIfDeleterDefaultConstructible<_Dummy>,
             class       = _EnableIfPointerConvertible<_Pp> >
-  _LIBCPP_HIDE_FROM_ABI
-  _LIBCPP_CONSTEXPR_SINCE_CXX23 explicit unique_ptr(_Pp __p) _NOEXCEPT : __ptr_(__p, __value_init_tag()) {}
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 explicit unique_ptr(_Pp __p) _NOEXCEPT
+      : __ptr_(__p),
+        __deleter_() {}
 
   template <class _Pp,
             bool _Dummy = true,
             class       = _EnableIfDeleterConstructible<_LValRefType<_Dummy> >,
             class       = _EnableIfPointerConvertible<_Pp> >
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unique_ptr(_Pp __p, _LValRefType<_Dummy> __d) _NOEXCEPT
-      : __ptr_(__p, __d) {}
+      : __ptr_(__p),
+        __deleter_(__d) {}
 
   template <bool _Dummy = true, class = _EnableIfDeleterConstructible<_LValRefType<_Dummy> > >
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unique_ptr(nullptr_t, _LValRefType<_Dummy> __d) _NOEXCEPT
-      : __ptr_(nullptr, __d) {}
+      : __ptr_(nullptr),
+        __deleter_(__d) {}
 
   template <class _Pp,
             bool _Dummy = true,
             class       = _EnableIfDeleterConstructible<_GoodRValRefType<_Dummy> >,
             class       = _EnableIfPointerConvertible<_Pp> >
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unique_ptr(_Pp __p, _GoodRValRefType<_Dummy> __d) _NOEXCEPT
-      : __ptr_(__p, std::move(__d)) {
+      : __ptr_(__p),
+        __deleter_(std::move(__d)) {
     static_assert(!is_reference<deleter_type>::value, "rvalue deleter bound to reference");
   }
 
   template <bool _Dummy = true, class = _EnableIfDeleterConstructible<_GoodRValRefType<_Dummy> > >
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unique_ptr(nullptr_t, _GoodRValRefType<_Dummy> __d) _NOEXCEPT
-      : __ptr_(nullptr, std::move(__d)) {
+      : __ptr_(nullptr),
+        __deleter_(std::move(__d)) {
     static_assert(!is_reference<deleter_type>::value, "rvalue deleter bound to reference");
   }
 
@@ -395,11 +407,12 @@ class _LIBCPP_UNIQUE_PTR_TRIVIAL_ABI _LIBCPP_TEMPLATE_VIS unique_ptr<_Tp[], _Dp>
   _LIBCPP_HIDE_FROM_ABI unique_ptr(_Pp __p, _BadRValRefType<_Dummy> __d) = delete;
 
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unique_ptr(unique_ptr&& __u) _NOEXCEPT
-      : __ptr_(__u.release(), std::forward<deleter_type>(__u.get_deleter())) {}
+      : __ptr_(__u.release()),
+        __deleter_(std::forward<deleter_type>(__u.get_deleter())) {}
 
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unique_ptr& operator=(unique_ptr&& __u) _NOEXCEPT {
     reset(__u.release());
-    __ptr_.second() = std::forward<deleter_type>(__u.get_deleter());
+    __deleter_ = std::forward<deleter_type>(__u.get_deleter());
     return *this;
   }
 
@@ -408,7 +421,8 @@ class _LIBCPP_UNIQUE_PTR_TRIVIAL_ABI _LIBCPP_TEMPLATE_VIS unique_ptr<_Tp[], _Dp>
             class = _EnableIfMoveConvertible<unique_ptr<_Up, _Ep>, _Up>,
             class = _EnableIfDeleterConvertible<_Ep> >
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unique_ptr(unique_ptr<_Up, _Ep>&& __u) _NOEXCEPT
-      : __ptr_(__u.release(), std::forward<_Ep>(__u.get_deleter())) {}
+      : __ptr_(__u.release()),
+        __deleter_(std::forward<_Ep>(__u.get_deleter())) {}
 
   template <class _Up,
             class _Ep,
@@ -416,7 +430,7 @@ class _LIBCPP_UNIQUE_PTR_TRIVIAL_ABI _LIBCPP_TEMPLATE_VIS unique_ptr<_Tp[], _Dp>
             class = _EnableIfDeleterAssignable<_Ep> >
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unique_ptr& operator=(unique_ptr<_Up, _Ep>&& __u) _NOEXCEPT {
     reset(__u.release());
-    __ptr_.second() = std::forward<_Ep>(__u.get_deleter());
+    __deleter_ = std::forward<_Ep>(__u.get_deleter());
     return *this;
   }
 
@@ -434,41 +448,45 @@ class _LIBCPP_UNIQUE_PTR_TRIVIAL_ABI _LIBCPP_TEMPLATE_VIS unique_ptr<_Tp[], _Dp>
   }
 
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 __add_lvalue_reference_t<_Tp> operator[](size_t __i) const {
-    return __ptr_.first()[__i];
+    return __ptr_[__i];
   }
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 pointer get() const _NOEXCEPT { return __ptr_.first(); }
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 pointer get() const _NOEXCEPT { return __ptr_; }
 
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 deleter_type& get_deleter() _NOEXCEPT { return __ptr_.second(); }
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 deleter_type& get_deleter() _NOEXCEPT { return __deleter_; }
 
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 const deleter_type& get_deleter() const _NOEXCEPT {
-    return __ptr_.second();
+    return __deleter_;
   }
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 explicit operator bool() const _NOEXCEPT {
-    return __ptr_.first() != nullptr;
+    return __ptr_ != nullptr;
   }
 
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 pointer release() _NOEXCEPT {
-    pointer __t    = __ptr_.first();
-    __ptr_.first() = pointer();
+    pointer __t = __ptr_;
+    __ptr_      = pointer();
     return __t;
   }
 
   template <class _Pp, __enable_if_t<_CheckArrayPointerConversion<_Pp>::value, int> = 0>
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 void reset(_Pp __p) _NOEXCEPT {
-    pointer __tmp  = __ptr_.first();
-    __ptr_.first() = __p;
+    pointer __tmp = __ptr_;
+    __ptr_        = __p;
     if (__tmp)
-      __ptr_.second()(__tmp);
+      __deleter_(__tmp);
   }
 
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 void reset(nullptr_t = nullptr) _NOEXCEPT {
-    pointer __tmp  = __ptr_.first();
-    __ptr_.first() = nullptr;
+    pointer __tmp = __ptr_;
+    __ptr_        = nullptr;
     if (__tmp)
-      __ptr_.second()(__tmp);
+      __deleter_(__tmp);
   }
 
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 void swap(unique_ptr& __u) _NOEXCEPT { __ptr_.swap(__u.__ptr_); }
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 void swap(unique_ptr& __u) _NOEXCEPT {
+    using std::swap;
+    swap(__ptr_, __u.__ptr_);
+    swap(__deleter_, __u.__deleter_);
+  }
 };
 
 template <class _Tp, class _Dp, __enable_if_t<__is_swappable_v<_Dp>, int> = 0>
diff --git a/libcxx/include/__split_buffer b/libcxx/include/__split_buffer
index bab724d1b8963..7916769bd83bf 100644
--- a/libcxx/include/__split_buffer
+++ b/libcxx/include/__split_buffer
@@ -78,7 +78,7 @@ public:
   pointer __first_;
   pointer __begin_;
   pointer __end_;
-  __compressed_pair<pointer, allocator_type> __end_cap_;
+  _LIBCPP_COMPRESSED_PAIR(pointer, __end_cap_, allocator_type, __alloc_);
 
   using __alloc_ref       = __add_lvalue_reference_t<allocator_type>;
   using __alloc_const_ref = __add_lvalue_reference_t<allocator_type>;
@@ -88,13 +88,13 @@ public:
 
   _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI __split_buffer()
       _NOEXCEPT_(is_nothrow_default_constructible<allocator_type>::value)
-      : __first_(nullptr), __begin_(nullptr), __end_(nullptr), __end_cap_(nullptr, __default_init_tag()) {}
+      : __first_(nullptr), __begin_(nullptr), __end_(nullptr), __end_cap_(nullptr) {}
 
   _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI explicit __split_buffer(__alloc_rr& __a)
-      : __first_(nullptr), __begin_(nullptr), __end_(nullptr), __end_cap_(nullptr, __a) {}
+      : __first_(nullptr), __begin_(nullptr), __end_(nullptr), __end_cap_(nullptr), __alloc_(__a) {}
 
   _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI explicit __split_buffer(const __alloc_rr& __a)
-      : __first_(nullptr), __begin_(nullptr), __end_(nullptr), __end_cap_(nullptr, __a) {}
+      : __first_(nullptr), __begin_(nullptr), __end_(nullptr), __end_cap_(nullptr), __alloc_(__a) {}
 
   _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI
   __split_buffer(size_type __cap, size_type __start, __alloc_rr& __a);
@@ -111,15 +111,11 @@ public:
 
   _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI ~__split_buffer();
 
-  _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI __alloc_rr& __alloc() _NOEXCEPT { return __end_cap_.second(); }
-  _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const __alloc_rr& __alloc() const _NOEXCEPT {
-    return __end_cap_.second();
-  }
+  _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI __alloc_rr& __alloc() _NOEXCEPT { return __alloc_; }
+  _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const __alloc_rr& __alloc() const _NOEXCEPT { return __alloc_; }
 
-  _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI pointer& __end_cap() _NOEXCEPT { return __end_cap_.first(); }
-  _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const pointer& __end_cap() const _NOEXCEPT {
-    return __end_cap_.first();
-  }
+  _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI pointer& __end_cap() _NOEXCEPT { return __end_cap_; }
+  _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const pointer& __end_cap() const _NOEXCEPT { return __end_cap_; }
 
   _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI iterator begin() _NOEXCEPT { return __begin_; }
   _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_iterator begin() const _NOEXCEPT { return __begin_; }
@@ -346,7 +342,7 @@ __split_buffer<_Tp, _Allocator>::__destruct_at_end(pointer __new_last, true_type
 template <class _Tp, class _Allocator>
 _LIBCPP_CONSTEXPR_SINCE_CXX20
 __split_buffer<_Tp, _Allocator>::__split_buffer(size_type __cap, size_type __start, __alloc_rr& __a)
-    : __end_cap_(nullptr, __a) {
+    : __end_cap_(nullptr), __alloc_(__a) {
   if (__cap == 0) {
     __first_ = nullptr;
   } else {
@@ -371,7 +367,8 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 __split_buffer<_Tp, _Allocator>::__split_buffer(__
     : __first_(std::move(__c.__first_)),
       __begin_(std::move(__c.__begin_)),
       __end_(std::move(__c.__end_)),
-      __end_cap_(std::move(__c.__end_cap_)) {
+      __end_cap_(std::move(__c.__end_cap_)),
+      __alloc_(std::move(__c.__alloc_)) {
   __c.__first_    = nullptr;
   __c.__begin_    = nullptr;
   __c.__end_      = nullptr;
@@ -381,7 +378,7 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 __split_buffer<_Tp, _Allocator>::__split_buffer(__
 template <class _Tp, class _Allocator>
 _LIBCPP_CONSTEXPR_SINCE_CXX20
 __split_buffer<_Tp, _Allocator>::__split_buffer(__split_buffer&& __c, const __alloc_rr& __a)
-    : __end_cap_(nullptr, __a) {
+    : __end_cap_(nullptr), __alloc_(__a) {
   if (__a == __c.__alloc()) {
     __first_        = __c.__first_;
     __begin_        = __c.__begin_;
diff --git a/libcxx/include/__tree b/libcxx/include/__tree
index 1990fa602d39c..6ded2c597f6fa 100644
--- a/libcxx/include/__tree
+++ b/libcxx/include/__tree
@@ -932,21 +932,21 @@ private:
 
 private:
   __iter_pointer __begin_node_;
-  __compressed_pair<__end_node_t, __node_allocator> __pair1_;
-  __compressed_pair<size_type, value_compare> __pair3_;
+  _LIBCPP_COMPRESSED_PAIR(__end_node_t, __end_node_, __node_allocator, __node_alloc_);
+  _LIBCPP_COMPRESSED_PAIR(size_type, __size_, value_compare, __value_comp_);
 
 public:
   _LIBCPP_HIDE_FROM_ABI __iter_pointer __end_node() _NOEXCEPT {
-    return static_cast<__iter_pointer>(pointer_traits<__end_node_ptr>::pointer_to(__pair1_.first()));
+    return static_cast<__iter_pointer>(pointer_traits<__end_node_ptr>::pointer_to(__end_node_));
   }
   _LIBCPP_HIDE_FROM_ABI __iter_pointer __end_node() const _NOEXCEPT {
     return static_cast<__iter_pointer>(
-        pointer_traits<__end_node_ptr>::pointer_to(const_cast<__end_node_t&>(__pair1_.first())));
+        pointer_traits<__end_node_ptr>::pointer_to(const_cast<__end_node_t&>(__end_node_)));
   }
-  _LIBCPP_HIDE_FROM_ABI __node_allocator& __node_alloc() _NOEXCEPT { return __pair1_.second(); }
+  _LIBCPP_HIDE_FROM_ABI __node_allocator& __node_alloc() _NOEXCEPT { return __node_alloc_; }
 
 private:
-  _LIBCPP_HIDE_FROM_ABI const __node_allocator& __node_alloc() const _NOEXCEPT { return __pair1_.second(); }
+  _LIBCPP_HIDE_FROM_ABI const __node_allocator& __node_alloc() const _NOEXCEPT { return __node_alloc_; }
   _LIBCPP_HIDE_FROM_ABI __iter_pointer& __begin_node() _NOEXCEPT { return __begin_node_; }
   _LIBCPP_HIDE_FROM_ABI const __iter_pointer& __begin_node() const _NOEXCEPT { return __begin_node_; }
 
@@ -954,12 +954,12 @@ public:
   _LIBCPP_HIDE_FROM_ABI allocator_type __alloc() const _NOEXCEPT { return allocator_type(__node_alloc()); }
 
 private:
-  _LIBCPP_HIDE_FROM_ABI size_type& size() _NOEXCEPT { return __pair3_.first(); }
+  _LIBCPP_HIDE_FROM_ABI size_type& size() _NOEXCEPT { return __size_; }
 
 public:
-  _LIBCPP_HIDE_FROM_ABI const size_type& size() const _NOEXCEPT { return __pair3_.first(); }
-  _LIBCPP_HIDE_FROM_ABI value_compare& value_comp() _NOEXCEPT { return __pair3_.second(); }
-  _LIBCPP_HIDE_FROM_ABI const value_compare& value_comp() const _NOEXCEPT { return __pair3_.second(); }
+  _LIBCPP_HIDE_FROM_ABI const size_type& size() const _NOEXCEPT { return __size_; }
+  _LIBCPP_HIDE_FROM_ABI value_compare& value_comp() _NOEXCEPT { return __value_comp_; }
+  _LIBCPP_HIDE_FROM_ABI const value_compare& value_comp() const _NOEXCEPT { return __value_comp_; }
 
 public:
   _LIBCPP_HIDE_FROM_ABI __node_pointer __root() const _NOEXCEPT {
@@ -1324,21 +1324,19 @@ private:
 template <class _Tp, class _Compare, class _Allocator>
 __tree<_Tp, _Compare, _Allocator>::__tree(const value_compare& __comp) _NOEXCEPT_(
     is_nothrow_default_constructible<__node_allocator>::value&& is_nothrow_copy_constructible<value_compare>::value)
-    : __pair3_(0, __comp) {
+    : __size_(0), __value_comp_(__comp) {
   __begin_node() = __end_node();
 }
 
 template <class _Tp, class _Compare, class _Allocator>
 __tree<_Tp, _Compare, _Allocator>::__tree(const allocator_type& __a)
-    : __begin_node_(__iter_pointer()),
-      __pair1_(__default_init_tag(), __node_allocator(__a)),
-      __pair3_(0, __default_init_tag()) {
+    : __begin_node_(__iter_pointer()), __node_alloc_(__node_allocator(__a)), __size_(0) {
   __begin_node() = __end_node();
 }
 
 template <class _Tp, class _Compare, class _Allocator>
 __tree<_Tp, _Compare, _Allocator>::__tree(const value_compare& __comp, const allocator_type& __a)
-    : __begin_node_(__iter_pointer()), __pair1_(__default_init_tag(), __node_allocator(__a)), __pair3_(0, __comp) {
+    : __begin_node_(__iter_pointer()), __node_alloc_(__node_allocator(__a)), __size_(0), __value_comp_(__comp) {
   __begin_node() = __end_node();
 }
 
@@ -1437,8 +1435,9 @@ void __tree<_Tp, _Compare, _Allocator>::__assign_multi(_InputIterator __first, _
 template <class _Tp, class _Compare, class _Allocator>
 __tree<_Tp, _Compare, _Allocator>::__tree(const __tree& __t)
     : __begin_node_(__iter_pointer()),
-      __pair1_(__default_init_tag(), __node_traits::select_on_container_copy_construction(__t.__node_alloc())),
-      __pair3_(0, __t.value_comp()) {
+      __node_alloc_(__node_traits::select_on_container_copy_construction(__t.__node_alloc())),
+      __size_(0),
+      __value_comp_(__t.value_comp()) {
   __begin_node() = __end_node();
 }
 
@@ -1446,8 +1445,10 @@ template <class _Tp, class _Compare, class _Allocator>
 __tree<_Tp, _Compare, _Allocator>::__tree(__tree&& __t) _NOEXCEPT_(
     is_nothrow_move_constructible<__node_allocator>::value&& is_nothrow_move_constructible<value_compare>::value)
     : __begin_node_(std::move(__t.__begin_node_)),
-      __pair1_(std::move(__t.__pair1_)),
-      __pair3_(std::move(__t.__pair3_)) {
+      __end_node_(std::move(__t.__end_node_)),
+      __node_alloc_(std::move(__t.__node_alloc_)),
+      __size_(__t.__size_),
+      __value_comp_(std::move(__t.__value_comp_)) {
   if (size() == 0)
     __begin_node() = __end_node();
   else {
@@ -1460,7 +1461,7 @@ __tree<_Tp, _Compare, _Allocator>::__tree(__tree&& __t) _NOEXCEPT_(
 
 template <class _Tp, class _Compare, class _Allocator>
 __tree<_Tp, _Compare, _Allocator>::__tree(__tree&& __t, const allocator_type& __a)
-    : __pair1_(__default_init_tag(), __node_allocator(__a)), __pair3_(0, std::move(__t.value_comp())) {
+    : __node_alloc_(__node_allocator(__a)), __size_(0), __value_comp_(std::move(__t.value_comp())) {
   if (__a == __t.__alloc()) {
     if (__t.size() == 0)
       __begin_node() = __end_node();
@@ -1482,10 +1483,11 @@ template <class _Tp, class _Compare, class _Allocator>
 void __tree<_Tp, _Compare, _Allocator>::__move_assign(__tree& __t, true_type)
     _NOEXCEPT_(is_nothrow_move_assignable<value_compare>::value&& is_nothrow_move_assignable<__node_allocator>::value) {
   destroy(static_cast<__node_pointer>(__end_node()->__left_));
-  __begin_node_    = __t.__begin_node_;
-  __pair1_.first() = __t.__pair1_.first();
+  __begin_node_ = __t.__begin_node_;
+  __end_node_   = __t.__end_node_;
   __move_assign_alloc(__t);
-  __pair3_ = std::move(__t.__pair3_);
+  __size_       = __t.__size_;
+  __value_comp_ = std::move(__t.__value_comp_);
   if (size() == 0)
     __begin_node() = __end_node();
   else {
@@ -1554,9 +1556,10 @@ void __tree<_Tp, _Compare, _Allocator>::swap(__tree& __t)
 {
   using std::swap;
   swap(__begin_node_, __t.__begin_node_);
-  swap(__pair1_.first(), __t.__pair1_.first());
+  swap(__end_node_, __t.__end_node_);
   std::__swap_allocator(__node_alloc(), __t.__node_alloc());
-  __pair3_.swap(__t.__pair3_);
+  swap(__size_, __t.__size_);
+  swap(__value_comp_, __t.__value_comp_);
   if (size() == 0)
     __begin_node() = __end_node();
   else
diff --git a/libcxx/include/__type_traits/datasizeof.h b/libcxx/include/__type_traits/datasizeof.h
index 35c12921e8ffa..1b324e470d0b0 100644
--- a/libcxx/include/__type_traits/datasizeof.h
+++ b/libcxx/include/__type_traits/datasizeof.h
@@ -54,9 +54,13 @@ struct _FirstPaddingByte<_Tp, true> {
 // the use as an extension.
 _LIBCPP_DIAGNOSTIC_PUSH
 _LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Winvalid-offsetof")
+_LIBCPP_GCC_DIAGNOSTIC_IGNORED("-Winvalid-offsetof")
 template <class _Tp>
 inline const size_t __datasizeof_v = offsetof(_FirstPaddingByte<_Tp>, __first_padding_byte_);
 _LIBCPP_DIAGNOSTIC_POP
+
+template <class _Tp>
+inline const size_t __datasizeof_v<_Tp&> = __datasizeof_v<_Tp>;
 #endif   // __has_extension(datasizeof)
 
 _LIBCPP_END_NAMESPACE_STD
diff --git a/libcxx/include/deque b/libcxx/include/deque
index 43ed8c46866ec..e184323212c32 100644
--- a/libcxx/include/deque
+++ b/libcxx/include/deque
@@ -561,12 +561,12 @@ private:
 
   __map __map_;
   size_type __start_;
-  __compressed_pair<size_type, allocator_type> __size_;
+  _LIBCPP_COMPRESSED_PAIR(size_type, __size_, allocator_type, __alloc_);
 
 public:
   // construct/copy/destroy:
   _LIBCPP_HIDE_FROM_ABI deque() _NOEXCEPT_(is_nothrow_default_constructible<allocator_type>::value)
-      : __start_(0), __size_(0, __default_init_tag()) {
+      : __start_(0), __size_(0) {
     __annotate_new(0);
   }
 
@@ -580,7 +580,7 @@ public:
   }
 
   _LIBCPP_HIDE_FROM_ABI explicit deque(const allocator_type& __a)
-      : __map_(__pointer_allocator(__a)), __start_(0), __size_(0, __a) {
+      : __map_(__pointer_allocator(__a)), __start_(0), __size_(0), __alloc_(__a) {
     __annotate_new(0);
   }
 
@@ -592,7 +592,7 @@ public:
 
   template <__enable_if_t<__is_allocator<_Allocator>::value, int> = 0>
   _LIBCPP_HIDE_FROM_ABI deque(size_type __n, const value_type& __v, const allocator_type& __a)
-      : __map_(__pointer_allocator(__a)), __start_(0), __size_(0, __a) {
+      : __map_(__pointer_allocator(__a)), __start_(0), __size_(0), __alloc_(__a) {
     __annotate_new(0);
     if (__n > 0)
       __append(__n, __v);
@@ -606,7 +606,7 @@ public:
 #if _LIBCPP_STD_VER >= 23
   template <_ContainerCompatibleRange<_Tp> _Range>
   _LIBCPP_HIDE_FROM_ABI deque(from_range_t, _Range&& __range, const allocator_type& __a = allocator_type())
-      : __map_(__pointer_allocator(__a)), __start_(0), __size_(0, __a) {
+      : __map_(__pointer_allocator(__a)), __start_(0), __size_(0), __alloc_(__a) {
     if constexpr (ranges::forward_range<_Range> || ranges::sized_range<_Range>) {
       __append_with_size(ranges::begin(__range), ranges::distance(__range));
 
@@ -669,8 +669,8 @@ public:
   _LIBCPP_HIDE_FROM_ABI void assign(size_type __n, const value_type& __v);
 
   _LIBCPP_HIDE_FROM_ABI allocator_type get_allocator() const _NOEXCEPT;
-  _LIBCPP_HIDE_FROM_ABI allocator_type& __alloc() _NOEXCEPT { return __size_.second(); }
-  _LIBCPP_HIDE_FROM_ABI const allocator_type& __alloc() const _NOEXCEPT { return __size_.second(); }
+  _LIBCPP_HIDE_FROM_ABI allocator_type& __alloc() _NOEXCEPT { return __alloc_; }
+  _LIBCPP_HIDE_FROM_ABI const allocator_type& __alloc() const _NOEXCEPT { return __alloc_; }
 
   // iterators:
 
@@ -709,8 +709,8 @@ public:
   // capacity:
   _LIBCPP_HIDE_FROM_ABI size_type size() const _NOEXCEPT { return __size(); }
 
-  _LIBCPP_HIDE_FROM_ABI size_type& __size() _NOEXCEPT { return __size_.first(); }
-  _LIBCPP_HIDE_FROM_ABI const size_type& __size() const _NOEXCEPT { return __size_.first(); }
+  _LIBCPP_HIDE_FROM_ABI size_type& __size() _NOEXCEPT { return __size_; }
+  _LIBCPP_HIDE_FROM_ABI const size_type& __size() const _NOEXCEPT { return __size_; }
 
   _LIBCPP_HIDE_FROM_ABI size_type max_size() const _NOEXCEPT {
     return std::min<size_type>(__alloc_traits::max_size(__alloc()), numeric_limits<difference_type>::max());
@@ -1230,7 +1230,7 @@ deque(from_range_t, _Range&&, _Alloc = _Alloc()) -> deque<ranges::range_value_t<
 #endif
 
 template <class _Tp, class _Allocator>
-deque<_Tp, _Allocator>::deque(size_type __n) : __start_(0), __size_(0, __default_init_tag()) {
+deque<_Tp, _Allocator>::deque(size_type __n) : __start_(0), __size_(0) {
   __annotate_new(0);
   if (__n > 0)
     __append(__n);
@@ -1239,7 +1239,7 @@ deque<_Tp, _Allocator>::deque(size_type __n) : __start_(0), __size_(0, __default
 #if _LIBCPP_STD_VER >= 14
 template <class _Tp, class _Allocator>
 deque<_Tp, _Allocator>::deque(size_type __n, const _Allocator& __a)
-    : __map_(__pointer_allocator(__a)), __start_(0), __size_(0, __a) {
+    : __map_(__pointer_allocator(__a)), __start_(0), __size_(0), __alloc_(__a) {
   __annotate_new(0);
   if (__n > 0)
     __append(__n);
@@ -1247,7 +1247,7 @@ deque<_Tp, _Allocator>::deque(size_type __n, const _Allocator& __a)
 #endif
 
 template <class _Tp, class _Allocator>
-deque<_Tp, _Allocator>::deque(size_type __n, const value_type& __v) : __start_(0), __size_(0, __default_init_tag()) {
+deque<_Tp, _Allocator>::deque(size_type __n, const value_type& __v) : __start_(0), __size_(0) {
   __annotate_new(0);
   if (__n > 0)
     __append(__n, __v);
@@ -1255,7 +1255,7 @@ deque<_Tp, _Allocator>::deque(size_type __n, const value_type& __v) : __start_(0
 
 template <class _Tp, class _Allocator>
 template <class _InputIter, __enable_if_t<__has_input_iterator_category<_InputIter>::value, int> >
-deque<_Tp, _Allocator>::deque(_InputIter __f, _InputIter __l) : __start_(0), __size_(0, __default_init_tag()) {
+deque<_Tp, _Allocator>::deque(_InputIter __f, _InputIter __l) : __start_(0), __size_(0) {
   __annotate_new(0);
   __append(__f, __l);
 }
@@ -1263,7 +1263,7 @@ deque<_Tp, _Allocator>::deque(_InputIter __f, _InputIter __l) : __start_(0), __s
 template <class _Tp, class _Allocator>
 template <class _InputIter, __enable_if_t<__has_input_iterator_category<_InputIter>::value, int> >
 deque<_Tp, _Allocator>::deque(_InputIter __f, _InputIter __l, const allocator_type& __a)
-    : __map_(__pointer_allocator(__a)), __start_(0), __size_(0, __a) {
+    : __map_(__pointer_allocator(__a)), __start_(0), __size_(0), __alloc_(__a) {
   __annotate_new(0);
   __append(__f, __l);
 }
@@ -1272,14 +1272,15 @@ template <class _Tp, class _Allocator>
 deque<_Tp, _Allocator>::deque(const deque& __c)
     : __map_(__pointer_allocator(__alloc_traits::select_on_container_copy_construction(__c.__alloc()))),
       __start_(0),
-      __size_(0, __map_.__alloc()) {
+      __size_(0),
+      __alloc_(__map_.__alloc()) {
   __annotate_new(0);
   __append(__c.begin(), __c.end());
 }
 
 template <class _Tp, class _Allocator>
 deque<_Tp, _Allocator>::deque(const deque& __c, const __type_identity_t<allocator_type>& __a)
-    : __map_(__pointer_allocator(__a)), __start_(0), __size_(0, __a) {
+    : __map_(__pointer_allocator(__a)), __start_(0), __size_(0), __alloc_(__a) {
   __annotate_new(0);
   __append(__c.begin(), __c.end());
 }
@@ -1296,21 +1297,24 @@ deque<_Tp, _Allocator>& deque<_Tp, _Allocator>::operator=(const deque& __c) {
 #ifndef _LIBCPP_CXX03_LANG
 
 template <class _Tp, class _Allocator>
-deque<_Tp, _Allocator>::deque(initializer_list<value_type> __il) : __start_(0), __size_(0, __default_init_tag()) {
+deque<_Tp, _Allocator>::deque(initializer_list<value_type> __il) : __start_(0), __size_(0) {
   __annotate_new(0);
   __append(__il.begin(), __il.end());
 }
 
 template <class _Tp, class _Allocator>
 deque<_Tp, _Allocator>::deque(initializer_list<value_type> __il, const allocator_type& __a)
-    : __map_(__pointer_allocator(__a)), __start_(0), __size_(0, __a) {
+    : __map_(__pointer_allocator(__a)), __start_(0), __size_(0), __alloc_(__a) {
   __annotate_new(0);
   __append(__il.begin(), __il.end());
 }
 
 template <class _Tp, class _Allocator>
 inline deque<_Tp, _Allocator>::deque(deque&& __c) noexcept(is_nothrow_move_constructible<allocator_type>::value)
-    : __map_(std::move(__c.__map_)), __start_(std::move(__c.__start_)), __size_(std::move(__c.__size_)) {
+    : __map_(std::move(__c.__map_)),
+      __start_(std::move(__c.__start_)),
+      __size_(std::move(__c.__size_)),
+      __alloc_(std::move(__c.__alloc_)) {
   __c.__start_ = 0;
   __c.__size() = 0;
 }
@@ -1319,7 +1323,8 @@ template <class _Tp, class _Allocator>
 inline deque<_Tp, _Allocator>::deque(deque&& __c, const __type_identity_t<allocator_type>& __a)
     : __map_(std::move(__c.__map_), __pointer_allocator(__a)),
       __start_(std::move(__c.__start_)),
-      __size_(std::move(__c.__size()), __a) {
+      __size_(std::move(__c.__size_)),
+      __alloc_(__a) {
   if (__a == __c.__alloc()) {
     __c.__start_ = 0;
     __c.__size() = 0;
diff --git a/libcxx/include/forward_list b/libcxx/include/forward_list
index e59c210654caa..8e457141b819f 100644
--- a/libcxx/include/forward_list
+++ b/libcxx/include/forward_list
@@ -227,6 +227,7 @@ template <class T, class Allocator, class Predicate>
 #include <__type_traits/type_identity.h>
 #include <__utility/forward.h>
 #include <__utility/move.h>
+#include <__utility/swap.h>
 #include <limits>
 #include <new> // __launder
 #include <version>
@@ -489,27 +490,27 @@ protected:
   typedef __rebind_alloc<allocator_traits<allocator_type>, __begin_node> __begin_node_allocator;
   typedef typename allocator_traits<__begin_node_allocator>::pointer __begin_node_pointer;
 
-  __compressed_pair<__begin_node, __node_allocator> __before_begin_;
+  _LIBCPP_COMPRESSED_PAIR(__begin_node, __before_begin_, __node_allocator, __alloc_);
 
   _LIBCPP_HIDE_FROM_ABI __begin_node_pointer __before_begin() _NOEXCEPT {
-    return pointer_traits<__begin_node_pointer>::pointer_to(__before_begin_.first());
+    return pointer_traits<__begin_node_pointer>::pointer_to(__before_begin_);
   }
   _LIBCPP_HIDE_FROM_ABI __begin_node_pointer __before_begin() const _NOEXCEPT {
-    return pointer_traits<__begin_node_pointer>::pointer_to(const_cast<__begin_node&>(__before_begin_.first()));
+    return pointer_traits<__begin_node_pointer>::pointer_to(const_cast<__begin_node&>(__before_begin_));
   }
 
-  _LIBCPP_HIDE_FROM_ABI __node_allocator& __alloc() _NOEXCEPT { return __before_begin_.second(); }
-  _LIBCPP_HIDE_FROM_ABI const __node_allocator& __alloc() const _NOEXCEPT { return __before_begin_.second(); }
+  _LIBCPP_HIDE_FROM_ABI __node_allocator& __alloc() _NOEXCEPT { return __alloc_; }
+  _LIBCPP_HIDE_FROM_ABI const __node_allocator& __alloc() const _NOEXCEPT { return __alloc_; }
 
   typedef __forward_list_iterator<__node_pointer> iterator;
   typedef __forward_list_const_iterator<__node_pointer> const_iterator;
 
   _LIBCPP_HIDE_FROM_ABI __forward_list_base() _NOEXCEPT_(is_nothrow_default_constructible<__node_allocator>::value)
-      : __before_begin_(__begin_node(), __default_init_tag()) {}
+      : __before_begin_(__begin_node()) {}
   _LIBCPP_HIDE_FROM_ABI explicit __forward_list_base(const allocator_type& __a)
-      : __before_begin_(__begin_node(), __node_allocator(__a)) {}
+      : __before_begin_(__begin_node()), __alloc_(__node_allocator(__a)) {}
   _LIBCPP_HIDE_FROM_ABI explicit __forward_list_base(const __node_allocator& __a)
-      : __before_begin_(__begin_node(), __a) {}
+      : __before_begin_(__begin_node()), __alloc_(__a) {}
 
 public:
 #ifndef _LIBCPP_CXX03_LANG
@@ -591,13 +592,13 @@ private:
 template <class _Tp, class _Alloc>
 inline __forward_list_base<_Tp, _Alloc>::__forward_list_base(__forward_list_base&& __x) noexcept(
     is_nothrow_move_constructible<__node_allocator>::value)
-    : __before_begin_(std::move(__x.__before_begin_)) {
+    : __before_begin_(std::move(__x.__before_begin_)), __alloc_(std::move(__x.__alloc_)) {
   __x.__before_begin()->__next_ = nullptr;
 }
 
 template <class _Tp, class _Alloc>
 inline __forward_list_base<_Tp, _Alloc>::__forward_list_base(__forward_list_base&& __x, const allocator_type& __a)
-    : __before_begin_(__begin_node(), __node_allocator(__a)) {
+    : __before_begin_(__begin_node()), __alloc_(__node_allocator(__a)) {
   if (__alloc() == __x.__alloc()) {
     __before_begin()->__next_     = __x.__before_begin()->__next_;
     __x.__before_begin()->__next_ = nullptr;
diff --git a/libcxx/include/future b/libcxx/include/future
index dea73dc6389bc..841ee29049f27 100644
--- a/libcxx/include/future
+++ b/libcxx/include/future
@@ -1401,13 +1401,13 @@ class __packaged_task_func;
 
 template <class _Fp, class _Alloc, class _Rp, class... _ArgTypes>
 class __packaged_task_func<_Fp, _Alloc, _Rp(_ArgTypes...)> : public __packaged_task_base<_Rp(_ArgTypes...)> {
-  __compressed_pair<_Fp, _Alloc> __f_;
+  _LIBCPP_COMPRESSED_PAIR(_Fp, __func_, _Alloc, __alloc_);
 
 public:
-  _LIBCPP_HIDE_FROM_ABI explicit __packaged_task_func(const _Fp& __f) : __f_(__f, __default_init_tag()) {}
-  _LIBCPP_HIDE_FROM_ABI explicit __packaged_task_func(_Fp&& __f) : __f_(std::move(__f), __default_init_tag()) {}
-  _LIBCPP_HIDE_FROM_ABI __packaged_task_func(const _Fp& __f, const _Alloc& __a) : __f_(__f, __a) {}
-  _LIBCPP_HIDE_FROM_ABI __packaged_task_func(_Fp&& __f, const _Alloc& __a) : __f_(std::move(__f), __a) {}
+  _LIBCPP_HIDE_FROM_ABI explicit __packaged_task_func(const _Fp& __f) : __func_(__f) {}
+  _LIBCPP_HIDE_FROM_ABI explicit __packaged_task_func(_Fp&& __f) : __func_(std::move(__f)) {}
+  _LIBCPP_HIDE_FROM_ABI __packaged_task_func(const _Fp& __f, const _Alloc& __a) : __func_(__f), __alloc_(__a) {}
+  _LIBCPP_HIDE_FROM_ABI __packaged_task_func(_Fp&& __f, const _Alloc& __a) : __func_(std::move(__f)), __alloc_(__a) {}
   _LIBCPP_HIDE_FROM_ABI_VIRTUAL virtual void __move_to(__packaged_task_base<_Rp(_ArgTypes...)>*) _NOEXCEPT;
   _LIBCPP_HIDE_FROM_ABI_VIRTUAL virtual void destroy();
   _LIBCPP_HIDE_FROM_ABI_VIRTUAL virtual void destroy_deallocate();
@@ -1417,12 +1417,13 @@ public:
 template <class _Fp, class _Alloc, class _Rp, class... _ArgTypes>
 void __packaged_task_func<_Fp, _Alloc, _Rp(_ArgTypes...)>::__move_to(
     __packaged_task_base<_Rp(_ArgTypes...)>* __p) _NOEXCEPT {
-  ::new ((void*)__p) __packaged_task_func(std::move(__f_.first()), std::move(__f_.second()));
+  ::new ((void*)__p) __packaged_task_func(std::move(__func_), std::move(__alloc_));
 }
 
 template <class _Fp, class _Alloc, class _Rp, class... _ArgTypes>
 void __packaged_task_func<_Fp, _Alloc, _Rp(_ArgTypes...)>::destroy() {
-  __f_.~__compressed_pair<_Fp, _Alloc>();
+  __func_.~_Fp();
+  __alloc_.~_Alloc();
 }
 
 template <class _Fp, class _Alloc, class _Rp, class... _ArgTypes>
@@ -1430,14 +1431,15 @@ void __packaged_task_func<_Fp, _Alloc, _Rp(_ArgTypes...)>::destroy_deallocate()
   typedef typename __allocator_traits_rebind<_Alloc, __packaged_task_func>::type _Ap;
   typedef allocator_traits<_Ap> _ATraits;
   typedef pointer_traits<typename _ATraits::pointer> _PTraits;
-  _Ap __a(__f_.second());
-  __f_.~__compressed_pair<_Fp, _Alloc>();
+  _Ap __a(__alloc_);
+  __func_.~_Fp();
+  __alloc_.~_Alloc();
   __a.deallocate(_PTraits::pointer_to(*this), 1);
 }
 
 template <class _Fp, class _Alloc, class _Rp, class... _ArgTypes>
 _Rp __packaged_task_func<_Fp, _Alloc, _Rp(_ArgTypes...)>::operator()(_ArgTypes&&... __arg) {
-  return std::__invoke(__f_.first(), std::forward<_ArgTypes>(__arg)...);
+  return std::__invoke(__func_, std::forward<_ArgTypes>(__arg)...);
 }
 
 template <class _Callable>
diff --git a/libcxx/include/list b/libcxx/include/list
index 57e5c05da9f06..d1fe8d354f407 100644
--- a/libcxx/include/list
+++ b/libcxx/include/list
@@ -497,16 +497,16 @@ protected:
                 "internal allocator type must differ from user-specified type; otherwise overload resolution breaks");
 
   __node_base __end_;
-  __compressed_pair<size_type, __node_allocator> __size_alloc_;
+  _LIBCPP_COMPRESSED_PAIR(size_type, __size_, __node_allocator, __node_alloc_);
 
   _LIBCPP_HIDE_FROM_ABI __link_pointer __end_as_link() const _NOEXCEPT {
     return __node_pointer_traits::__unsafe_link_pointer_cast(const_cast<__node_base&>(__end_).__self());
   }
 
-  _LIBCPP_HIDE_FROM_ABI size_type& __sz() _NOEXCEPT { return __size_alloc_.first(); }
-  _LIBCPP_HIDE_FROM_ABI const size_type& __sz() const _NOEXCEPT { return __size_alloc_.first(); }
-  _LIBCPP_HIDE_FROM_ABI __node_allocator& __node_alloc() _NOEXCEPT { return __size_alloc_.second(); }
-  _LIBCPP_HIDE_FROM_ABI const __node_allocator& __node_alloc() const _NOEXCEPT { return __size_alloc_.second(); }
+  _LIBCPP_HIDE_FROM_ABI size_type& __sz() _NOEXCEPT { return __size_; }
+  _LIBCPP_HIDE_FROM_ABI const size_type& __sz() const _NOEXCEPT { return __size_; }
+  _LIBCPP_HIDE_FROM_ABI __node_allocator& __node_alloc() _NOEXCEPT { return __node_alloc_; }
+  _LIBCPP_HIDE_FROM_ABI const __node_allocator& __node_alloc() const _NOEXCEPT { return __node_alloc_; }
 
   _LIBCPP_HIDE_FROM_ABI size_type __node_alloc_max_size() const _NOEXCEPT {
     return __node_alloc_traits::max_size(__node_alloc());
@@ -600,17 +600,20 @@ inline void __list_imp<_Tp, _Alloc>::__unlink_nodes(__link_pointer __f, __link_p
 
 template <class _Tp, class _Alloc>
 inline __list_imp<_Tp, _Alloc>::__list_imp() _NOEXCEPT_(is_nothrow_default_constructible<__node_allocator>::value)
-    : __size_alloc_(0, __default_init_tag()) {}
+    : __size_(0) {}
 
 template <class _Tp, class _Alloc>
-inline __list_imp<_Tp, _Alloc>::__list_imp(const allocator_type& __a) : __size_alloc_(0, __node_allocator(__a)) {}
+inline __list_imp<_Tp, _Alloc>::__list_imp(const allocator_type& __a)
+    : __size_(0), __node_alloc_(__node_allocator(__a)) {}
 
 template <class _Tp, class _Alloc>
-inline __list_imp<_Tp, _Alloc>::__list_imp(const __node_allocator& __a) : __size_alloc_(0, __a) {}
+inline __list_imp<_Tp, _Alloc>::__list_imp(const __node_allocator& __a) : __size_(0), __node_alloc_(__a) {}
 
 #ifndef _LIBCPP_CXX03_LANG
 template <class _Tp, class _Alloc>
-inline __list_imp<_Tp, _Alloc>::__list_imp(__node_allocator&& __a) _NOEXCEPT : __size_alloc_(0, std::move(__a)) {}
+inline __list_imp<_Tp, _Alloc>::__list_imp(__node_allocator&& __a) _NOEXCEPT
+    : __size_(0),
+      __node_alloc_(std::move(__a)) {}
 #endif
 
 template <class _Tp, class _Alloc>
diff --git a/libcxx/include/string b/libcxx/include/string
index 54d24c88a9c3f..1cecb0c2776b9 100644
--- a/libcxx/include/string
+++ b/libcxx/include/string
@@ -872,18 +872,18 @@ private:
     __long __l;
   };
 
-  __compressed_pair<__rep, allocator_type> __r_;
+  _LIBCPP_COMPRESSED_PAIR(__rep, __rep_, allocator_type, __alloc_);
 
   // Construct a string with the given allocator and enough storage to hold `__size` characters, but
   // don't initialize the characters. The contents of the string, including the null terminator, must be
   // initialized separately.
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 explicit basic_string(
       __uninitialized_size_tag, size_type __size, const allocator_type& __a)
-      : __r_(__default_init_tag(), __a) {
+      : __alloc_(__a) {
     if (__size > max_size())
       __throw_length_error();
     if (__fits_in_sso(__size)) {
-      __r_.first() = __rep();
+      __rep_ = __rep();
       __set_short_size(__size);
     } else {
       auto __capacity   = __recommend(__size) + 1;
@@ -899,7 +899,7 @@ private:
   template <class _Iter, class _Sent>
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20
   basic_string(__init_with_sentinel_tag, _Iter __first, _Sent __last, const allocator_type& __a)
-      : __r_(__default_init_tag(), __a) {
+      : __alloc_(__a) {
     __init_with_sentinel(std::move(__first), std::move(__last));
   }
 
@@ -914,7 +914,7 @@ public:
 
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string()
       _NOEXCEPT_(is_nothrow_default_constructible<allocator_type>::value)
-      : __r_(__value_init_tag(), __default_init_tag()) {
+      : __rep_() {
     __annotate_new(0);
   }
 
@@ -924,14 +924,14 @@ public:
 #else
       _NOEXCEPT
 #endif
-      : __r_(__value_init_tag(), __a) {
+      : __rep_(), __alloc_(__a) {
     __annotate_new(0);
   }
 
   _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_STRING_INTERNAL_MEMORY_ACCESS basic_string(const basic_string& __str)
-      : __r_(__default_init_tag(), __alloc_traits::select_on_container_copy_construction(__str.__alloc())) {
+      : __alloc_(__alloc_traits::select_on_container_copy_construction(__str.__alloc())) {
     if (!__str.__is_long()) {
-      __r_.first() = __str.__r_.first();
+      __rep_ = __str.__rep_;
       __annotate_new(__get_short_size());
     } else
       __init_copy_ctor_external(std::__to_address(__str.__get_long_pointer()), __str.__get_long_size());
@@ -939,9 +939,9 @@ public:
 
   _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_STRING_INTERNAL_MEMORY_ACCESS
   basic_string(const basic_string& __str, const allocator_type& __a)
-      : __r_(__default_init_tag(), __a) {
+      : __alloc_(__a) {
     if (!__str.__is_long()) {
-      __r_.first() = __str.__r_.first();
+      __rep_ = __str.__rep_;
       __annotate_new(__get_short_size());
     } else
       __init_copy_ctor_external(std::__to_address(__str.__get_long_pointer()), __str.__get_long_size());
@@ -957,28 +957,29 @@ public:
       // Turning off ASan instrumentation for variable initialization with _LIBCPP_STRING_INTERNAL_MEMORY_ACCESS
       // does not work consistently during initialization of __r_, so we instead unpoison __str's memory manually first.
       // __str's memory needs to be unpoisoned only in the case where it's a short string.
-      : __r_([](basic_string& __s) -> decltype(__s.__r_)&& {
+      : __rep_([](basic_string& __s) -> decltype(__s.__rep_)&& {
           if (!__s.__is_long())
             __s.__annotate_delete();
-          return std::move(__s.__r_);
-        }(__str)) {
-    __str.__r_.first() = __rep();
+          return std::move(__s.__rep_);
+        }(__str)),
+        __alloc_(std::move(__str.__alloc_)) {
+    __str.__rep_ = __rep();
     __str.__annotate_new(0);
     if (!__is_long())
       __annotate_new(size());
   }
 
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string(basic_string&& __str, const allocator_type& __a)
-      : __r_(__default_init_tag(), __a) {
+      : __alloc_(__a) {
     if (__str.__is_long() && __a != __str.__alloc()) // copy, not move
       __init(std::__to_address(__str.__get_long_pointer()), __str.__get_long_size());
     else {
       if (__libcpp_is_constant_evaluated())
-        __r_.first() = __rep();
+        __rep_ = __rep();
       if (!__str.__is_long())
         __str.__annotate_delete();
-      __r_.first()       = __str.__r_.first();
-      __str.__r_.first() = __rep();
+      __rep_       = __str.__rep_;
+      __str.__rep_ = __rep();
       __str.__annotate_new(0);
       if (!__is_long() && this != &__str)
         __annotate_new(size());
@@ -987,15 +988,14 @@ public:
 #endif // _LIBCPP_CXX03_LANG
 
   template <__enable_if_t<__is_allocator<_Allocator>::value, int> = 0>
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string(const _CharT* __s)
-      : __r_(__default_init_tag(), __default_init_tag()) {
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string(const _CharT* __s) {
     _LIBCPP_ASSERT_NON_NULL(__s != nullptr, "basic_string(const char*) detected nullptr");
     __init(__s, traits_type::length(__s));
   }
 
   template <__enable_if_t<__is_allocator<_Allocator>::value, int> = 0>
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string(const _CharT* __s, const _Allocator& __a)
-      : __r_(__default_init_tag(), __a) {
+      : __alloc_(__a) {
     _LIBCPP_ASSERT_NON_NULL(__s != nullptr, "basic_string(const char*, allocator) detected nullptr");
     __init(__s, traits_type::length(__s));
   }
@@ -1004,23 +1004,19 @@ public:
   basic_string(nullptr_t) = delete;
 #endif
 
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string(const _CharT* __s, size_type __n)
-      : __r_(__default_init_tag(), __default_init_tag()) {
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string(const _CharT* __s, size_type __n) {
     _LIBCPP_ASSERT_NON_NULL(__n == 0 || __s != nullptr, "basic_string(const char*, n) detected nullptr");
     __init(__s, __n);
   }
 
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20
   basic_string(const _CharT* __s, size_type __n, const _Allocator& __a)
-      : __r_(__default_init_tag(), __a) {
+      : __alloc_(__a) {
     _LIBCPP_ASSERT_NON_NULL(__n == 0 || __s != nullptr, "basic_string(const char*, n, allocator) detected nullptr");
     __init(__s, __n);
   }
 
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string(size_type __n, _CharT __c)
-      : __r_(__default_init_tag(), __default_init_tag()) {
-    __init(__n, __c);
-  }
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string(size_type __n, _CharT __c) { __init(__n, __c); }
 
 #if _LIBCPP_STD_VER >= 23
   _LIBCPP_HIDE_FROM_ABI constexpr basic_string(
@@ -1029,7 +1025,7 @@ public:
 
   _LIBCPP_HIDE_FROM_ABI constexpr basic_string(
       basic_string&& __str, size_type __pos, size_type __n, const _Allocator& __alloc = _Allocator())
-      : __r_(__default_init_tag(), __alloc) {
+      : __alloc_(__alloc) {
     if (__pos > __str.size())
       __throw_out_of_range();
 
@@ -1045,13 +1041,13 @@ public:
 
   template <__enable_if_t<__is_allocator<_Allocator>::value, int> = 0>
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string(size_type __n, _CharT __c, const _Allocator& __a)
-      : __r_(__default_init_tag(), __a) {
+      : __alloc_(__a) {
     __init(__n, __c);
   }
 
   _LIBCPP_CONSTEXPR_SINCE_CXX20
   basic_string(const basic_string& __str, size_type __pos, size_type __n, const _Allocator& __a = _Allocator())
-      : __r_(__default_init_tag(), __a) {
+      : __alloc_(__a) {
     size_type __str_sz = __str.size();
     if (__pos > __str_sz)
       __throw_out_of_range();
@@ -1060,7 +1056,7 @@ public:
 
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20
   basic_string(const basic_string& __str, size_type __pos, const _Allocator& __a = _Allocator())
-      : __r_(__default_init_tag(), __a) {
+      : __alloc_(__a) {
     size_type __str_sz = __str.size();
     if (__pos > __str_sz)
       __throw_out_of_range();
@@ -1073,7 +1069,7 @@ public:
                           int> = 0>
   _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS _LIBCPP_CONSTEXPR_SINCE_CXX20
   basic_string(const _Tp& __t, size_type __pos, size_type __n, const allocator_type& __a = allocator_type())
-      : __r_(__default_init_tag(), __a) {
+      : __alloc_(__a) {
     __self_view __sv0 = __t;
     __self_view __sv  = __sv0.substr(__pos, __n);
     __init(__sv.data(), __sv.size());
@@ -1083,8 +1079,8 @@ public:
             __enable_if_t<__can_be_converted_to_string_view<_CharT, _Traits, _Tp>::value &&
                               !__is_same_uncvref<_Tp, basic_string>::value,
                           int> = 0>
-  _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS _LIBCPP_CONSTEXPR_SINCE_CXX20 explicit basic_string(const _Tp& __t)
-      : __r_(__default_init_tag(), __default_init_tag()) {
+  _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS _LIBCPP_CONSTEXPR_SINCE_CXX20 explicit basic_string(
+      const _Tp& __t) {
     __self_view __sv = __t;
     __init(__sv.data(), __sv.size());
   }
@@ -1095,21 +1091,20 @@ public:
                           int> = 0>
   _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS
   _LIBCPP_CONSTEXPR_SINCE_CXX20 explicit basic_string(const _Tp& __t, const allocator_type& __a)
-      : __r_(__default_init_tag(), __a) {
+      : __alloc_(__a) {
     __self_view __sv = __t;
     __init(__sv.data(), __sv.size());
   }
 
   template <class _InputIterator, __enable_if_t<__has_input_iterator_category<_InputIterator>::value, int> = 0>
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string(_InputIterator __first, _InputIterator __last)
-      : __r_(__default_init_tag(), __default_init_tag()) {
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string(_InputIterator __first, _InputIterator __last) {
     __init(__first, __last);
   }
 
   template <class _InputIterator, __enable_if_t<__has_input_iterator_category<_InputIterator>::value, int> = 0>
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20
   basic_string(_InputIterator __first, _InputIterator __last, const allocator_type& __a)
-      : __r_(__default_init_tag(), __a) {
+      : __alloc_(__a) {
     __init(__first, __last);
   }
 
@@ -1117,7 +1112,7 @@ public:
   template <_ContainerCompatibleRange<_CharT> _Range>
   _LIBCPP_HIDE_FROM_ABI constexpr basic_string(
       from_range_t, _Range&& __range, const allocator_type& __a = allocator_type())
-      : __r_(__default_init_tag(), __a) {
+      : __alloc_(__a) {
     if constexpr (ranges::forward_range<_Range> || ranges::sized_range<_Range>) {
       __init_with_size(ranges::begin(__range), ranges::end(__range), ranges::distance(__range));
     } else {
@@ -1127,13 +1122,12 @@ public:
 #endif
 
 #ifndef _LIBCPP_CXX03_LANG
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string(initializer_list<_CharT> __il)
-      : __r_(__default_init_tag(), __default_init_tag()) {
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string(initializer_list<_CharT> __il) {
     __init(__il.begin(), __il.end());
   }
 
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string(initializer_list<_CharT> __il, const _Allocator& __a)
-      : __r_(__default_init_tag(), __a) {
+      : __alloc_(__a) {
     __init(__il.begin(), __il.end());
   }
 #endif // _LIBCPP_CXX03_LANG
@@ -1398,8 +1392,8 @@ public:
     size_type __old_sz = __str.size();
     if (!__str.__is_long())
       __str.__annotate_delete();
-    __r_.first()       = __str.__r_.first();
-    __str.__r_.first() = __rep();
+    __rep_       = __str.__rep_;
+    __str.__rep_ = __rep();
     __str.__annotate_new(0);
 
     _Traits::move(data(), data() + __pos, __len);
@@ -1806,10 +1800,10 @@ private:
 
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_STRING_INTERNAL_MEMORY_ACCESS bool
   __is_long() const _NOEXCEPT {
-    if (__libcpp_is_constant_evaluated() && __builtin_constant_p(__r_.first().__l.__is_long_)) {
-      return __r_.first().__l.__is_long_;
+    if (__libcpp_is_constant_evaluated() && __builtin_constant_p(__rep_.__l.__is_long_)) {
+      return __rep_.__l.__is_long_;
     }
-    return __r_.first().__s.__is_long_;
+    return __rep_.__s.__is_long_;
   }
 
   static _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __begin_lifetime(pointer __begin, size_type __n) {
@@ -1862,27 +1856,27 @@ private:
   _LIBCPP_CONSTEXPR_SINCE_CXX20 iterator
   __insert_with_size(const_iterator __pos, _Iterator __first, _Sentinel __last, size_type __n);
 
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 allocator_type& __alloc() _NOEXCEPT { return __r_.second(); }
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR const allocator_type& __alloc() const _NOEXCEPT { return __r_.second(); }
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 allocator_type& __alloc() _NOEXCEPT { return __alloc_; }
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR const allocator_type& __alloc() const _NOEXCEPT { return __alloc_; }
 
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_STRING_INTERNAL_MEMORY_ACCESS void
   __set_short_size(size_type __s) _NOEXCEPT {
     _LIBCPP_ASSERT_INTERNAL(__s < __min_cap, "__s should never be greater than or equal to the short string capacity");
-    __r_.first().__s.__size_    = __s;
-    __r_.first().__s.__is_long_ = false;
+    __rep_.__s.__size_    = __s;
+    __rep_.__s.__is_long_ = false;
   }
 
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_STRING_INTERNAL_MEMORY_ACCESS size_type
   __get_short_size() const _NOEXCEPT {
-    _LIBCPP_ASSERT_INTERNAL(!__r_.first().__s.__is_long_, "String has to be short when trying to get the short size");
-    return __r_.first().__s.__size_;
+    _LIBCPP_ASSERT_INTERNAL(!__rep_.__s.__is_long_, "String has to be short when trying to get the short size");
+    return __rep_.__s.__size_;
   }
 
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __set_long_size(size_type __s) _NOEXCEPT {
-    __r_.first().__l.__size_ = __s;
+    __rep_.__l.__size_ = __s;
   }
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 size_type __get_long_size() const _NOEXCEPT {
-    return __r_.first().__l.__size_;
+    return __rep_.__l.__size_;
   }
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __set_size(size_type __s) _NOEXCEPT {
     if (__is_long())
@@ -1892,31 +1886,36 @@ private:
   }
 
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __set_long_cap(size_type __s) _NOEXCEPT {
-    __r_.first().__l.__cap_     = __s / __endian_factor;
-    __r_.first().__l.__is_long_ = true;
+    __rep_.__l.__cap_     = __s / __endian_factor;
+    __rep_.__l.__is_long_ = true;
   }
 
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 size_type __get_long_cap() const _NOEXCEPT {
-    return __r_.first().__l.__cap_ * __endian_factor;
+    return __rep_.__l.__cap_ * __endian_factor;
   }
 
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __set_long_pointer(pointer __p) _NOEXCEPT {
-    __r_.first().__l.__data_ = __p;
+    __rep_.__l.__data_ = __p;
   }
+
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 pointer __get_long_pointer() _NOEXCEPT {
-    return _LIBCPP_ASAN_VOLATILE_WRAPPER(__r_.first().__l.__data_);
+    return _LIBCPP_ASAN_VOLATILE_WRAPPER(__rep_.__l.__data_);
   }
+
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 const_pointer __get_long_pointer() const _NOEXCEPT {
-    return _LIBCPP_ASAN_VOLATILE_WRAPPER(__r_.first().__l.__data_);
+    return _LIBCPP_ASAN_VOLATILE_WRAPPER(__rep_.__l.__data_);
   }
+
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_STRING_INTERNAL_MEMORY_ACCESS pointer
   __get_short_pointer() _NOEXCEPT {
-    return _LIBCPP_ASAN_VOLATILE_WRAPPER(pointer_traits<pointer>::pointer_to(__r_.first().__s.__data_[0]));
+    return _LIBCPP_ASAN_VOLATILE_WRAPPER(pointer_traits<pointer>::pointer_to(__rep_.__s.__data_[0]));
   }
+
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_STRING_INTERNAL_MEMORY_ACCESS const_pointer
   __get_short_pointer() const _NOEXCEPT {
-    return _LIBCPP_ASAN_VOLATILE_WRAPPER(pointer_traits<const_pointer>::pointer_to(__r_.first().__s.__data_[0]));
+    return _LIBCPP_ASAN_VOLATILE_WRAPPER(pointer_traits<const_pointer>::pointer_to(__rep_.__s.__data_[0]));
   }
+
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 pointer __get_pointer() _NOEXCEPT {
     return __is_long() ? __get_long_pointer() : __get_short_pointer();
   }
@@ -2208,7 +2207,7 @@ template <class _CharT, class _Traits, class _Allocator>
 _LIBCPP_CONSTEXPR_SINCE_CXX20 void
 basic_string<_CharT, _Traits, _Allocator>::__init(const value_type* __s, size_type __sz, size_type __reserve) {
   if (__libcpp_is_constant_evaluated())
-    __r_.first() = __rep();
+    __rep_ = __rep();
   if (__reserve > max_size())
     __throw_length_error();
   pointer __p;
@@ -2232,7 +2231,7 @@ template <class _CharT, class _Traits, class _Allocator>
 _LIBCPP_CONSTEXPR_SINCE_CXX20 void
 basic_string<_CharT, _Traits, _Allocator>::__init(const value_type* __s, size_type __sz) {
   if (__libcpp_is_constant_evaluated())
-    __r_.first() = __rep();
+    __rep_ = __rep();
   if (__sz > max_size())
     __throw_length_error();
   pointer __p;
@@ -2256,7 +2255,7 @@ template <class _CharT, class _Traits, class _Allocator>
 _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_NOINLINE void
 basic_string<_CharT, _Traits, _Allocator>::__init_copy_ctor_external(const value_type* __s, size_type __sz) {
   if (__libcpp_is_constant_evaluated())
-    __r_.first() = __rep();
+    __rep_ = __rep();
 
   pointer __p;
   if (__fits_in_sso(__sz)) {
@@ -2279,7 +2278,7 @@ basic_string<_CharT, _Traits, _Allocator>::__init_copy_ctor_external(const value
 template <class _CharT, class _Traits, class _Allocator>
 _LIBCPP_CONSTEXPR_SINCE_CXX20 void basic_string<_CharT, _Traits, _Allocator>::__init(size_type __n, value_type __c) {
   if (__libcpp_is_constant_evaluated())
-    __r_.first() = __rep();
+    __rep_ = __rep();
 
   if (__n > max_size())
     __throw_length_error();
@@ -2311,7 +2310,7 @@ template <class _CharT, class _Traits, class _Allocator>
 template <class _InputIterator, class _Sentinel>
 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void
 basic_string<_CharT, _Traits, _Allocator>::__init_with_sentinel(_InputIterator __first, _Sentinel __last) {
-  __r_.first() = __rep();
+  __rep_ = __rep();
   __annotate_new(0);
 
 #ifndef _LIBCPP_HAS_NO_EXCEPTIONS
@@ -2342,7 +2341,7 @@ template <class _InputIterator, class _Sentinel>
 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void
 basic_string<_CharT, _Traits, _Allocator>::__init_with_size(_InputIterator __first, _Sentinel __last, size_type __sz) {
   if (__libcpp_is_constant_evaluated())
-    __r_.first() = __rep();
+    __rep_ = __rep();
 
   if (__sz > max_size())
     __throw_length_error();
@@ -2563,7 +2562,7 @@ basic_string<_CharT, _Traits, _Allocator>::operator=(const basic_string& __str)
         size_type __old_size = __get_short_size();
         if (__get_short_size() < __str.__get_short_size())
           __annotate_increase(__str.__get_short_size() - __get_short_size());
-        __r_.first() = __str.__r_.first();
+        __rep_ = __str.__rep_;
         if (__old_size > __get_short_size())
           __annotate_shrink(__old_size);
       } else {
@@ -2611,7 +2610,7 @@ basic_string<_CharT, _Traits, _Allocator>::__move_assign(basic_string& __str, tr
   bool __str_was_short     = !__str.__is_long();
 
   __move_assign_alloc(__str);
-  __r_.first() = __str.__r_.first();
+  __rep_ = __str.__rep_;
   __str.__set_short_size(0);
   traits_type::assign(__str.__get_short_pointer()[0], value_type());
 
@@ -3347,7 +3346,7 @@ inline _LIBCPP_CONSTEXPR_SINCE_CXX20 void basic_string<_CharT, _Traits, _Allocat
     __annotate_delete();
   if (this != &__str && !__str.__is_long())
     __str.__annotate_delete();
-  std::swap(__r_.first(), __str.__r_.first());
+  std::swap(__rep_, __str.__rep_);
   std::__swap_allocator(__alloc(), __str.__alloc());
   if (!__is_long())
     __annotate_new(__get_short_size());
@@ -3710,7 +3709,7 @@ inline _LIBCPP_CONSTEXPR_SINCE_CXX20 void basic_string<_CharT, _Traits, _Allocat
   if (__is_long()) {
     __annotate_delete();
     __alloc_traits::deallocate(__alloc(), __get_long_pointer(), capacity() + 1);
-    __r_.first() = __rep();
+    __rep_ = __rep();
   }
 }
 
diff --git a/libcxx/include/vector b/libcxx/include/vector
index 014971b4a680e..f80282ebdef6d 100644
--- a/libcxx/include/vector
+++ b/libcxx/include/vector
@@ -430,7 +430,7 @@ public:
 #else
       _NOEXCEPT
 #endif
-      : __end_cap_(nullptr, __a) {
+      : __alloc_(__a) {
   }
 
   _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI explicit vector(size_type __n) {
@@ -444,7 +444,7 @@ public:
 
 #if _LIBCPP_STD_VER >= 14
   _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI explicit vector(size_type __n, const allocator_type& __a)
-      : __end_cap_(nullptr, __a) {
+      : __alloc_(__a) {
     auto __guard = std::__make_exception_guard(__destroy_vector(*this));
     if (__n > 0) {
       __vallocate(__n);
@@ -466,7 +466,7 @@ public:
   template <__enable_if_t<__is_allocator<_Allocator>::value, int> = 0>
   _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI
   vector(size_type __n, const value_type& __x, const allocator_type& __a)
-      : __end_cap_(nullptr, __a) {
+      : __alloc_(__a) {
     if (__n > 0) {
       __vallocate(__n);
       __construct_at_end(__n, __x);
@@ -504,7 +504,7 @@ public:
   template <_ContainerCompatibleRange<_Tp> _Range>
   _LIBCPP_HIDE_FROM_ABI constexpr vector(
       from_range_t, _Range&& __range, const allocator_type& __alloc = allocator_type())
-      : __end_cap_(nullptr, __alloc) {
+      : __alloc_(__alloc) {
     if constexpr (ranges::forward_range<_Range> || ranges::sized_range<_Range>) {
       auto __n = static_cast<size_type>(ranges::distance(__range));
       __init_with_size(ranges::begin(__range), ranges::end(__range), __n);
@@ -760,8 +760,7 @@ public:
 private:
   pointer __begin_ = nullptr;
   pointer __end_   = nullptr;
-  __compressed_pair<pointer, allocator_type> __end_cap_ =
-      __compressed_pair<pointer, allocator_type>(nullptr, __default_init_tag());
+  _LIBCPP_COMPRESSED_PAIR(pointer, __cap_ = nullptr, allocator_type, __alloc_);
 
   //  Allocate space for __n objects
   //  throws length_error if __n > max_size()
@@ -930,17 +929,14 @@ private:
     ++__tx.__pos_;
   }
 
-  _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI allocator_type& __alloc() _NOEXCEPT {
-    return this->__end_cap_.second();
-  }
+  // TODO: Remove these now redundant accessors
+  _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI allocator_type& __alloc() _NOEXCEPT { return this->__alloc_; }
   _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const allocator_type& __alloc() const _NOEXCEPT {
-    return this->__end_cap_.second();
-  }
-  _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI pointer& __end_cap() _NOEXCEPT {
-    return this->__end_cap_.first();
+    return this->__alloc_;
   }
+  _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI pointer& __end_cap() _NOEXCEPT { return this->__cap_; }
   _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const pointer& __end_cap() const _NOEXCEPT {
-    return this->__end_cap_.first();
+    return this->__cap_;
   }
 
   _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __clear() _NOEXCEPT {
@@ -1174,7 +1170,7 @@ template <class _InputIterator,
                         int> >
 _LIBCPP_CONSTEXPR_SINCE_CXX20
 vector<_Tp, _Allocator>::vector(_InputIterator __first, _InputIterator __last, const allocator_type& __a)
-    : __end_cap_(nullptr, __a) {
+    : __alloc_(__a) {
   __init_with_sentinel(__first, __last);
 }
 
@@ -1195,21 +1191,21 @@ template <class _ForwardIterator,
                         int> >
 _LIBCPP_CONSTEXPR_SINCE_CXX20
 vector<_Tp, _Allocator>::vector(_ForwardIterator __first, _ForwardIterator __last, const allocator_type& __a)
-    : __end_cap_(nullptr, __a) {
+    : __alloc_(__a) {
   size_type __n = static_cast<size_type>(std::distance(__first, __last));
   __init_with_size(__first, __last, __n);
 }
 
 template <class _Tp, class _Allocator>
 _LIBCPP_CONSTEXPR_SINCE_CXX20 vector<_Tp, _Allocator>::vector(const vector& __x)
-    : __end_cap_(nullptr, __alloc_traits::select_on_container_copy_construction(__x.__alloc())) {
+    : __alloc_(__alloc_traits::select_on_container_copy_construction(__x.__alloc())) {
   __init_with_size(__x.__begin_, __x.__end_, __x.size());
 }
 
 template <class _Tp, class _Allocator>
 _LIBCPP_CONSTEXPR_SINCE_CXX20
 vector<_Tp, _Allocator>::vector(const vector& __x, const __type_identity_t<allocator_type>& __a)
-    : __end_cap_(nullptr, __a) {
+    : __alloc_(__a) {
   __init_with_size(__x.__begin_, __x.__end_, __x.size());
 }
 
@@ -1220,7 +1216,7 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 inline _LIBCPP_HIDE_FROM_ABI vector<_Tp, _Allocato
 #else
     _NOEXCEPT_(is_nothrow_move_constructible<allocator_type>::value)
 #endif
-    : __end_cap_(nullptr, std::move(__x.__alloc())) {
+    : __alloc_(std::move(__x.__alloc())) {
   this->__begin_    = __x.__begin_;
   this->__end_      = __x.__end_;
   this->__end_cap() = __x.__end_cap();
@@ -1230,7 +1226,7 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 inline _LIBCPP_HIDE_FROM_ABI vector<_Tp, _Allocato
 template <class _Tp, class _Allocator>
 _LIBCPP_CONSTEXPR_SINCE_CXX20 inline _LIBCPP_HIDE_FROM_ABI
 vector<_Tp, _Allocator>::vector(vector&& __x, const __type_identity_t<allocator_type>& __a)
-    : __end_cap_(nullptr, __a) {
+    : __alloc_(__a) {
   if (__a == __x.__alloc()) {
     this->__begin_    = __x.__begin_;
     this->__end_      = __x.__end_;
@@ -1260,7 +1256,7 @@ vector<_Tp, _Allocator>::vector(initializer_list<value_type> __il) {
 template <class _Tp, class _Allocator>
 _LIBCPP_CONSTEXPR_SINCE_CXX20 inline _LIBCPP_HIDE_FROM_ABI
 vector<_Tp, _Allocator>::vector(initializer_list<value_type> __il, const allocator_type& __a)
-    : __end_cap_(nullptr, __a) {
+    : __alloc_(__a) {
   auto __guard = std::__make_exception_guard(__destroy_vector(*this));
   if (__il.size() > 0) {
     __vallocate(__il.size());
@@ -1844,7 +1840,7 @@ private:
 
   __storage_pointer __begin_;
   size_type __size_;
-  __compressed_pair<size_type, __storage_allocator> __cap_alloc_;
+  _LIBCPP_COMPRESSED_PAIR(size_type, __cap_, __storage_allocator, __alloc_);
 
 public:
   typedef __bit_reference<vector> reference;
@@ -1855,15 +1851,12 @@ public:
 #endif
 
 private:
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 size_type& __cap() _NOEXCEPT { return __cap_alloc_.first(); }
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 const size_type& __cap() const _NOEXCEPT {
-    return __cap_alloc_.first();
-  }
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 __storage_allocator& __alloc() _NOEXCEPT {
-    return __cap_alloc_.second();
-  }
+  // TODO: Remove these now redundant accessors
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 size_type& __cap() _NOEXCEPT { return __cap_; }
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 const size_type& __cap() const _NOEXCEPT { return __cap_; }
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 __storage_allocator& __alloc() _NOEXCEPT { return __alloc_; }
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 const __storage_allocator& __alloc() const _NOEXCEPT {
-    return __cap_alloc_.second();
+    return __alloc_;
   }
 
   static const unsigned __bits_per_word = static_cast<unsigned>(sizeof(__storage_type) * CHAR_BIT);
@@ -1926,7 +1919,7 @@ public:
 #if _LIBCPP_STD_VER >= 23
   template <_ContainerCompatibleRange<bool> _Range>
   _LIBCPP_HIDE_FROM_ABI constexpr vector(from_range_t, _Range&& __range, const allocator_type& __a = allocator_type())
-      : __begin_(nullptr), __size_(0), __cap_alloc_(0, static_cast<__storage_allocator>(__a)) {
+      : __begin_(nullptr), __size_(0), __cap_(0), __alloc_(static_cast<__storage_allocator>(__a)) {
     if constexpr (ranges::forward_range<_Range> || ranges::sized_range<_Range>) {
       auto __n = static_cast<size_type>(ranges::distance(__range));
       __init_with_size(ranges::begin(__range), ranges::end(__range), __n);
@@ -2331,7 +2324,7 @@ vector<bool, _Allocator>::__construct_at_end(_InputIterator __first, _Sentinel _
 template <class _Allocator>
 inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 vector<bool, _Allocator>::vector()
     _NOEXCEPT_(is_nothrow_default_constructible<allocator_type>::value)
-    : __begin_(nullptr), __size_(0), __cap_alloc_(0, __default_init_tag()) {}
+    : __begin_(nullptr), __size_(0), __cap_(0) {}
 
 template <class _Allocator>
 inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 vector<bool, _Allocator>::vector(const allocator_type& __a)
@@ -2340,12 +2333,12 @@ inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 vector<bool, _Allocat
 #else
         _NOEXCEPT
 #endif
-    : __begin_(nullptr), __size_(0), __cap_alloc_(0, static_cast<__storage_allocator>(__a)) {
+    : __begin_(nullptr), __size_(0), __cap_(0), __alloc_(static_cast<__storage_allocator>(__a)) {
 }
 
 template <class _Allocator>
 _LIBCPP_CONSTEXPR_SINCE_CXX20 vector<bool, _Allocator>::vector(size_type __n)
-    : __begin_(nullptr), __size_(0), __cap_alloc_(0, __default_init_tag()) {
+    : __begin_(nullptr), __size_(0), __cap_(0) {
   if (__n > 0) {
     __vallocate(__n);
     __construct_at_end(__n, false);
@@ -2355,7 +2348,7 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 vector<bool, _Allocator>::vector(size_type __n)
 #if _LIBCPP_STD_VER >= 14
 template <class _Allocator>
 _LIBCPP_CONSTEXPR_SINCE_CXX20 vector<bool, _Allocator>::vector(size_type __n, const allocator_type& __a)
-    : __begin_(nullptr), __size_(0), __cap_alloc_(0, static_cast<__storage_allocator>(__a)) {
+    : __begin_(nullptr), __size_(0), __cap_(0), __alloc_(static_cast<__storage_allocator>(__a)) {
   if (__n > 0) {
     __vallocate(__n);
     __construct_at_end(__n, false);
@@ -2365,7 +2358,7 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 vector<bool, _Allocator>::vector(size_type __n, co
 
 template <class _Allocator>
 _LIBCPP_CONSTEXPR_SINCE_CXX20 vector<bool, _Allocator>::vector(size_type __n, const value_type& __x)
-    : __begin_(nullptr), __size_(0), __cap_alloc_(0, __default_init_tag()) {
+    : __begin_(nullptr), __size_(0), __cap_(0) {
   if (__n > 0) {
     __vallocate(__n);
     __construct_at_end(__n, __x);
@@ -2375,7 +2368,7 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 vector<bool, _Allocator>::vector(size_type __n, co
 template <class _Allocator>
 _LIBCPP_CONSTEXPR_SINCE_CXX20
 vector<bool, _Allocator>::vector(size_type __n, const value_type& __x, const allocator_type& __a)
-    : __begin_(nullptr), __size_(0), __cap_alloc_(0, static_cast<__storage_allocator>(__a)) {
+    : __begin_(nullptr), __size_(0), __cap_(0), __alloc_(static_cast<__storage_allocator>(__a)) {
   if (__n > 0) {
     __vallocate(__n);
     __construct_at_end(__n, __x);
@@ -2385,7 +2378,7 @@ vector<bool, _Allocator>::vector(size_type __n, const value_type& __x, const all
 template <class _Allocator>
 template <class _InputIterator, __enable_if_t<__has_exactly_input_iterator_category<_InputIterator>::value, int> >
 _LIBCPP_CONSTEXPR_SINCE_CXX20 vector<bool, _Allocator>::vector(_InputIterator __first, _InputIterator __last)
-    : __begin_(nullptr), __size_(0), __cap_alloc_(0, __default_init_tag()) {
+    : __begin_(nullptr), __size_(0), __cap_(0) {
   __init_with_sentinel(__first, __last);
 }
 
@@ -2393,14 +2386,14 @@ template <class _Allocator>
 template <class _InputIterator, __enable_if_t<__has_exactly_input_iterator_category<_InputIterator>::value, int> >
 _LIBCPP_CONSTEXPR_SINCE_CXX20
 vector<bool, _Allocator>::vector(_InputIterator __first, _InputIterator __last, const allocator_type& __a)
-    : __begin_(nullptr), __size_(0), __cap_alloc_(0, static_cast<__storage_allocator>(__a)) {
+    : __begin_(nullptr), __size_(0), __cap_(0), __alloc_(static_cast<__storage_allocator>(__a)) {
   __init_with_sentinel(__first, __last);
 }
 
 template <class _Allocator>
 template <class _ForwardIterator, __enable_if_t<__has_forward_iterator_category<_ForwardIterator>::value, int> >
 _LIBCPP_CONSTEXPR_SINCE_CXX20 vector<bool, _Allocator>::vector(_ForwardIterator __first, _ForwardIterator __last)
-    : __begin_(nullptr), __size_(0), __cap_alloc_(0, __default_init_tag()) {
+    : __begin_(nullptr), __size_(0), __cap_(0) {
   auto __n = static_cast<size_type>(std::distance(__first, __last));
   __init_with_size(__first, __last, __n);
 }
@@ -2409,7 +2402,7 @@ template <class _Allocator>
 template <class _ForwardIterator, __enable_if_t<__has_forward_iterator_category<_ForwardIterator>::value, int> >
 _LIBCPP_CONSTEXPR_SINCE_CXX20
 vector<bool, _Allocator>::vector(_ForwardIterator __first, _ForwardIterator __last, const allocator_type& __a)
-    : __begin_(nullptr), __size_(0), __cap_alloc_(0, static_cast<__storage_allocator>(__a)) {
+    : __begin_(nullptr), __size_(0), __cap_(0), __alloc_(static_cast<__storage_allocator>(__a)) {
   auto __n = static_cast<size_type>(std::distance(__first, __last));
   __init_with_size(__first, __last, __n);
 }
@@ -2418,7 +2411,7 @@ vector<bool, _Allocator>::vector(_ForwardIterator __first, _ForwardIterator __la
 
 template <class _Allocator>
 _LIBCPP_CONSTEXPR_SINCE_CXX20 vector<bool, _Allocator>::vector(initializer_list<value_type> __il)
-    : __begin_(nullptr), __size_(0), __cap_alloc_(0, __default_init_tag()) {
+    : __begin_(nullptr), __size_(0), __cap_(0) {
   size_type __n = static_cast<size_type>(__il.size());
   if (__n > 0) {
     __vallocate(__n);
@@ -2429,7 +2422,7 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 vector<bool, _Allocator>::vector(initializer_list<
 template <class _Allocator>
 _LIBCPP_CONSTEXPR_SINCE_CXX20
 vector<bool, _Allocator>::vector(initializer_list<value_type> __il, const allocator_type& __a)
-    : __begin_(nullptr), __size_(0), __cap_alloc_(0, static_cast<__storage_allocator>(__a)) {
+    : __begin_(nullptr), __size_(0), __cap_(0), __alloc_(static_cast<__storage_allocator>(__a)) {
   size_type __n = static_cast<size_type>(__il.size());
   if (__n > 0) {
     __vallocate(__n);
@@ -2443,7 +2436,8 @@ template <class _Allocator>
 _LIBCPP_CONSTEXPR_SINCE_CXX20 vector<bool, _Allocator>::vector(const vector& __v)
     : __begin_(nullptr),
       __size_(0),
-      __cap_alloc_(0, __storage_traits::select_on_container_copy_construction(__v.__alloc())) {
+      __cap_(0),
+      __alloc_(__storage_traits::select_on_container_copy_construction(__v.__alloc())) {
   if (__v.size() > 0) {
     __vallocate(__v.size());
     __construct_at_end(__v.begin(), __v.end(), __v.size());
@@ -2452,7 +2446,7 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 vector<bool, _Allocator>::vector(const vector& __v
 
 template <class _Allocator>
 _LIBCPP_CONSTEXPR_SINCE_CXX20 vector<bool, _Allocator>::vector(const vector& __v, const allocator_type& __a)
-    : __begin_(nullptr), __size_(0), __cap_alloc_(0, __a) {
+    : __begin_(nullptr), __size_(0), __cap_(0), __alloc_(__a) {
   if (__v.size() > 0) {
     __vallocate(__v.size());
     __construct_at_end(__v.begin(), __v.end(), __v.size());
@@ -2484,7 +2478,8 @@ inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 vector<bool, _Allocat
 #endif
     : __begin_(__v.__begin_),
       __size_(__v.__size_),
-      __cap_alloc_(std::move(__v.__cap_alloc_)) {
+      __cap_(__v.__cap_),
+      __alloc_(std::move(__v.__alloc_)) {
   __v.__begin_ = nullptr;
   __v.__size_  = 0;
   __v.__cap()  = 0;
@@ -2493,7 +2488,7 @@ inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 vector<bool, _Allocat
 template <class _Allocator>
 _LIBCPP_CONSTEXPR_SINCE_CXX20
 vector<bool, _Allocator>::vector(vector&& __v, const __type_identity_t<allocator_type>& __a)
-    : __begin_(nullptr), __size_(0), __cap_alloc_(0, __a) {
+    : __begin_(nullptr), __size_(0), __cap_(0), __alloc_(__a) {
   if (__a == allocator_type(__v.__alloc())) {
     this->__begin_ = __v.__begin_;
     this->__size_  = __v.__size_;
diff --git a/libcxx/test/libcxx/containers/unord/unord.set/missing_hash_specialization.verify.cpp b/libcxx/test/libcxx/containers/unord/unord.set/missing_hash_specialization.verify.cpp
index f492b760edf26..f6d93c7e6ca57 100644
--- a/libcxx/test/libcxx/containers/unord/unord.set/missing_hash_specialization.verify.cpp
+++ b/libcxx/test/libcxx/containers/unord/unord.set/missing_hash_specialization.verify.cpp
@@ -48,11 +48,10 @@ int main(int, char**) {
     using Set = std::unordered_set<VT>;
     Set s; // expected-error at __hash_table:* {{the specified hash does not meet the Hash requirements}}
 
-
-  // FIXME: It would be great to suppress the below diagnostic all together.
-  //        but for now it's sufficient that it appears last. However there is
-  //        currently no way to test the order diagnostics are issued.
-  // expected-error@*:* {{call to implicitly-deleted default constructor of 'std::}}
+    // FIXME: It would be great to suppress the below diagnostic all together.
+    //        but for now it's sufficient that it appears last. However there is
+    //        currently no way to test the order diagnostics are issued.
+    // expected-error@*:* {{call to implicitly-deleted default constructor}}
   }
   {
     using Set = std::unordered_set<int, BadHashNoCopy>;
diff --git a/libcxx/test/libcxx/memory/compressed_pair/compressed_pair.pass.cpp b/libcxx/test/libcxx/memory/compressed_pair/compressed_pair.pass.cpp
deleted file mode 100644
index 8bc890a208d0c..0000000000000
--- a/libcxx/test/libcxx/memory/compressed_pair/compressed_pair.pass.cpp
+++ /dev/null
@@ -1,52 +0,0 @@
-//===----------------------------------------------------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-#include <assert.h>
-#include <memory>
-#include <new>
-
-#include "test_macros.h"
-
-typedef std::__compressed_pair<int, unsigned> IntPair;
-
-void test_constructor() {
-  IntPair value;
-  assert(value.first() == 0);
-  assert(value.second() == 0);
-
-  value.first() = 1;
-  value.second() = 2;
-  new (&value) IntPair;
-  assert(value.first() == 0);
-  assert(value.second() == 0);
-}
-
-void test_constructor_default_init() {
-  IntPair value;
-  value.first() = 1;
-  value.second() = 2;
-
-  new (&value) IntPair(std::__default_init_tag(), 3);
-  assert(value.first() == 1);
-  assert(value.second() == 3);
-
-  new (&value) IntPair(4, std::__default_init_tag());
-  assert(value.first() == 4);
-  assert(value.second() == 3);
-
-  new (&value) IntPair(std::__default_init_tag(), std::__default_init_tag());
-  assert(value.first() == 4);
-  assert(value.second() == 3);
-}
-
-int main(int, char**)
-{
-  test_constructor();
-  test_constructor_default_init();
-  return 0;
-}
diff --git a/libcxx/test/libcxx/utilities/memory/util.smartptr/util.smartptr.shared/libcxx.control_block_layout.pass.cpp b/libcxx/test/libcxx/utilities/memory/util.smartptr/util.smartptr.shared/libcxx.control_block_layout.pass.cpp
index 0af79eef4687a..9b90f1716f3b1 100644
--- a/libcxx/test/libcxx/utilities/memory/util.smartptr/util.smartptr.shared/libcxx.control_block_layout.pass.cpp
+++ b/libcxx/test/libcxx/utilities/memory/util.smartptr/util.smartptr.shared/libcxx.control_block_layout.pass.cpp
@@ -18,6 +18,7 @@
 #include <cassert>
 #include <cstddef>
 #include <memory>
+#include <tuple>
 #include <type_traits>
 #include <utility>
 
@@ -26,6 +27,44 @@
 
 #include "test_macros.h"
 
+struct value_init_tag {};
+
+template <class T, int _Idx, bool CanBeEmptyBase = std::is_empty<T>::value && !std::__libcpp_is_final<T>::value>
+struct compressed_pair_elem {
+  explicit compressed_pair_elem(value_init_tag) : value_() {}
+
+  template <class U>
+  explicit compressed_pair_elem(U&& u) : value_(std::forward<U>(u)) {}
+
+  T& get() { return value_; }
+
+private:
+  T value_;
+};
+
+template <class T, int _Idx>
+struct compressed_pair_elem<T, _Idx, true> : private T {
+  explicit compressed_pair_elem(value_init_tag) : T() {}
+
+  template <class U>
+  explicit compressed_pair_elem(U&& u) : T(std::forward<U>(u)) {}
+
+  T& get() { return *this; }
+};
+
+template <class T1, class T2>
+class compressed_pair : private compressed_pair_elem<T1, 0>, private compressed_pair_elem<T2, 1> {
+public:
+  using Base1 = compressed_pair_elem<T1, 0>;
+  using Base2 = compressed_pair_elem<T2, 1>;
+
+  template <class U1, class U2>
+  explicit compressed_pair(U1&& t1, U2&& t2) : Base1(std::forward<U1>(t1)), Base2(std::forward<U2>(t2)) {}
+
+  T1& first() { return static_cast<Base1&>(*this).get(); }
+  T2& second() { return static_cast<Base2&>(*this).get(); }
+};
+
 // This is the pre-C++20 implementation of the control block used by non-array
 // std::allocate_shared and std::make_shared. We keep it here so that we can
 // make sure our implementation is backwards compatible with it forever.
@@ -33,10 +72,8 @@
 // Of course, the class and its methods were renamed, but the size and layout
 // of the class should remain the same as the original implementation.
 template <class T, class Alloc>
-struct OldEmplaceControlBlock
-  : std::__shared_weak_count
-{
-  explicit OldEmplaceControlBlock(Alloc a) : data_(std::move(a), std::__value_init_tag()) { }
+struct OldEmplaceControlBlock : std::__shared_weak_count {
+  explicit OldEmplaceControlBlock(Alloc a) : data_(std::move(a), value_init_tag()) {}
   T* get_elem() noexcept { return std::addressof(data_.second()); }
   Alloc* get_alloc() noexcept { return std::addressof(data_.first()); }
 
@@ -49,7 +86,7 @@ struct OldEmplaceControlBlock
     // Not implemented
   }
 
-  std::__compressed_pair<Alloc, T> data_;
+  compressed_pair<Alloc, T> data_;
 };
 
 template <class T, template <class> class Alloc>
@@ -67,8 +104,8 @@ void test() {
 
   // 1. Check the stored object
   {
-    char const* old_elem = reinterpret_cast<char const*>(old.get_elem());
-    char const* new_elem = reinterpret_cast<char const*>(new_.__get_elem());
+    char const* old_elem      = reinterpret_cast<char const*>(old.get_elem());
+    char const* new_elem      = reinterpret_cast<char const*>(new_.__get_elem());
     std::ptrdiff_t old_offset = old_elem - reinterpret_cast<char const*>(&old);
     std::ptrdiff_t new_offset = new_elem - reinterpret_cast<char const*>(&new_);
     assert(new_offset == old_offset && "offset of stored element changed");
@@ -76,8 +113,8 @@ void test() {
 
   // 2. Check the allocator
   {
-    char const* old_alloc = reinterpret_cast<char const*>(old.get_alloc());
-    char const* new_alloc = reinterpret_cast<char const*>(new_.__get_alloc());
+    char const* old_alloc     = reinterpret_cast<char const*>(old.get_alloc());
+    char const* new_alloc     = reinterpret_cast<char const*>(new_.__get_alloc());
     std::ptrdiff_t old_offset = old_alloc - reinterpret_cast<char const*>(&old);
     std::ptrdiff_t new_offset = new_alloc - reinterpret_cast<char const*>(&new_);
     assert(new_offset == old_offset && "offset of allocator changed");
@@ -89,48 +126,64 @@ void test() {
 }
 
 // Object types to store in the control block
-struct TrivialEmptyType { };
-struct TrivialNonEmptyType { char c[11]; };
-struct FinalEmptyType final { };
+struct TrivialEmptyType {};
+
+struct TrivialNonEmptyType {
+  char c[11];
+};
+
+struct FinalEmptyType final {};
+
 struct NonTrivialType {
   char c[22];
-  NonTrivialType() : c{'x'} { }
+  NonTrivialType() : c{'x'} {}
+};
+
+struct VirtualFunctionType {
+  virtual ~VirtualFunctionType() {}
 };
 
 // Allocator types
 template <class T>
 struct TrivialEmptyAlloc {
-  using value_type = T;
+  using value_type    = T;
   TrivialEmptyAlloc() = default;
-  template <class U> TrivialEmptyAlloc(TrivialEmptyAlloc<U>) { }
+  template <class U>
+  TrivialEmptyAlloc(TrivialEmptyAlloc<U>) {}
   T* allocate(std::size_t) { return nullptr; }
-  void deallocate(T*, std::size_t) { }
+  void deallocate(T*, std::size_t) {}
 };
+
 template <class T>
 struct TrivialNonEmptyAlloc {
   char storage[77];
-  using value_type = T;
+  using value_type       = T;
   TrivialNonEmptyAlloc() = default;
-  template <class U> TrivialNonEmptyAlloc(TrivialNonEmptyAlloc<U>) { }
+  template <class U>
+  TrivialNonEmptyAlloc(TrivialNonEmptyAlloc<U>) {}
   T* allocate(std::size_t) { return nullptr; }
-  void deallocate(T*, std::size_t) { }
+  void deallocate(T*, std::size_t) {}
 };
+
 template <class T>
 struct FinalEmptyAlloc final {
-  using value_type = T;
+  using value_type  = T;
   FinalEmptyAlloc() = default;
-  template <class U> FinalEmptyAlloc(FinalEmptyAlloc<U>) { }
+  template <class U>
+  FinalEmptyAlloc(FinalEmptyAlloc<U>) {}
   T* allocate(std::size_t) { return nullptr; }
-  void deallocate(T*, std::size_t) { }
+  void deallocate(T*, std::size_t) {}
 };
+
 template <class T>
 struct NonTrivialAlloc {
   char storage[88];
   using value_type = T;
-  NonTrivialAlloc() { }
-  template <class U> NonTrivialAlloc(NonTrivialAlloc<U>) { }
+  NonTrivialAlloc() {}
+  template <class U>
+  NonTrivialAlloc(NonTrivialAlloc<U>) {}
   T* allocate(std::size_t) { return nullptr; }
-  void deallocate(T*, std::size_t) { }
+  void deallocate(T*, std::size_t) {}
 };
 
 int main(int, char**) {
@@ -145,15 +198,19 @@ int main(int, char**) {
   test<TrivialNonEmptyType, NonTrivialAlloc>();
 
   test<FinalEmptyType, TrivialEmptyAlloc>();
-  test<FinalEmptyType, TrivialNonEmptyAlloc>();
-  test<FinalEmptyType, FinalEmptyAlloc>();
-  test<FinalEmptyType, NonTrivialAlloc>();
+  // FinalEmptyType combined with TrivialNonEmptyAlloc, FinalEmptyAlloc or NonTrivialAlloc is known to have an ABI break
+  // between LLVM 18 and LLVM 19. It's been deemed not severe enough to cause actual breakage.
 
   test<NonTrivialType, TrivialEmptyAlloc>();
   test<NonTrivialType, TrivialNonEmptyAlloc>();
   test<NonTrivialType, FinalEmptyAlloc>();
   test<NonTrivialType, NonTrivialAlloc>();
 
+  test<VirtualFunctionType, TrivialEmptyAlloc>();
+  test<VirtualFunctionType, TrivialNonEmptyAlloc>();
+  test<VirtualFunctionType, FinalEmptyAlloc>();
+  test<VirtualFunctionType, NonTrivialAlloc>();
+
   // Test a few real world types just to make sure we didn't mess up badly somehow
   test<std::string, std::allocator>();
   test<int, std::allocator>();



More information about the libcxx-commits mailing list