[libcxx-commits] [libcxx] [libc++] Implement Tombstone Traits (PR #237502)

William Tran-Viet via libcxx-commits libcxx-commits at lists.llvm.org
Sat Oct 31 13:15:17 PDT 2026


https://github.com/smallp-o-p updated https://github.com/llvm/llvm-project/pull/237502

>From 524cd9f8a1ae830052969b9ebb215d72b042abbb Mon Sep 17 00:00:00 2001
From: Nikolas Klauser <nikolasklauser at berlin.de>
Date: Sun, 9 Jun 2024 10:35:22 +0200
Subject: [PATCH 01/12] [libc++] Add tombstone traits to use in optional,
 variant

---
 libcxx/include/CMakeLists.txt                 |   1 +
 libcxx/include/__configuration/abi.h          |   1 +
 .../include/__functional/reference_wrapper.h  |  24 +-
 libcxx/include/__memory/shared_ptr.h          |  25 +-
 libcxx/include/__memory/tombstone_traits.h    | 289 ++++++++++++++++++
 libcxx/include/__memory/unique_ptr.h          |  21 ++
 libcxx/include/__type_traits/enable_if.h      |   3 +
 libcxx/include/__type_traits/is_fundamental.h |   1 +
 libcxx/include/__utility/pair.h               |  22 ++
 libcxx/include/module.modulemap.in            |   4 +
 libcxx/include/string                         |  53 +++-
 libcxx/include/string_view                    |   9 +
 libcxx/src/locale.cpp                         |   2 +
 .../test/libcxx/transitive_includes/cxx03.csv |   1 +
 .../test/libcxx/transitive_includes/cxx11.csv |   1 +
 .../test/libcxx/transitive_includes/cxx14.csv |   1 +
 .../test/libcxx/transitive_includes/cxx17.csv |   1 +
 .../test/libcxx/transitive_includes/cxx20.csv |   2 +
 .../test/libcxx/transitive_includes/cxx23.csv |   4 +
 .../test/libcxx/transitive_includes/cxx26.csv |   4 +
 .../optional/tombstone_types.pass.cpp         |  68 +++++
 21 files changed, 525 insertions(+), 12 deletions(-)
 create mode 100644 libcxx/include/__memory/tombstone_traits.h
 create mode 100644 libcxx/test/std/utilities/optional/tombstone_types.pass.cpp

diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index fcb66d5fe2f48a..d5ffe939dba3fa 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -636,6 +636,7 @@ set(files
   __memory/swap_allocator.h
   __memory/temp_value.h
   __memory/temporary_buffer.h
+  __memory/tombstone_traits.h
   __memory/uninitialized_algorithms.h
   __memory/uninitialized_multidimensional_algorithms.h
   __memory/unique_ptr.h
diff --git a/libcxx/include/__configuration/abi.h b/libcxx/include/__configuration/abi.h
index 9343eacf393449..e637e217b5b8f7 100644
--- a/libcxx/include/__configuration/abi.h
+++ b/libcxx/include/__configuration/abi.h
@@ -86,6 +86,7 @@
 #  if defined(__FreeBSD__)
 #    define _LIBCPP_DEPRECATED_ABI_DISABLE_PAIR_TRIVIAL_COPY_CTOR
 #  endif
+
 #endif
 
 // We had some bugs where we use [[no_unique_address]] together with construct_at,
diff --git a/libcxx/include/__functional/reference_wrapper.h b/libcxx/include/__functional/reference_wrapper.h
index b1efd9f76d877b..d696e7c81e04f4 100644
--- a/libcxx/include/__functional/reference_wrapper.h
+++ b/libcxx/include/__functional/reference_wrapper.h
@@ -13,8 +13,10 @@
 #include <__compare/synth_three_way.h>
 #include <__concepts/convertible_to.h>
 #include <__config>
+#include <__cstddef/size_t.h>
 #include <__functional/weak_result_type.h>
 #include <__memory/addressof.h>
+#include <__memory/tombstone_traits.h>
 #include <__type_traits/common_reference.h>
 #include <__type_traits/desugars_to.h>
 #include <__type_traits/enable_if.h>
@@ -125,7 +127,27 @@ class reference_wrapper : public __weak_result_type<_Tp> {
 #if _LIBCPP_STD_VER >= 17
 template <class _Tp>
 reference_wrapper(_Tp&) -> reference_wrapper<_Tp>;
-#endif
+
+template <class _Tp>
+struct __tombstone_traits<reference_wrapper<_Tp>> {
+  // reference_wrapper<_Tp> is conceptually that same as _Tp& and can only be constructed from a _Tp&. Since references
+  // can never be null, reference_wrapper can also never be null, allowing us to use it as an invalid state.
+
+  template <class _Payload, size_t _Np>
+  struct __representation;
+
+  template <class _Payload>
+  struct __representation<_Payload, 0> {
+    template <class... _Args>
+    constexpr __representation(_Args&&... __args) : __payload_(std::forward<_Args>(__args)...), __value_(nullptr) {}
+
+    bool __is_tombstone() { return __value_ == nullptr; }
+
+    _LIBCPP_NO_UNIQUE_ADDRESS _Payload __payload_;
+    _Tp* __value_;
+  };
+};
+#endif // _LIBCPP_STD_VER >= 17
 
 template <class _Tp>
 [[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI
diff --git a/libcxx/include/__memory/shared_ptr.h b/libcxx/include/__memory/shared_ptr.h
index 0db58b37a6288b..39749416787685 100644
--- a/libcxx/include/__memory/shared_ptr.h
+++ b/libcxx/include/__memory/shared_ptr.h
@@ -33,6 +33,7 @@
 #include <__memory/destroy.h>
 #include <__memory/pointer_traits.h>
 #include <__memory/shared_count.h>
+#include <__memory/tombstone_traits.h>
 #include <__memory/uninitialized_algorithms.h>
 #include <__memory/uninitialized_multidimensional_algorithms.h>
 #include <__memory/unique_ptr.h>
@@ -652,14 +653,25 @@ class _LIBCPP_SHARED_PTR_TRIVIAL_ABI shared_ptr {
   friend class shared_ptr;
   template <class _Up>
   friend class weak_ptr;
+
+  friend struct __tombstone_traits<shared_ptr<_Tp> >;
 };
 
-#if _LIBCPP_STD_VER >= 17
+#if _LIBCPP_STD_VER >= 17 && 0
 template <class _Tp>
 shared_ptr(weak_ptr<_Tp>) -> shared_ptr<_Tp>;
 template <class _Tp, class _Dp>
 shared_ptr(unique_ptr<_Tp, _Dp>) -> shared_ptr<_Tp>;
-#endif
+
+template <class _Tp>
+struct __tombstone_traits<shared_ptr<_Tp>> {
+  static constexpr auto __disengaged_value_ =
+      __tombstone_traits_assume_aligned_pointer<__shared_weak_count*>::__disengaged_value_;
+  static constexpr size_t __is_disengaged_offset_ =
+      __builtin_offsetof(shared_ptr<_Tp>, __cntrl_) +
+      __tombstone_traits_assume_aligned_pointer<__shared_weak_count*>::__is_disengaged_offset_;
+};
+#endif // _LIBCPP_STD_VER >= 17
 
 //
 // std::allocate_shared and std::make_shared
@@ -1295,12 +1307,19 @@ class _LIBCPP_SHARED_PTR_TRIVIAL_ABI weak_ptr {
   friend class weak_ptr;
   template <class _Up>
   friend class shared_ptr;
+
+  friend struct __tombstone_traits<weak_ptr<_Tp> >;
 };
 
 #if _LIBCPP_STD_VER >= 17
 template <class _Tp>
 weak_ptr(shared_ptr<_Tp>) -> weak_ptr<_Tp>;
-#endif
+
+template <class _Tp>
+struct __tombstone_traits<weak_ptr<_Tp>> {
+
+};
+#endif // _LIBCPP_STD_VER >= 17
 
 template <class _Tp>
 inline _LIBCPP_HIDE_FROM_ABI void swap(weak_ptr<_Tp>& __x, weak_ptr<_Tp>& __y) _NOEXCEPT {
diff --git a/libcxx/include/__memory/tombstone_traits.h b/libcxx/include/__memory/tombstone_traits.h
new file mode 100644
index 00000000000000..f354a25e69df53
--- /dev/null
+++ b/libcxx/include/__memory/tombstone_traits.h
@@ -0,0 +1,289 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef _LIBCPP___TYPE_TRAITS_TOMBSTONE_TRAITS_H
+#define _LIBCPP___TYPE_TRAITS_TOMBSTONE_TRAITS_H
+
+#include <__assert>
+#include <__config>
+#include <__cstddef/size_t.h>
+#include <__memory/construct_at.h>
+#include <__type_traits/datasizeof.h>
+#include <__type_traits/enable_if.h>
+#include <__type_traits/is_constant_evaluated.h>
+#include <__type_traits/is_fundamental.h>
+#include <__type_traits/is_integral.h>
+#include <__type_traits/is_trivial.h>
+#include <__type_traits/is_trivially_destructible.h>
+#include <__type_traits/remove_cv.h>
+#include <__type_traits/void_t.h>
+#include <__utility/forward.h>
+#include <__utility/in_place.h>
+#include <__utility/move.h>
+#include <cstdint>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+#  pragma GCC system_header
+#endif
+
+_LIBCPP_PUSH_MACROS
+#include <__undef_macros>
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+template <class>
+struct __tombstone_traits;
+
+#if _LIBCPP_STD_VER >= 17
+
+// bools always have exactly one bit set. If there is more than one set it's disengaged.
+template <>
+struct __tombstone_traits<bool> {
+  template <class _Payload, size_t _Np>
+  struct __representation {
+    template <class... _Args>
+    constexpr __representation(_Args&&... __args) : __payload_(std::forward<_Args>(__args)...), __value_(_Np + 2) {}
+
+    bool __is_tombstone() { return __value_ == _Np + 2; }
+
+    _LIBCPP_NO_UNIQUE_ADDRESS _Payload __payload_;
+    unsigned char __value_;
+  };
+
+  static constexpr size_t __max_tombstone = 254;
+};
+
+template <size_t _PaddingSize>
+struct __padding {
+  char __padding_[_PaddingSize];
+};
+
+template <>
+struct __padding<0> {};
+
+// Pointers to a type that has an alignment greater than one always have the lowest bits set to zero. This is a single
+// implementation for all the places where we have an invalid pointer to _Tp as the "invalid state" representation.
+template <class _Tp>
+struct __tombstone_traits_assume_aligned_pointer {
+  template <class _Payload, size_t _Np>
+  struct __representation {
+    template <class... _Args>
+    constexpr __representation(_Args&&... __args) : __payload_(std::forward<_Args>(__args)...), __value_(_Np + 1) {}
+
+    bool __is_tombstone() { return __value_ == _Np + 1; }
+
+    _LIBCPP_NO_UNIQUE_ADDRESS _Payload __payload_;
+    _LIBCPP_NO_UNIQUE_ADDRESS __padding<sizeof(_Tp*) - 1 - __datasizeof_v<_Payload>> __padding_;
+    unsigned char __value_;
+  };
+
+  static constexpr size_t __max_tombstone = 0; // TODO: Calculate this correctly
+};
+
+// TODO: Look into
+// - filesystem::directory_iterator
+// - vector<T> with alignof(T) == 1
+// - string_view (basic_string_view<T> works with alignof(T) >= 2)
+
+// This is constrained on fundamental types because we might not always know the alignment of a user-defined type.
+// For example, in one TU there may only be a forward declaration and in another there is already the definition
+// available. If we made this optimization conditional on the completeness of the type this would result in a non-benign
+// ODR violation.
+template <class _Tp>
+struct __tombstone_traits<__enable_specialization_if<is_fundamental_v<_Tp> && alignof(_Tp) >= 2, _Tp*>>
+    : __tombstone_traits_assume_aligned_pointer<_Tp> {};
+
+template <class _Tp>
+struct __tombstone_traits<_Tp**> : __tombstone_traits_assume_aligned_pointer<_Tp*> {
+  static_assert(alignof(_Tp*) >= 2, "alignment of a pointer isn't at least 2!?");
+};
+
+inline constexpr struct __init_engaged_t {
+} __init_engaged;
+inline constexpr struct __init_disengaged_t {
+} __init_disengaged;
+
+template <class _Tp, class = void>
+struct alignas(_Tp) __dummy_payload {
+  char __data_[__datasizeof_v<_Tp>];
+
+  static_assert(alignof(__dummy_payload) == alignof(_Tp));
+  static_assert(sizeof(__dummy_payload) == sizeof(_Tp));
+  static_assert(__datasizeof_v<__dummy_payload> == __datasizeof_v<_Tp>);
+};
+
+template <class _Tp>
+struct alignas(_Tp) __dummy_payload<_Tp, __enable_if_t<__datasizeof_v<_Tp> == 0>> {};
+
+template <class _Tp, class _Payload, bool = is_trivially_destructible_v<_Tp> && is_trivially_destructible_v<_Payload>>
+union _MaybeTombstone {
+  using _Tombstone      = __tombstone_traits<_Tp>::template __representation<_Payload, 0>;
+  using _DummyTombstone = __tombstone_traits<_Tp>::template __representation<__dummy_payload<_Payload>, 0>;
+
+  _Tp __value_;
+  _Tombstone __tombstone_;
+
+  template <class... _Args>
+  explicit constexpr _MaybeTombstone(__init_disengaged_t, _Args&&... __args)
+      : __tombstone_(std::forward<_Args>(__args)...) {}
+
+  template <class... _Args>
+  explicit constexpr _MaybeTombstone(__init_engaged_t, _Args&&... __args) : __value_(std::forward<_Args>(__args)...) {}
+
+  _MaybeTombstone(const _MaybeTombstone&)            = default;
+  _MaybeTombstone(_MaybeTombstone&&)                 = default;
+  _MaybeTombstone& operator=(const _MaybeTombstone&) = default;
+  _MaybeTombstone& operator=(_MaybeTombstone&&)      = default;
+
+  _LIBCPP_HIDE_FROM_ABI constexpr bool __is_engaged() const noexcept {
+    if consteval {
+      return __builtin_is_within_lifetime(&__value_);
+    } else {
+      _DummyTombstone __dummy;
+      static_assert(sizeof(_DummyTombstone) <= sizeof(*this));
+      __builtin_memcpy(&__dummy, this, sizeof(_DummyTombstone));
+
+      return !__dummy.__is_tombstone();
+    }
+  }
+
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 ~_MaybeTombstone() {
+    if (__is_engaged()) {
+      std::destroy_at(&__value_);
+    } else {
+      std::destroy_at(&__tombstone_);
+    }
+  }
+};
+
+template <class _Tp, class _Payload>
+union _MaybeTombstone<_Tp, _Payload, true> {
+  using _Tombstone      = __tombstone_traits<_Tp>::template __representation<_Payload, 0>;
+  using _DummyTombstone = __tombstone_traits<_Tp>::template __representation<__dummy_payload<_Payload>, 0>;
+
+  _Tp __value_;
+  _Tombstone __tombstone_;
+
+  template <class... _Args>
+  explicit constexpr _MaybeTombstone(__init_disengaged_t, _Args&&... __args)
+      : __tombstone_(std::forward<_Args>(__args)...) {}
+
+  template <class... _Args>
+  explicit constexpr _MaybeTombstone(__init_engaged_t, _Args&&... __args) : __value_(std::forward<_Args>(__args)...) {}
+
+  _MaybeTombstone(const _MaybeTombstone&)            = default;
+  _MaybeTombstone(_MaybeTombstone&&)                 = default;
+  _MaybeTombstone& operator=(const _MaybeTombstone&) = default;
+  _MaybeTombstone& operator=(_MaybeTombstone&&)      = default;
+
+  _LIBCPP_HIDE_FROM_ABI constexpr bool __is_engaged() const noexcept {
+    if consteval {
+      return __builtin_is_within_lifetime(&__value_);
+    } else {
+      _DummyTombstone __dummy;
+      static_assert(sizeof(_DummyTombstone) <= sizeof(*this));
+      __builtin_memcpy(&__dummy, this, sizeof(_DummyTombstone));
+
+      return !__dummy.__is_tombstone();
+    }
+  }
+
+  _LIBCPP_CONSTEXPR_SINCE_CXX20 ~_MaybeTombstone() = default;
+};
+
+template <class _Tp, class _Payload>
+struct __tombstoned_value final {
+  using _Tombstone      = __tombstone_traits<_Tp>::template __representation<_Payload, 0>;
+  using _DummyTombstone = __tombstone_traits<_Tp>::template __representation<__dummy_payload<_Payload>, 0>;
+
+  static_assert(__builtin_is_implicit_lifetime(_DummyTombstone));
+  static_assert(sizeof(_Tombstone) == sizeof(_DummyTombstone));
+  static_assert(alignof(_Tombstone) == alignof(_DummyTombstone));
+  static_assert(__datasizeof_v<_Tombstone> == __datasizeof_v<_DummyTombstone>);
+  static_assert(sizeof(_Tombstone) <= sizeof(_Tp), "Trying to use tobstone which can't hold T");
+
+  _MaybeTombstone<_Tp, _Payload> __data_;
+
+  template <class... _Args>
+  explicit _LIBCPP_HIDE_FROM_ABI constexpr __tombstoned_value(__init_disengaged_t, _Args&&... __args)
+      : __data_(__init_disengaged, std::forward<_Args>(__args)...) {}
+
+  template <class... _Args>
+  explicit _LIBCPP_HIDE_FROM_ABI constexpr __tombstoned_value(__init_engaged_t, _Args&&... __args)
+      : __data_(__init_engaged, std::forward<_Args>(__args)...) {}
+
+  _LIBCPP_HIDE_FROM_ABI constexpr bool __is_engaged() const noexcept { return __data_.__is_engaged(); }
+
+  _LIBCPP_HIDE_FROM_ABI constexpr auto&& __get_value() & noexcept {
+    _LIBCPP_ASSERT_INTERNAL(__is_engaged(), "Trying to get the value of a disenagaged tombstoned value");
+    return __data_.__value_;
+  }
+
+  _LIBCPP_HIDE_FROM_ABI constexpr auto&& __get_value() const& noexcept {
+    _LIBCPP_ASSERT_INTERNAL(__is_engaged(), "Trying to get the value of a disenagaged tombstoned value");
+    return __data_.__value_;
+  }
+
+  _LIBCPP_HIDE_FROM_ABI constexpr auto&& __get_value() && noexcept {
+    _LIBCPP_ASSERT_INTERNAL(__is_engaged(), "Trying to get the value of a disenagaged tombstoned value");
+    return std::move(__data_.__value_);
+  }
+
+  _LIBCPP_HIDE_FROM_ABI constexpr auto&& __get_value() const&& noexcept {
+    _LIBCPP_ASSERT_INTERNAL(__is_engaged(), "Trying to get the value of a disenagaged tombstoned value");
+    return std::move(__data_.__value_);
+  }
+
+  _LIBCPP_HIDE_FROM_ABI constexpr auto&& __get_payload() & noexcept {
+    _LIBCPP_ASSERT_INTERNAL(!__is_engaged(), "Trying to get the payload of an enagaged tombstoned value");
+    return __data_.__tombstone_.__payload_;
+  }
+
+  _LIBCPP_HIDE_FROM_ABI constexpr auto&& __get_payload() const& noexcept {
+    _LIBCPP_ASSERT_INTERNAL(!__is_engaged(), "Trying to get the payload of an enagaged tombstoned value");
+    return __data_.__tombstone_.__payload_;
+  }
+
+  _LIBCPP_HIDE_FROM_ABI constexpr auto&& __get_payload() && noexcept {
+    _LIBCPP_ASSERT_INTERNAL(!__is_engaged(), "Trying to get the payload of an enagaged tombstoned value");
+    return std::move(__data_.__tombstone_.__payload_);
+  }
+
+  _LIBCPP_HIDE_FROM_ABI constexpr auto&& __get_payload() const&& noexcept {
+    _LIBCPP_ASSERT_INTERNAL(!__is_engaged(), "Trying to get the payload of an enagaged tombstoned value");
+    return std::move(__data_.__tombstone_.__payload_);
+  }
+
+  template <class... _Args>
+  _LIBCPP_HIDE_FROM_ABI constexpr void __engage(in_place_t, _Args&&... __args) {
+    _LIBCPP_ASSERT_INTERNAL(!__is_engaged(), "Trying to enage a already engaged tombstoned value");
+    std::destroy_at(&__data_.__tombstone_);
+    std::__construct_at(&__data_.__value_, std::forward<_Args>(__args)...);
+  }
+
+  template <class... _Args>
+  _LIBCPP_HIDE_FROM_ABI constexpr void __disengage(in_place_t, _Args&&... __args) {
+    _LIBCPP_ASSERT_INTERNAL(!__is_engaged(), "Trying to disenage a disengaged tombstoned value");
+    std::destroy_at(&__data_.__value_);
+    std::__construct_at(&__data_.__tombstone_, std::forward<_Args>(__args)...);
+  }
+};
+
+template <class _Tp, class = void>
+inline constexpr bool __has_tombstone_v = false;
+
+template <class _Tp>
+inline constexpr bool __has_tombstone_v<_Tp, void_t<decltype(sizeof(__tombstone_traits<_Tp>))>> = true;
+
+#endif // _LIBCPP_STD_VER >= 17
+
+_LIBCPP_END_NAMESPACE_STD
+
+_LIBCPP_POP_MACROS
+
+#endif // _LIBCPP___TYPE_TRAITS_TOMBSTONE_TRAITS_H
diff --git a/libcxx/include/__memory/unique_ptr.h b/libcxx/include/__memory/unique_ptr.h
index 01820aa52b5335..96e53c80487485 100644
--- a/libcxx/include/__memory/unique_ptr.h
+++ b/libcxx/include/__memory/unique_ptr.h
@@ -24,6 +24,7 @@
 #include <__memory/auto_ptr.h>
 #include <__memory/compressed_pair.h>
 #include <__memory/pointer_traits.h>
+#include <__memory/tombstone_traits.h>
 #include <__type_traits/add_reference.h>
 #include <__type_traits/common_type.h>
 #include <__type_traits/conditional.h>
@@ -274,8 +275,18 @@ class _LIBCPP_UNIQUE_PTR_TRIVIAL_ABI unique_ptr {
     swap(__ptr_, __u.__ptr_);
     swap(__deleter_, __u.__deleter_);
   }
+
+  friend struct __tombstone_traits<unique_ptr>;
 };
 
+#if _LIBCPP_STD_VER >= 17
+template <class _Tp>
+struct __tombstone_traits<__enable_specialization_if<__has_tombstone_v<_Tp*>, unique_ptr<_Tp>>>
+    : __tombstone_traits<_Tp*> {
+  static_assert(__builtin_offsetof(unique_ptr<_Tp>, __ptr_) == 0, "Unexpected pointer offset");
+};
+#endif // _LIBCPP_STD_VER >= 17
+
 // Bounds checking in unique_ptr<T[]>
 // ==================================
 //
@@ -577,8 +588,18 @@ class _LIBCPP_UNIQUE_PTR_TRIVIAL_ABI unique_ptr<_Tp[], _Dp> {
     swap(__deleter_, __u.__deleter_);
     swap(__checker_, __u.__checker_);
   }
+
+  friend struct __tombstone_traits<unique_ptr>;
 };
 
+#if _LIBCPP_STD_VER >= 17
+template <class _Tp>
+struct __tombstone_traits<__enable_specialization_if<__has_tombstone_v<_Tp*>, unique_ptr<_Tp[]>>>
+    : __tombstone_traits<_Tp*> {
+  static_assert(__builtin_offsetof(unique_ptr<_Tp[]>, __ptr_) == 0, "Unexpected pointer offset");
+};
+#endif
+
 template <class _Tp, class _Dp, __enable_if_t<__is_swappable_v<_Dp>, int> = 0>
 inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 void
 swap(unique_ptr<_Tp, _Dp>& __x, unique_ptr<_Tp, _Dp>& __y) _NOEXCEPT {
diff --git a/libcxx/include/__type_traits/enable_if.h b/libcxx/include/__type_traits/enable_if.h
index ae1af6ebf17d90..b22d4e9dd68378 100644
--- a/libcxx/include/__type_traits/enable_if.h
+++ b/libcxx/include/__type_traits/enable_if.h
@@ -38,6 +38,9 @@ template <bool _Bp, class _Tp = void>
 using enable_if_t = typename enable_if<_Bp, _Tp>::type;
 #endif
 
+template <bool _Bp, class _Tp, class = __enable_if_t<_Bp> >
+using __enable_specialization_if = _Tp;
+
 _LIBCPP_END_NAMESPACE_STD
 
 #endif // _LIBCPP___TYPE_TRAITS_ENABLE_IF_H
diff --git a/libcxx/include/__type_traits/is_fundamental.h b/libcxx/include/__type_traits/is_fundamental.h
index 6236553cfb836b..9449289368d755 100644
--- a/libcxx/include/__type_traits/is_fundamental.h
+++ b/libcxx/include/__type_traits/is_fundamental.h
@@ -11,6 +11,7 @@
 
 #include <__config>
 #include <__type_traits/integral_constant.h>
+#include <__type_traits/is_arithmetic.h>
 #include <__type_traits/is_null_pointer.h>
 #include <__type_traits/is_void.h>
 
diff --git a/libcxx/include/__utility/pair.h b/libcxx/include/__utility/pair.h
index a65c178a9f0360..6d5b3ffa274343 100644
--- a/libcxx/include/__utility/pair.h
+++ b/libcxx/include/__utility/pair.h
@@ -18,6 +18,7 @@
 #include <__fwd/array.h>
 #include <__fwd/pair.h>
 #include <__fwd/tuple.h>
+#include <__memory/tombstone_traits.h>
 #include <__tuple/tuple_like_no_subrange.h>
 #include <__tuple/tuple_size.h>
 #include <__type_traits/common_reference.h>
@@ -433,6 +434,27 @@ struct pair
 #if _LIBCPP_STD_VER >= 17
 template <class _T1, class _T2>
 pair(_T1, _T2) -> pair<_T1, _T2>;
+#endif // _LIBCPP_STD_VER >= 17
+
+#if 0
+template <class _Tp, class _Up, bool __first_tombstone>
+struct __tombstone_traits_pair;
+
+template <class _Tp, class _Up>
+struct __tombstone_traits_pair<_Tp, _Up, true> : __tombstone_traits<_Tp> {
+  static_assert(__builtin_offsetof(pair<_Tp, _Up>, first) == 0);
+};
+
+template <class _Tp, class _Up>
+struct __tombstone_traits_pair<_Tp, _Up, false> {
+  static constexpr auto __disengaged_value_ = __tombstone_traits<_Up>::__disengaged_value_;
+  static constexpr size_t __is_disengaged_offset_ =
+      __builtin_offsetof(pair<_Tp, _Up>, second) + __tombstone_traits<_Up>::__is_disengaged_offset_;
+};
+
+template <class _Tp, class _Up>
+struct __tombstone_traits<__enable_specialization_if<__has_tombstone_v<_Tp> || __has_tombstone_v<_Up>, pair<_Tp, _Up>>>
+    : __tombstone_traits_pair<_Tp, _Up, __has_tombstone_v<_Tp>> {};
 #endif
 
 // [pairs.spec], specialized algorithms
diff --git a/libcxx/include/module.modulemap.in b/libcxx/include/module.modulemap.in
index 6ca65ba556fa1c..d031a5dc4f47fd 100644
--- a/libcxx/include/module.modulemap.in
+++ b/libcxx/include/module.modulemap.in
@@ -1734,6 +1734,10 @@ module std {
       header "__memory/temporary_buffer.h"
       export std.utility.pair // return type of std::get_temporary_buffer()
     }
+    module tombstone_traits                   {
+      header "__memory/tombstone_traits.h"
+      export std.utility.piecewise_construct
+    }
     module uninitialized_algorithms {
       header "__memory/uninitialized_algorithms.h"
       export std.memory.destroy
diff --git a/libcxx/include/string b/libcxx/include/string
index 33175c115fd10c..a693ddf47d37fa 100644
--- a/libcxx/include/string
+++ b/libcxx/include/string
@@ -620,6 +620,7 @@ basic_string<char32_t> operator""s( const char32_t *str, size_t len );
 #  include <__memory/noexcept_move_assign_container.h>
 #  include <__memory/pointer_traits.h>
 #  include <__memory/swap_allocator.h>
+#  include <__memory/tombstone_traits.h>
 #  include <__memory_resource/polymorphic_allocator.h>
 #  include <__ranges/access.h>
 #  include <__ranges/concepts.h>
@@ -724,14 +725,6 @@ inline const bool __can_be_converted_to_string_view_v =
 struct __uninitialized_size_tag {};
 struct __init_with_sentinel_tag {};
 
-template <size_t _PaddingSize>
-struct __padding {
-  char __padding_[_PaddingSize];
-};
-
-template <>
-struct __padding<0> {};
-
 template <class _CharT, class _Traits, class _Allocator>
 class _LIBCPP_WARN_UNUSED basic_string {
 public:
@@ -2496,6 +2489,10 @@ private:
 #  ifdef _LIBCPP_BUILDING_LIBRARY
   void __init(const value_type* __s, size_type __sz, size_type __reserve);
 #  endif
+
+#if _LIBCPP_STD_VER >= 17
+  friend __tombstone_traits<basic_string>;
+#endif
 };
 
 // These declarations must appear before any functions are implicitly used
@@ -2586,6 +2583,46 @@ basic_string(from_range_t, _Range&&, _Allocator = _Allocator())
     -> basic_string<ranges::range_value_t<_Range>, char_traits<ranges::range_value_t<_Range>>, _Allocator>;
 #  endif
 
+#  if _LIBCPP_STD_VER >= 17
+template <class _CharT, class _Traits, class _Allocator>
+struct __tombstone_traits<basic_string<_CharT, _Traits, _Allocator>> {
+  // If `string` is in the `__short` representation, the size can never be larger than `__min_cap`. 65 sets the bit
+  // for the small string representation and the size to 32. The maximum size is
+  // `sizeof(size_type) * 2 + sizeof(pointer)`, which is never greater than 24.
+
+  using _String = basic_string<_CharT, _Traits, _Allocator>;
+
+  static_assert(_String::__min_cap <= 32, "__min_cap is too big!");
+
+  template <class _Payload, size_t _Np>
+  struct __representation {
+    _LIBCPP_DIAGNOSTIC_PUSH
+    _LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wreorder-ctor")
+    template <class... _Args>
+    constexpr __representation(_Args&&... __args)
+        : __payload_(std::forward<_Args>(__args)...), __is_long_(0), __size_(_String::__min_cap + _Np) {}
+    _LIBCPP_DIAGNOSTIC_POP
+
+    bool __is_tombstone() { return __size_ == _String::__min_cap + _Np; }
+
+#    ifndef _LIBCPP_ABI_ALTERNATE_STRING_LAYOUT
+    struct _LIBCPP_PACKED {
+      unsigned char __is_long_ : 1;
+      unsigned char __size_    : 7;
+    };
+#    endif
+    _LIBCPP_NO_UNIQUE_ADDRESS _Payload __payload_;
+#    ifdef _LIBCPP_ABI_ALTERNATE_STRING_LAYOUT
+    _LIBCPP_NO_UNIQUE_ADDRESS
+    __padding<sizeof(_String::value_type) * (_String::__min_cap + 1) - 1 - __datasizeof_v<_Payload>>
+        __padding_;
+    unsigned char __size_    : 7;
+    unsigned char __is_long_ : 1;
+#    endif
+  };
+};
+#  endif                       // _LIBCPP_STD_VER >= 17
+
 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) {
diff --git a/libcxx/include/string_view b/libcxx/include/string_view
index 736ac391a7979b..89f88aabc3dbf2 100644
--- a/libcxx/include/string_view
+++ b/libcxx/include/string_view
@@ -227,6 +227,7 @@ namespace std {
 #  include <__iterator/reverse_iterator.h>
 #  include <__iterator/wrap_iter.h>
 #  include <__memory/pointer_traits.h>
+#  include <__memory/tombstone_traits.h>
 #  include <__ranges/concepts.h>
 #  include <__ranges/data.h>
 #  include <__ranges/enable_borrowed_range.h>
@@ -735,6 +736,14 @@ template <class _CharT, class _Traits>
 inline constexpr bool ranges::enable_borrowed_range<basic_string_view<_CharT, _Traits> > = true;
 #  endif // _LIBCPP_STD_VER >= 20
 
+#if _LIBCPP_STD_VER >= 17
+template <class _CharT, class _Traits>
+struct __tombstone_traits<__enable_specialization_if<alignof(_CharT) >= 2, basic_string_view<_CharT, _Traits>>>
+    : __tombstone_traits_assume_aligned_pointer<const _CharT*> {
+  static_assert(__builtin_offsetof(basic_string_view<_CharT, _Traits>, __data_) == 0);
+};
+#endif
+
 // [string.view.deduct]
 
 #  if _LIBCPP_STD_VER >= 20
diff --git a/libcxx/src/locale.cpp b/libcxx/src/locale.cpp
index 7795e9eab2fc7b..495c61696ccfdd 100644
--- a/libcxx/src/locale.cpp
+++ b/libcxx/src/locale.cpp
@@ -142,6 +142,8 @@ class _LIBCPP_HIDDEN locale::__imp : public facet {
   void install_from(const __imp& other);
 };
 
+static_assert(alignof(locale::__imp) == alignof(void*), "__tombstone_traits alignment is wrong!");
+
 locale::__imp::__imp(size_t refs) : facet(refs), facets_(N), name_("C") {
   facets_.clear();
   install(&make<std::collate<char> >(1u));
diff --git a/libcxx/test/libcxx/transitive_includes/cxx03.csv b/libcxx/test/libcxx/transitive_includes/cxx03.csv
index 201fc2f36bf482..929ba564d4381f 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx03.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx03.csv
@@ -234,6 +234,7 @@ experimental/iterator tuple
 experimental/iterator typeinfo
 experimental/iterator version
 experimental/memory cstdint
+experimental/memory cstdlib
 experimental/memory cstring
 experimental/memory version
 experimental/propagate_const version
diff --git a/libcxx/test/libcxx/transitive_includes/cxx11.csv b/libcxx/test/libcxx/transitive_includes/cxx11.csv
index ab8791f9aa0747..adf7ebf2d7c80d 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx11.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx11.csv
@@ -234,6 +234,7 @@ experimental/iterator tuple
 experimental/iterator typeinfo
 experimental/iterator version
 experimental/memory cstdint
+experimental/memory cstdlib
 experimental/memory cstring
 experimental/memory version
 experimental/propagate_const version
diff --git a/libcxx/test/libcxx/transitive_includes/cxx14.csv b/libcxx/test/libcxx/transitive_includes/cxx14.csv
index 3d5030b5644e2b..c1274500243f96 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx14.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx14.csv
@@ -234,6 +234,7 @@ experimental/iterator tuple
 experimental/iterator typeinfo
 experimental/iterator version
 experimental/memory cstdint
+experimental/memory cstdlib
 experimental/memory cstring
 experimental/memory version
 experimental/propagate_const version
diff --git a/libcxx/test/libcxx/transitive_includes/cxx17.csv b/libcxx/test/libcxx/transitive_includes/cxx17.csv
index 8e3b1de5efd7ee..0896b2f1b72673 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx17.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx17.csv
@@ -243,6 +243,7 @@ experimental/iterator tuple
 experimental/iterator typeinfo
 experimental/iterator version
 experimental/memory cstdint
+experimental/memory cstdlib
 experimental/memory cstring
 experimental/memory version
 experimental/propagate_const version
diff --git a/libcxx/test/libcxx/transitive_includes/cxx20.csv b/libcxx/test/libcxx/transitive_includes/cxx20.csv
index b9d1dd17aa016f..4ea0167247c080 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx20.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx20.csv
@@ -196,6 +196,7 @@ condition_variable typeinfo
 condition_variable version
 coroutine compare
 coroutine cstdint
+coroutine cstdlib
 coroutine cstring
 coroutine limits
 coroutine version
@@ -278,6 +279,7 @@ experimental/iterator typeinfo
 experimental/iterator variant
 experimental/iterator version
 experimental/memory cstdint
+experimental/memory cstdlib
 experimental/memory cstring
 experimental/memory version
 experimental/propagate_const version
diff --git a/libcxx/test/libcxx/transitive_includes/cxx23.csv b/libcxx/test/libcxx/transitive_includes/cxx23.csv
index 83125257f35f54..75120224ed18eb 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx23.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx23.csv
@@ -199,6 +199,7 @@ coroutine compare
 coroutine cstdint
 coroutine cstring
 coroutine limits
+coroutine new
 coroutine version
 cstddef version
 ctgmath bitset
@@ -282,6 +283,7 @@ experimental/iterator variant
 experimental/iterator version
 experimental/memory cstdint
 experimental/memory cstring
+experimental/memory new
 experimental/memory version
 experimental/propagate_const version
 experimental/simd cstdint
@@ -295,6 +297,7 @@ experimental/utility compare
 experimental/utility cstdint
 experimental/utility initializer_list
 experimental/utility limits
+experimental/utility new
 experimental/utility utility
 experimental/utility version
 filesystem cctype
@@ -1097,6 +1100,7 @@ utility compare
 utility cstdint
 utility initializer_list
 utility limits
+utility new
 utility version
 valarray cmath
 valarray cstdint
diff --git a/libcxx/test/libcxx/transitive_includes/cxx26.csv b/libcxx/test/libcxx/transitive_includes/cxx26.csv
index 229e85afd106b7..cb99de928efcc3 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx26.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx26.csv
@@ -196,6 +196,7 @@ coroutine compare
 coroutine cstdint
 coroutine cstring
 coroutine limits
+coroutine new
 coroutine version
 cstddef version
 ctgmath bitset
@@ -279,6 +280,7 @@ experimental/iterator variant
 experimental/iterator version
 experimental/memory cstdint
 experimental/memory cstring
+experimental/memory new
 experimental/memory version
 experimental/propagate_const version
 experimental/simd cstdint
@@ -293,6 +295,7 @@ experimental/utility cstdint
 experimental/utility cstring
 experimental/utility initializer_list
 experimental/utility limits
+experimental/utility new
 experimental/utility utility
 experimental/utility version
 filesystem cctype
@@ -1090,6 +1093,7 @@ utility cstdint
 utility cstring
 utility initializer_list
 utility limits
+utility new
 utility version
 valarray cmath
 valarray cstdint
diff --git a/libcxx/test/std/utilities/optional/tombstone_types.pass.cpp b/libcxx/test/std/utilities/optional/tombstone_types.pass.cpp
new file mode 100644
index 00000000000000..43cab57d250713
--- /dev/null
+++ b/libcxx/test/std/utilities/optional/tombstone_types.pass.cpp
@@ -0,0 +1,68 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14
+// <optional>
+
+#include <cassert>
+#include <optional>
+#include <string>
+
+#include "test_macros.h"
+
+TEST_CONSTEXPR_CXX20 bool test() {
+  {
+    std::optional<bool> opt;
+    assert(!opt);
+    opt = true;
+    assert(opt);
+    assert(*opt);
+    opt = false;
+    assert(opt);
+    assert(!*opt);
+    opt.reset();
+    assert(!opt);
+  }
+
+  {
+    std::optional<std::string> opt;
+    assert(!opt);
+    opt = "";
+    assert(opt);
+    assert(*opt == "");
+    opt = "23 letter string to SSO";
+    assert(opt);
+    assert(*opt == "23 letter string to SSO");
+    opt.reset();
+    assert(!opt);
+  }
+
+  {
+    int i;
+    int j;
+    std::optional<int*> opt;
+    assert(!opt);
+    opt = &i;
+    assert(opt);
+    assert(*opt == &i);
+    opt = &j;
+    assert(opt);
+    assert(*opt == &j);
+    opt.reset();
+    assert(!opt);
+  }
+
+  return true;
+}
+
+int main(int, char**) {
+  test();
+#if TEST_STD_VER >= 20
+  static_assert(test());
+#endif
+}

>From 980894cc871f9edba4d2de1d8eda0a35cc6003ef Mon Sep 17 00:00:00 2001
From: William Tran-Viet <wtranviet at proton.me>
Date: Fri, 30 Oct 2026 22:53:21 -0400
Subject: [PATCH 02/12] Fix some typos

---
 libcxx/include/__memory/tombstone_traits.h | 16 +++++++++-------
 1 file changed, 9 insertions(+), 7 deletions(-)

diff --git a/libcxx/include/__memory/tombstone_traits.h b/libcxx/include/__memory/tombstone_traits.h
index f354a25e69df53..9adc4625075334 100644
--- a/libcxx/include/__memory/tombstone_traits.h
+++ b/libcxx/include/__memory/tombstone_traits.h
@@ -100,11 +100,12 @@ struct __tombstone_traits<__enable_specialization_if<is_fundamental_v<_Tp> && al
 
 template <class _Tp>
 struct __tombstone_traits<_Tp**> : __tombstone_traits_assume_aligned_pointer<_Tp*> {
-  static_assert(alignof(_Tp*) >= 2, "alignment of a pointer isn't at least 2!?");
+  static_assert(alignof(_Tp*) >= 2, "Alignment of a pointer isn't at least 2!");
 };
 
 inline constexpr struct __init_engaged_t {
 } __init_engaged;
+
 inline constexpr struct __init_disengaged_t {
 } __init_disengaged;
 
@@ -144,8 +145,9 @@ union _MaybeTombstone {
     if consteval {
       return __builtin_is_within_lifetime(&__value_);
     } else {
-      _DummyTombstone __dummy;
       static_assert(sizeof(_DummyTombstone) <= sizeof(*this));
+
+      _DummyTombstone __dummy;
       __builtin_memcpy(&__dummy, this, sizeof(_DummyTombstone));
 
       return !__dummy.__is_tombstone();
@@ -205,7 +207,7 @@ struct __tombstoned_value final {
   static_assert(sizeof(_Tombstone) == sizeof(_DummyTombstone));
   static_assert(alignof(_Tombstone) == alignof(_DummyTombstone));
   static_assert(__datasizeof_v<_Tombstone> == __datasizeof_v<_DummyTombstone>);
-  static_assert(sizeof(_Tombstone) <= sizeof(_Tp), "Trying to use tobstone which can't hold T");
+  static_assert(sizeof(_Tombstone) <= sizeof(_Tp), "Trying to use tombstone which can't hold T");
 
   _MaybeTombstone<_Tp, _Payload> __data_;
 
@@ -250,25 +252,25 @@ struct __tombstoned_value final {
   }
 
   _LIBCPP_HIDE_FROM_ABI constexpr auto&& __get_payload() && noexcept {
-    _LIBCPP_ASSERT_INTERNAL(!__is_engaged(), "Trying to get the payload of an enagaged tombstoned value");
+    _LIBCPP_ASSERT_INTERNAL(!__is_engaged(), "Trying to get the payload of an engaged tombstoned value");
     return std::move(__data_.__tombstone_.__payload_);
   }
 
   _LIBCPP_HIDE_FROM_ABI constexpr auto&& __get_payload() const&& noexcept {
-    _LIBCPP_ASSERT_INTERNAL(!__is_engaged(), "Trying to get the payload of an enagaged tombstoned value");
+    _LIBCPP_ASSERT_INTERNAL(!__is_engaged(), "Trying to get the payload of an engaged tombstoned value");
     return std::move(__data_.__tombstone_.__payload_);
   }
 
   template <class... _Args>
   _LIBCPP_HIDE_FROM_ABI constexpr void __engage(in_place_t, _Args&&... __args) {
-    _LIBCPP_ASSERT_INTERNAL(!__is_engaged(), "Trying to enage a already engaged tombstoned value");
+    _LIBCPP_ASSERT_INTERNAL(!__is_engaged(), "Trying to engage a already engaged tombstoned value");
     std::destroy_at(&__data_.__tombstone_);
     std::__construct_at(&__data_.__value_, std::forward<_Args>(__args)...);
   }
 
   template <class... _Args>
   _LIBCPP_HIDE_FROM_ABI constexpr void __disengage(in_place_t, _Args&&... __args) {
-    _LIBCPP_ASSERT_INTERNAL(!__is_engaged(), "Trying to disenage a disengaged tombstoned value");
+    _LIBCPP_ASSERT_INTERNAL(__is_engaged(), "Trying to disengage a disengaged tombstoned value");
     std::destroy_at(&__data_.__value_);
     std::__construct_at(&__data_.__tombstone_, std::forward<_Args>(__args)...);
   }

>From b808386775c23b62281d20251df57e6e855c4c12 Mon Sep 17 00:00:00 2001
From: William Tran-Viet <wtranviet at proton.me>
Date: Fri, 30 Oct 2026 22:57:14 -0400
Subject: [PATCH 03/12] Rename macro to where it actually lives

---
 libcxx/include/__memory/tombstone_traits.h | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/libcxx/include/__memory/tombstone_traits.h b/libcxx/include/__memory/tombstone_traits.h
index 9adc4625075334..4bc52c8a4307d7 100644
--- a/libcxx/include/__memory/tombstone_traits.h
+++ b/libcxx/include/__memory/tombstone_traits.h
@@ -6,8 +6,8 @@
 //
 //===----------------------------------------------------------------------===//
 
-#ifndef _LIBCPP___TYPE_TRAITS_TOMBSTONE_TRAITS_H
-#define _LIBCPP___TYPE_TRAITS_TOMBSTONE_TRAITS_H
+#ifndef _LIBCPP___MEMORY_TOMBSTONE_TRAITS_H
+#define _LIBCPP___MEMORY_TOMBSTONE_TRAITS_H
 
 #include <__assert>
 #include <__config>
@@ -288,4 +288,4 @@ _LIBCPP_END_NAMESPACE_STD
 
 _LIBCPP_POP_MACROS
 
-#endif // _LIBCPP___TYPE_TRAITS_TOMBSTONE_TRAITS_H
+#endif // _LIBCPP___MEMORY_TOMBSTONE_TRAITS_H

>From c586b6cad3c08c725a43ee2e7b55037399fce37e Mon Sep 17 00:00:00 2001
From: William Tran-Viet <wtranviet at proton.me>
Date: Sat, 31 Oct 2026 01:04:01 -0400
Subject: [PATCH 04/12] Update Tp* tombstone traits to accommodate little
 endian

---
 libcxx/include/__memory/tombstone_traits.h | 31 +++++++++++++++++++---
 1 file changed, 27 insertions(+), 4 deletions(-)

diff --git a/libcxx/include/__memory/tombstone_traits.h b/libcxx/include/__memory/tombstone_traits.h
index 4bc52c8a4307d7..6c5e769b2581ba 100644
--- a/libcxx/include/__memory/tombstone_traits.h
+++ b/libcxx/include/__memory/tombstone_traits.h
@@ -75,14 +75,30 @@ struct __tombstone_traits_assume_aligned_pointer {
     template <class... _Args>
     constexpr __representation(_Args&&... __args) : __payload_(std::forward<_Args>(__args)...), __value_(_Np + 1) {}
 
-    bool __is_tombstone() { return __value_ == _Np + 1; }
+    constexpr bool __is_tombstone() { return __value_ == _Np + 1; }
+
+    static_assert(sizeof(_Tp*) - 1 - (alignof(_Payload) - 1) >= sizeof(_Payload));
+
+    // clang-format off
+#  ifdef _LIBCPP_LITTLE_ENDIAN
+    // TODO: Figure out a better explanation for the layout
+    // On little-endian, the value is the first byte, and how much we can use the remaining 7 bytes depends on the payload's alignment requirements.
+    // If alignof == 1, we have to pad 0 bytes.
+    // If alignof == 2, we have to pad 1 byte.
+    // If alignof == 4, we have to pad 3 bytes.
+    unsigned char __value_;
+    _LIBCPP_NO_UNIQUE_ADDRESS __padding<alignof(_Payload) - 1> __padding_;
+    _LIBCPP_NO_UNIQUE_ADDRESS _Payload __payload_;
+#  else
+    // On big-endian, we actually only need to use the datasize of _Payload because it sits first, which relaxes the requirements for the payload quite a bit
+    // since we can fill all 7 bytes without worrying about alignment. However, to keep things consistent, maintain the same requirements as little-endian.
 
     _LIBCPP_NO_UNIQUE_ADDRESS _Payload __payload_;
-    _LIBCPP_NO_UNIQUE_ADDRESS __padding<sizeof(_Tp*) - 1 - __datasizeof_v<_Payload>> __padding_;
+    _LIBCPP_NO_UNIQUE_ADDRESS __padding<alignof(_Payload) - 1> __padding_;
     unsigned char __value_;
+#  endif
+    // clang-format on
   };
-
-  static constexpr size_t __max_tombstone = 0; // TODO: Calculate this correctly
 };
 
 // TODO: Look into
@@ -198,6 +214,13 @@ union _MaybeTombstone<_Tp, _Payload, true> {
   _LIBCPP_CONSTEXPR_SINCE_CXX20 ~_MaybeTombstone() = default;
 };
 
+// For a type to have a tombstone, it must have a specialization of __tombstone_traits.
+// __tombstoned_value that can contain one of either _Tp, or a specialized _Payload class/struct, which must occupy
+// the same memory footprint as _Tp.
+// If _Tp has a valid memory represntation of that type, then __tombstoned_value is engaged and contains that
+// instance of _Tp. Otherwise, it is _Payload, which represents an impossible in-memory value of _Tp, as well as any
+// extra metadata which can fit inside.
+
 template <class _Tp, class _Payload>
 struct __tombstoned_value final {
   using _Tombstone      = __tombstone_traits<_Tp>::template __representation<_Payload, 0>;

>From ca55080b0958e402ee0fd19a29c8c6a7e962cb82 Mon Sep 17 00:00:00 2001
From: William Tran-Viet <wtranviet at proton.me>
Date: Sat, 31 Oct 2026 01:59:44 -0400
Subject: [PATCH 05/12] Remove shared_ptr specialization (for now)

---
 libcxx/include/__memory/shared_ptr.h | 18 ------------------
 1 file changed, 18 deletions(-)

diff --git a/libcxx/include/__memory/shared_ptr.h b/libcxx/include/__memory/shared_ptr.h
index 39749416787685..1d8a62c984a67a 100644
--- a/libcxx/include/__memory/shared_ptr.h
+++ b/libcxx/include/__memory/shared_ptr.h
@@ -653,26 +653,8 @@ class _LIBCPP_SHARED_PTR_TRIVIAL_ABI shared_ptr {
   friend class shared_ptr;
   template <class _Up>
   friend class weak_ptr;
-
-  friend struct __tombstone_traits<shared_ptr<_Tp> >;
 };
 
-#if _LIBCPP_STD_VER >= 17 && 0
-template <class _Tp>
-shared_ptr(weak_ptr<_Tp>) -> shared_ptr<_Tp>;
-template <class _Tp, class _Dp>
-shared_ptr(unique_ptr<_Tp, _Dp>) -> shared_ptr<_Tp>;
-
-template <class _Tp>
-struct __tombstone_traits<shared_ptr<_Tp>> {
-  static constexpr auto __disengaged_value_ =
-      __tombstone_traits_assume_aligned_pointer<__shared_weak_count*>::__disengaged_value_;
-  static constexpr size_t __is_disengaged_offset_ =
-      __builtin_offsetof(shared_ptr<_Tp>, __cntrl_) +
-      __tombstone_traits_assume_aligned_pointer<__shared_weak_count*>::__is_disengaged_offset_;
-};
-#endif // _LIBCPP_STD_VER >= 17
-
 //
 // std::allocate_shared and std::make_shared
 //

>From 31283177200064047f09240c475693f1707ebe47 Mon Sep 17 00:00:00 2001
From: William Tran-Viet <wtranviet at proton.me>
Date: Sat, 31 Oct 2026 02:00:30 -0400
Subject: [PATCH 06/12] Remove pair tombstone_traits

---
 libcxx/include/__utility/pair.h | 22 ----------------------
 1 file changed, 22 deletions(-)

diff --git a/libcxx/include/__utility/pair.h b/libcxx/include/__utility/pair.h
index 6d5b3ffa274343..86dc245d91493c 100644
--- a/libcxx/include/__utility/pair.h
+++ b/libcxx/include/__utility/pair.h
@@ -18,7 +18,6 @@
 #include <__fwd/array.h>
 #include <__fwd/pair.h>
 #include <__fwd/tuple.h>
-#include <__memory/tombstone_traits.h>
 #include <__tuple/tuple_like_no_subrange.h>
 #include <__tuple/tuple_size.h>
 #include <__type_traits/common_reference.h>
@@ -436,27 +435,6 @@ template <class _T1, class _T2>
 pair(_T1, _T2) -> pair<_T1, _T2>;
 #endif // _LIBCPP_STD_VER >= 17
 
-#if 0
-template <class _Tp, class _Up, bool __first_tombstone>
-struct __tombstone_traits_pair;
-
-template <class _Tp, class _Up>
-struct __tombstone_traits_pair<_Tp, _Up, true> : __tombstone_traits<_Tp> {
-  static_assert(__builtin_offsetof(pair<_Tp, _Up>, first) == 0);
-};
-
-template <class _Tp, class _Up>
-struct __tombstone_traits_pair<_Tp, _Up, false> {
-  static constexpr auto __disengaged_value_ = __tombstone_traits<_Up>::__disengaged_value_;
-  static constexpr size_t __is_disengaged_offset_ =
-      __builtin_offsetof(pair<_Tp, _Up>, second) + __tombstone_traits<_Up>::__is_disengaged_offset_;
-};
-
-template <class _Tp, class _Up>
-struct __tombstone_traits<__enable_specialization_if<__has_tombstone_v<_Tp> || __has_tombstone_v<_Up>, pair<_Tp, _Up>>>
-    : __tombstone_traits_pair<_Tp, _Up, __has_tombstone_v<_Tp>> {};
-#endif
-
 // [pairs.spec], specialized algorithms
 
 template <class _T1, class _T2, class _U1, class _U2>

>From a4f0ecee7824b83ae86d4bec601751aa110e17ed Mon Sep 17 00:00:00 2001
From: William Tran-Viet <wtranviet at proton.me>
Date: Sat, 31 Oct 2026 02:00:56 -0400
Subject: [PATCH 07/12] shared_ptr include

---
 libcxx/include/__memory/shared_ptr.h | 1 -
 1 file changed, 1 deletion(-)

diff --git a/libcxx/include/__memory/shared_ptr.h b/libcxx/include/__memory/shared_ptr.h
index 1d8a62c984a67a..21c311640b874c 100644
--- a/libcxx/include/__memory/shared_ptr.h
+++ b/libcxx/include/__memory/shared_ptr.h
@@ -33,7 +33,6 @@
 #include <__memory/destroy.h>
 #include <__memory/pointer_traits.h>
 #include <__memory/shared_count.h>
-#include <__memory/tombstone_traits.h>
 #include <__memory/uninitialized_algorithms.h>
 #include <__memory/uninitialized_multidimensional_algorithms.h>
 #include <__memory/unique_ptr.h>

>From 02b131039b13c1730961a0e7e5db30e7840eeb26 Mon Sep 17 00:00:00 2001
From: William Tran-Viet <wtranviet at proton.me>
Date: Sat, 31 Oct 2026 02:21:39 -0400
Subject: [PATCH 08/12] Bump minimum to C++20 Remove _LIBCPP_HIDE_FROM_ABI Add
 diagnostic push/pop Tidy up some usings

---
 .../include/__functional/reference_wrapper.h  |  4 +-
 libcxx/include/__memory/tombstone_traits.h    | 57 ++++++++++---------
 libcxx/include/__memory/unique_ptr.h          |  8 ++-
 libcxx/include/string                         |  8 +--
 4 files changed, 42 insertions(+), 35 deletions(-)

diff --git a/libcxx/include/__functional/reference_wrapper.h b/libcxx/include/__functional/reference_wrapper.h
index d696e7c81e04f4..0d16a65bdc14cd 100644
--- a/libcxx/include/__functional/reference_wrapper.h
+++ b/libcxx/include/__functional/reference_wrapper.h
@@ -127,7 +127,9 @@ class reference_wrapper : public __weak_result_type<_Tp> {
 #if _LIBCPP_STD_VER >= 17
 template <class _Tp>
 reference_wrapper(_Tp&) -> reference_wrapper<_Tp>;
+#endif // _LIBCPP_STD_VER >= 17
 
+#if _LIBCPP_STD_VER >= 20
 template <class _Tp>
 struct __tombstone_traits<reference_wrapper<_Tp>> {
   // reference_wrapper<_Tp> is conceptually that same as _Tp& and can only be constructed from a _Tp&. Since references
@@ -147,7 +149,7 @@ struct __tombstone_traits<reference_wrapper<_Tp>> {
     _Tp* __value_;
   };
 };
-#endif // _LIBCPP_STD_VER >= 17
+#endif // _LIBCPP_STD_VER >= 20
 
 template <class _Tp>
 [[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI
diff --git a/libcxx/include/__memory/tombstone_traits.h b/libcxx/include/__memory/tombstone_traits.h
index 6c5e769b2581ba..4f8a15665603f0 100644
--- a/libcxx/include/__memory/tombstone_traits.h
+++ b/libcxx/include/__memory/tombstone_traits.h
@@ -39,7 +39,7 @@ _LIBCPP_BEGIN_NAMESPACE_STD
 template <class>
 struct __tombstone_traits;
 
-#if _LIBCPP_STD_VER >= 17
+#if _LIBCPP_STD_VER >= 20
 
 // bools always have exactly one bit set. If there is more than one set it's disengaged.
 template <>
@@ -49,7 +49,7 @@ struct __tombstone_traits<bool> {
     template <class... _Args>
     constexpr __representation(_Args&&... __args) : __payload_(std::forward<_Args>(__args)...), __value_(_Np + 2) {}
 
-    bool __is_tombstone() { return __value_ == _Np + 2; }
+    constexpr bool __is_tombstone() { return __value_ == _Np + 2; }
 
     _LIBCPP_NO_UNIQUE_ADDRESS _Payload __payload_;
     unsigned char __value_;
@@ -72,12 +72,16 @@ template <class _Tp>
 struct __tombstone_traits_assume_aligned_pointer {
   template <class _Payload, size_t _Np>
   struct __representation {
+    _LIBCPP_DIAGNOSTIC_PUSH
+    _LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wreorder-ctor")
     template <class... _Args>
     constexpr __representation(_Args&&... __args) : __payload_(std::forward<_Args>(__args)...), __value_(_Np + 1) {}
+    _LIBCPP_DIAGNOSTIC_POP
 
     constexpr bool __is_tombstone() { return __value_ == _Np + 1; }
 
-    static_assert(sizeof(_Tp*) - 1 - (alignof(_Payload) - 1) >= sizeof(_Payload));
+    static_assert(sizeof(_Tp*) - 1 - (alignof(_Payload) - 1) >= sizeof(_Payload),
+                  "Payload is too big for tombstone of pointer!");
 
     // clang-format off
 #  ifdef _LIBCPP_LITTLE_ENDIAN
@@ -128,10 +132,6 @@ inline constexpr struct __init_disengaged_t {
 template <class _Tp, class = void>
 struct alignas(_Tp) __dummy_payload {
   char __data_[__datasizeof_v<_Tp>];
-
-  static_assert(alignof(__dummy_payload) == alignof(_Tp));
-  static_assert(sizeof(__dummy_payload) == sizeof(_Tp));
-  static_assert(__datasizeof_v<__dummy_payload> == __datasizeof_v<_Tp>);
 };
 
 template <class _Tp>
@@ -157,7 +157,7 @@ union _MaybeTombstone {
   _MaybeTombstone& operator=(const _MaybeTombstone&) = default;
   _MaybeTombstone& operator=(_MaybeTombstone&&)      = default;
 
-  _LIBCPP_HIDE_FROM_ABI constexpr bool __is_engaged() const noexcept {
+  constexpr bool __is_engaged() const noexcept {
     if consteval {
       return __builtin_is_within_lifetime(&__value_);
     } else {
@@ -170,7 +170,7 @@ union _MaybeTombstone {
     }
   }
 
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 ~_MaybeTombstone() {
+  constexpr ~_MaybeTombstone() {
     if (__is_engaged()) {
       std::destroy_at(&__value_);
     } else {
@@ -199,7 +199,7 @@ union _MaybeTombstone<_Tp, _Payload, true> {
   _MaybeTombstone& operator=(const _MaybeTombstone&) = default;
   _MaybeTombstone& operator=(_MaybeTombstone&&)      = default;
 
-  _LIBCPP_HIDE_FROM_ABI constexpr bool __is_engaged() const noexcept {
+  constexpr bool __is_engaged() const noexcept {
     if consteval {
       return __builtin_is_within_lifetime(&__value_);
     } else {
@@ -211,7 +211,7 @@ union _MaybeTombstone<_Tp, _Payload, true> {
     }
   }
 
-  _LIBCPP_CONSTEXPR_SINCE_CXX20 ~_MaybeTombstone() = default;
+  constexpr ~_MaybeTombstone() = default;
 };
 
 // For a type to have a tombstone, it must have a specialization of __tombstone_traits.
@@ -223,8 +223,9 @@ union _MaybeTombstone<_Tp, _Payload, true> {
 
 template <class _Tp, class _Payload>
 struct __tombstoned_value final {
-  using _Tombstone      = __tombstone_traits<_Tp>::template __representation<_Payload, 0>;
-  using _DummyTombstone = __tombstone_traits<_Tp>::template __representation<__dummy_payload<_Payload>, 0>;
+  using _Repr           = _MaybeTombstone<_Tp, _Payload>;
+  using _Tombstone      = _Repr::_Tombstone;
+  using _DummyTombstone = _Repr::_DummyTombstone;
 
   static_assert(__builtin_is_implicit_lifetime(_DummyTombstone));
   static_assert(sizeof(_Tombstone) == sizeof(_DummyTombstone));
@@ -232,67 +233,67 @@ struct __tombstoned_value final {
   static_assert(__datasizeof_v<_Tombstone> == __datasizeof_v<_DummyTombstone>);
   static_assert(sizeof(_Tombstone) <= sizeof(_Tp), "Trying to use tombstone which can't hold T");
 
-  _MaybeTombstone<_Tp, _Payload> __data_;
+  _Repr __data_;
 
   template <class... _Args>
-  explicit _LIBCPP_HIDE_FROM_ABI constexpr __tombstoned_value(__init_disengaged_t, _Args&&... __args)
+  explicit constexpr __tombstoned_value(__init_disengaged_t, _Args&&... __args)
       : __data_(__init_disengaged, std::forward<_Args>(__args)...) {}
 
   template <class... _Args>
-  explicit _LIBCPP_HIDE_FROM_ABI constexpr __tombstoned_value(__init_engaged_t, _Args&&... __args)
+  explicit constexpr __tombstoned_value(__init_engaged_t, _Args&&... __args)
       : __data_(__init_engaged, std::forward<_Args>(__args)...) {}
 
-  _LIBCPP_HIDE_FROM_ABI constexpr bool __is_engaged() const noexcept { return __data_.__is_engaged(); }
+  constexpr bool __is_engaged() const noexcept { return __data_.__is_engaged(); }
 
-  _LIBCPP_HIDE_FROM_ABI constexpr auto&& __get_value() & noexcept {
+  constexpr auto&& __get_value() & noexcept {
     _LIBCPP_ASSERT_INTERNAL(__is_engaged(), "Trying to get the value of a disenagaged tombstoned value");
     return __data_.__value_;
   }
 
-  _LIBCPP_HIDE_FROM_ABI constexpr auto&& __get_value() const& noexcept {
+  constexpr auto&& __get_value() const& noexcept {
     _LIBCPP_ASSERT_INTERNAL(__is_engaged(), "Trying to get the value of a disenagaged tombstoned value");
     return __data_.__value_;
   }
 
-  _LIBCPP_HIDE_FROM_ABI constexpr auto&& __get_value() && noexcept {
+  constexpr auto&& __get_value() && noexcept {
     _LIBCPP_ASSERT_INTERNAL(__is_engaged(), "Trying to get the value of a disenagaged tombstoned value");
     return std::move(__data_.__value_);
   }
 
-  _LIBCPP_HIDE_FROM_ABI constexpr auto&& __get_value() const&& noexcept {
+  constexpr auto&& __get_value() const&& noexcept {
     _LIBCPP_ASSERT_INTERNAL(__is_engaged(), "Trying to get the value of a disenagaged tombstoned value");
     return std::move(__data_.__value_);
   }
 
-  _LIBCPP_HIDE_FROM_ABI constexpr auto&& __get_payload() & noexcept {
+  constexpr auto&& __get_payload() & noexcept {
     _LIBCPP_ASSERT_INTERNAL(!__is_engaged(), "Trying to get the payload of an enagaged tombstoned value");
     return __data_.__tombstone_.__payload_;
   }
 
-  _LIBCPP_HIDE_FROM_ABI constexpr auto&& __get_payload() const& noexcept {
+  constexpr auto&& __get_payload() const& noexcept {
     _LIBCPP_ASSERT_INTERNAL(!__is_engaged(), "Trying to get the payload of an enagaged tombstoned value");
     return __data_.__tombstone_.__payload_;
   }
 
-  _LIBCPP_HIDE_FROM_ABI constexpr auto&& __get_payload() && noexcept {
+  constexpr auto&& __get_payload() && noexcept {
     _LIBCPP_ASSERT_INTERNAL(!__is_engaged(), "Trying to get the payload of an engaged tombstoned value");
     return std::move(__data_.__tombstone_.__payload_);
   }
 
-  _LIBCPP_HIDE_FROM_ABI constexpr auto&& __get_payload() const&& noexcept {
+  constexpr auto&& __get_payload() const&& noexcept {
     _LIBCPP_ASSERT_INTERNAL(!__is_engaged(), "Trying to get the payload of an engaged tombstoned value");
     return std::move(__data_.__tombstone_.__payload_);
   }
 
   template <class... _Args>
-  _LIBCPP_HIDE_FROM_ABI constexpr void __engage(in_place_t, _Args&&... __args) {
+  constexpr void __engage(in_place_t, _Args&&... __args) {
     _LIBCPP_ASSERT_INTERNAL(!__is_engaged(), "Trying to engage a already engaged tombstoned value");
     std::destroy_at(&__data_.__tombstone_);
     std::__construct_at(&__data_.__value_, std::forward<_Args>(__args)...);
   }
 
   template <class... _Args>
-  _LIBCPP_HIDE_FROM_ABI constexpr void __disengage(in_place_t, _Args&&... __args) {
+  constexpr void __disengage(in_place_t, _Args&&... __args) {
     _LIBCPP_ASSERT_INTERNAL(__is_engaged(), "Trying to disengage a disengaged tombstoned value");
     std::destroy_at(&__data_.__value_);
     std::__construct_at(&__data_.__tombstone_, std::forward<_Args>(__args)...);
@@ -305,7 +306,7 @@ inline constexpr bool __has_tombstone_v = false;
 template <class _Tp>
 inline constexpr bool __has_tombstone_v<_Tp, void_t<decltype(sizeof(__tombstone_traits<_Tp>))>> = true;
 
-#endif // _LIBCPP_STD_VER >= 17
+#endif // _LIBCPP_STD_VER >= 20
 
 _LIBCPP_END_NAMESPACE_STD
 
diff --git a/libcxx/include/__memory/unique_ptr.h b/libcxx/include/__memory/unique_ptr.h
index 96e53c80487485..f04bad1b9434a6 100644
--- a/libcxx/include/__memory/unique_ptr.h
+++ b/libcxx/include/__memory/unique_ptr.h
@@ -276,10 +276,12 @@ class _LIBCPP_UNIQUE_PTR_TRIVIAL_ABI unique_ptr {
     swap(__deleter_, __u.__deleter_);
   }
 
+#if _LIBCPP_STD_VER >= 20
   friend struct __tombstone_traits<unique_ptr>;
+#endif
 };
 
-#if _LIBCPP_STD_VER >= 17
+#if _LIBCPP_STD_VER >= 20
 template <class _Tp>
 struct __tombstone_traits<__enable_specialization_if<__has_tombstone_v<_Tp*>, unique_ptr<_Tp>>>
     : __tombstone_traits<_Tp*> {
@@ -589,10 +591,12 @@ class _LIBCPP_UNIQUE_PTR_TRIVIAL_ABI unique_ptr<_Tp[], _Dp> {
     swap(__checker_, __u.__checker_);
   }
 
+#if _LIBCPP_STD_VER >= 20
   friend struct __tombstone_traits<unique_ptr>;
+#endif
 };
 
-#if _LIBCPP_STD_VER >= 17
+#if _LIBCPP_STD_VER >= 20
 template <class _Tp>
 struct __tombstone_traits<__enable_specialization_if<__has_tombstone_v<_Tp*>, unique_ptr<_Tp[]>>>
     : __tombstone_traits<_Tp*> {
diff --git a/libcxx/include/string b/libcxx/include/string
index a693ddf47d37fa..4f35f2a9b7a47c 100644
--- a/libcxx/include/string
+++ b/libcxx/include/string
@@ -2490,9 +2490,9 @@ private:
   void __init(const value_type* __s, size_type __sz, size_type __reserve);
 #  endif
 
-#if _LIBCPP_STD_VER >= 17
+#  if _LIBCPP_STD_VER >= 20
   friend __tombstone_traits<basic_string>;
-#endif
+#  endif
 };
 
 // These declarations must appear before any functions are implicitly used
@@ -2583,7 +2583,7 @@ basic_string(from_range_t, _Range&&, _Allocator = _Allocator())
     -> basic_string<ranges::range_value_t<_Range>, char_traits<ranges::range_value_t<_Range>>, _Allocator>;
 #  endif
 
-#  if _LIBCPP_STD_VER >= 17
+#  if _LIBCPP_STD_VER >= 20
 template <class _CharT, class _Traits, class _Allocator>
 struct __tombstone_traits<basic_string<_CharT, _Traits, _Allocator>> {
   // If `string` is in the `__short` representation, the size can never be larger than `__min_cap`. 65 sets the bit
@@ -2621,7 +2621,7 @@ struct __tombstone_traits<basic_string<_CharT, _Traits, _Allocator>> {
 #    endif
   };
 };
-#  endif                       // _LIBCPP_STD_VER >= 17
+#  endif                       // _LIBCPP_STD_VER >= 20
 
 template <class _CharT, class _Traits, class _Allocator>
 _LIBCPP_CONSTEXPR_SINCE_CXX20 void

>From 9c594b36ae320b432d07a8be1590c4dc3e4539e2 Mon Sep 17 00:00:00 2001
From: William Tran-Viet <wtranviet at proton.me>
Date: Sat, 31 Oct 2026 02:28:54 -0400
Subject: [PATCH 09/12] Add tests for each specialized type in this PR

---
 .../memory/tombstone_traits/bool.pass.cpp     |  42 +++++
 .../memory/tombstone_traits/pointer.pass.cpp  | 158 ++++++++++++++++++
 .../reference_wrapper.pass.cpp                |  75 +++++++++
 .../memory/tombstone_traits/string.pass.cpp   | 100 +++++++++++
 .../tombstone_traits/unique_ptr.pass.cpp      | 151 +++++++++++++++++
 5 files changed, 526 insertions(+)
 create mode 100644 libcxx/test/libcxx/memory/tombstone_traits/bool.pass.cpp
 create mode 100644 libcxx/test/libcxx/memory/tombstone_traits/pointer.pass.cpp
 create mode 100644 libcxx/test/libcxx/memory/tombstone_traits/reference_wrapper.pass.cpp
 create mode 100644 libcxx/test/libcxx/memory/tombstone_traits/string.pass.cpp
 create mode 100644 libcxx/test/libcxx/memory/tombstone_traits/unique_ptr.pass.cpp

diff --git a/libcxx/test/libcxx/memory/tombstone_traits/bool.pass.cpp b/libcxx/test/libcxx/memory/tombstone_traits/bool.pass.cpp
new file mode 100644
index 00000000000000..a541570e5f8dba
--- /dev/null
+++ b/libcxx/test/libcxx/memory/tombstone_traits/bool.pass.cpp
@@ -0,0 +1,42 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: std-at-least-c++20
+
+// tombstone_traits<bool>
+
+#include <__memory/tombstone_traits.h>
+#include <cassert>
+#include <utility>
+
+struct Empty {};
+
+constexpr bool test() {
+  std::__tombstoned_value<bool, Empty> tombstone(std::__init_disengaged);
+
+  assert(!tombstone.__is_engaged());
+
+  tombstone.__engage(std::in_place, true);
+
+  assert(tombstone.__get_value());
+  assert(std::as_const(tombstone.__get_value()));
+  assert(std::move(tombstone.__get_value()));
+  assert(std::move(std::as_const(tombstone.__get_value())));
+
+  tombstone.__disengage(std::in_place);
+  assert(!tombstone.__is_engaged());
+
+  return true;
+}
+
+int main(int, char**) {
+  test();
+  static_assert(test());
+
+  return 0;
+}
diff --git a/libcxx/test/libcxx/memory/tombstone_traits/pointer.pass.cpp b/libcxx/test/libcxx/memory/tombstone_traits/pointer.pass.cpp
new file mode 100644
index 00000000000000..5951ec60769fb1
--- /dev/null
+++ b/libcxx/test/libcxx/memory/tombstone_traits/pointer.pass.cpp
@@ -0,0 +1,158 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRED: std-at-least-c++20
+
+// UNSUPPORTED: 32-bit-pointer
+// TODO: Expand tests to accommodate 32-bit pointers
+
+#include <__memory/tombstone_traits.h>
+#include <cassert>
+#include <string_view>
+#include <utility>
+
+// Payloads that can fit into the available bytes given their padding
+
+struct Size7Align1 {
+  char payload[7] = {
+      'h',
+      'e',
+      'l',
+      'l',
+      'o',
+      '1',
+      '\0',
+  };
+
+  constexpr std::string_view getPayload() & { return "ref"; }
+  constexpr std::string_view getPayload() && { return "move"; }
+  constexpr std::string_view getPayload() const& { return "const ref"; }
+  constexpr std::string_view getPayload() const&& { return "const move"; }
+};
+
+struct Size6Align2 {
+  short a = 1, b = 2, c = 3;
+};
+
+struct Size4Align4 {
+  int a = 1234;
+};
+
+constexpr bool test() {
+  // start engaged, disengage
+  {
+    int my_int = 1;
+    std::__tombstoned_value<int*, Size7Align1> tombstone(std::__init_engaged, &my_int);
+    assert(sizeof(tombstone) == sizeof(&my_int));
+
+    assert(tombstone.__is_engaged());
+    assert(tombstone.__get_value() == &my_int);
+    assert(std::as_const(tombstone.__get_value()) == &my_int);
+    assert(std::move(tombstone.__get_value()) == &my_int);
+    assert(std::move(std::as_const(tombstone)).__get_value() == &my_int);
+    assert(*tombstone.__get_value() == my_int);
+
+    tombstone.__disengage(std::in_place, Size7Align1{});
+    assert(!tombstone.__is_engaged());
+
+    assert(std::string_view(tombstone.__get_payload().payload) == "hello1");
+    assert(tombstone.__get_payload().getPayload() == "ref");
+    assert(std::as_const(tombstone.__get_payload()).getPayload() == "const ref");
+    assert(std::move(tombstone.__get_payload()).getPayload() == "move");
+    assert(std::move(std::as_const(tombstone.__get_payload())).getPayload() == "const move");
+  }
+
+  {
+    short my_short = 1;
+    std::__tombstoned_value<short*, Size6Align2> tombstone(std::__init_engaged, &my_short);
+    assert(sizeof(tombstone) == sizeof(&my_short));
+
+    assert(tombstone.__is_engaged());
+    assert(tombstone.__get_value() == &my_short);
+    assert(*tombstone.__get_value() == my_short);
+
+    tombstone.__disengage(std::in_place, Size6Align2{});
+    assert(!tombstone.__is_engaged());
+
+    assert(tombstone.__get_payload().a == 1);
+    assert(tombstone.__get_payload().b == 2);
+    assert(tombstone.__get_payload().c == 3);
+  }
+
+  {
+    long my_long = 3;
+    std::__tombstoned_value<long*, Size4Align4> tombstone(std::__init_engaged, &my_long);
+    assert(sizeof(tombstone) == sizeof(&my_long));
+
+    assert(tombstone.__is_engaged());
+    assert(tombstone.__get_value() == &my_long);
+    assert(*tombstone.__get_value() == my_long);
+
+    tombstone.__disengage(std::in_place, Size4Align4{});
+    assert(!tombstone.__is_engaged());
+
+    assert(tombstone.__get_payload().a == 1234);
+  }
+
+  // start disengaged, then engage
+  {
+    int my_int = 1;
+    std::__tombstoned_value<int*, Size7Align1> tombstone(std::__init_disengaged, Size7Align1{});
+    assert(sizeof(tombstone) == sizeof(&my_int));
+
+    assert(!tombstone.__is_engaged());
+    assert(std::string_view(tombstone.__get_payload().payload) == "hello1");
+
+    tombstone.__engage(std::in_place, &my_int);
+    assert(tombstone.__is_engaged());
+
+    assert(tombstone.__get_value() == &my_int);
+    assert(*tombstone.__get_value() == my_int);
+  }
+
+  {
+    short my_short = 1;
+    std::__tombstoned_value<short*, Size6Align2> tombstone(std::__init_disengaged, Size6Align2{});
+    assert(sizeof(tombstone) == sizeof(&my_short));
+
+    assert(!tombstone.__is_engaged());
+    assert(tombstone.__get_payload().a == 1);
+    assert(tombstone.__get_payload().b == 2);
+    assert(tombstone.__get_payload().c == 3);
+
+    tombstone.__engage(std::in_place, &my_short);
+    assert(tombstone.__is_engaged());
+
+    assert(tombstone.__get_value() == &my_short);
+    assert(*tombstone.__get_value() == my_short);
+  }
+
+  {
+    long my_long = 3;
+    std::__tombstoned_value<long*, Size4Align4> tombstone(std::__init_disengaged, Size4Align4{});
+    assert(sizeof(tombstone) == sizeof(&my_long));
+
+    assert(!tombstone.__is_engaged());
+    assert(tombstone.__get_payload().a == 1234);
+
+    tombstone.__engage(std::in_place, &my_long);
+    assert(tombstone.__is_engaged());
+
+    assert(tombstone.__get_value() == &my_long);
+    assert(*tombstone.__get_value() == my_long);
+  }
+
+  return true;
+}
+
+int main(int, char**) {
+  test();
+  static_assert(test());
+
+  return 0;
+}
diff --git a/libcxx/test/libcxx/memory/tombstone_traits/reference_wrapper.pass.cpp b/libcxx/test/libcxx/memory/tombstone_traits/reference_wrapper.pass.cpp
new file mode 100644
index 00000000000000..a47c1c35f6dace
--- /dev/null
+++ b/libcxx/test/libcxx/memory/tombstone_traits/reference_wrapper.pass.cpp
@@ -0,0 +1,75 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: std-at-least-c++20
+
+// tombstone_traits<reference_wrapper>
+
+#include <__memory/tombstone_traits.h>
+#include <cassert>
+#include <functional>
+#include <utility>
+
+struct Empty {};
+
+struct Incomplete;
+static_assert(std::__has_tombstone_v<std::reference_wrapper<Incomplete>>);
+
+template <class T>
+constexpr void test_type(T& value) {
+  // start engaged, disengage
+  {
+    std::__tombstoned_value<std::reference_wrapper<T>, Empty> tombstone(std::__init_engaged, value);
+    assert(sizeof(tombstone) == sizeof(std::reference_wrapper<T>));
+
+    assert(tombstone.__is_engaged());
+    assert(&tombstone.__get_value().get() == &value);
+    assert(&std::as_const(tombstone).__get_value().get() == &value);
+    assert(&std::move(tombstone).__get_value().get() == &value);
+
+    tombstone.__disengage(std::in_place);
+    assert(!tombstone.__is_engaged());
+  }
+
+  // start disengaged, then engage
+  {
+    std::__tombstoned_value<std::reference_wrapper<T>, Empty> tombstone(std::__init_disengaged);
+    assert(sizeof(tombstone) == sizeof(std::reference_wrapper<T>));
+
+    assert(!tombstone.__is_engaged());
+
+    tombstone.__engage(std::in_place, value);
+    assert(tombstone.__is_engaged());
+    assert(&tombstone.__get_value().get() == &value);
+  }
+}
+
+struct UserDefined {
+  int a = 1;
+};
+
+constexpr bool test() {
+  int my_int = 1;
+  test_type<int>(my_int);
+  test_type<const int>(my_int);
+
+  char my_char = 'a';
+  test_type<char>(my_char);
+
+  UserDefined my_struct;
+  test_type<UserDefined>(my_struct);
+
+  return true;
+}
+
+int main(int, char**) {
+  test();
+  static_assert(test());
+
+  return 0;
+}
diff --git a/libcxx/test/libcxx/memory/tombstone_traits/string.pass.cpp b/libcxx/test/libcxx/memory/tombstone_traits/string.pass.cpp
new file mode 100644
index 00000000000000..43889fac50b0d0
--- /dev/null
+++ b/libcxx/test/libcxx/memory/tombstone_traits/string.pass.cpp
@@ -0,0 +1,100 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: std-at-least-c++20
+
+// UNSUPPORTED: 32-bit-pointer
+// TODO: Expand tests to accommodate 32-bit pointers
+
+// tombstone_traits<basic_string>
+
+#include <__memory/tombstone_traits.h>
+#include <cassert>
+#include <cstddef>
+#include <string>
+#include <utility>
+
+struct Empty {
+  friend constexpr bool operator==(const Empty&, const Empty&) = default;
+};
+
+struct Size7Align1 {
+  char payload[7] = {'h', 'e', 'l', 'l', 'o', '1', '\0'};
+
+  friend constexpr bool operator==(const Size7Align1&, const Size7Align1&) = default;
+};
+
+struct Size16Align8 {
+  long long a = 1, b = 2;
+
+  friend constexpr bool operator==(const Size16Align8&, const Size16Align8&) = default;
+};
+
+template <class String, class Payload>
+constexpr void test_payload(std::size_t size) {
+  using CharT = typename String::value_type;
+  const String expected(size, CharT('a'));
+
+  // start engaged, disengage
+  {
+    std::__tombstoned_value<String, Payload> tombstone(std::__init_engaged, expected);
+    assert(sizeof(tombstone) == sizeof(String));
+
+    assert(tombstone.__is_engaged());
+    assert(tombstone.__get_value() == expected);
+    assert(std::as_const(tombstone).__get_value() == expected);
+
+    tombstone.__disengage(std::in_place, Payload{});
+    assert(!tombstone.__is_engaged());
+    assert(tombstone.__get_payload() == Payload{});
+  }
+
+  // start disengaged, then engage
+  {
+    std::__tombstoned_value<String, Payload> tombstone(std::__init_disengaged, Payload{});
+    assert(sizeof(tombstone) == sizeof(String));
+
+    assert(!tombstone.__is_engaged());
+    assert(tombstone.__get_payload() == Payload{});
+
+    tombstone.__engage(std::in_place, expected);
+    assert(tombstone.__is_engaged());
+    assert(tombstone.__get_value() == expected);
+  }
+}
+
+template <class String>
+constexpr void test_string() {
+  // Exercises both the short and the long representation
+  for (std::size_t size : {std::size_t(0), std::size_t(1), std::size_t(100)}) {
+    test_payload<String, Empty>(size);
+    test_payload<String, Size7Align1>(size);
+    test_payload<String, Size16Align8>(size);
+  }
+}
+
+constexpr bool test() {
+  test_string<std::string>();
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+  test_string<std::wstring>();
+#endif
+#ifndef TEST_HAS_NO_CHAR8_T
+  test_string<std::u8string>();
+#endif
+  test_string<std::u16string>();
+  test_string<std::u32string>();
+
+  return true;
+}
+
+int main(int, char**) {
+  test();
+  static_assert(test());
+
+  return 0;
+}
diff --git a/libcxx/test/libcxx/memory/tombstone_traits/unique_ptr.pass.cpp b/libcxx/test/libcxx/memory/tombstone_traits/unique_ptr.pass.cpp
new file mode 100644
index 00000000000000..0539e8d81474a0
--- /dev/null
+++ b/libcxx/test/libcxx/memory/tombstone_traits/unique_ptr.pass.cpp
@@ -0,0 +1,151 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: std-at-least-c++20
+
+// UNSUPPORTED: 32-bit-pointer
+// TODO: Expand tests to accommodate 32-bit pointers
+
+// tombstone_traits<unique_ptr>
+
+#include <__memory/tombstone_traits.h>
+#include <cassert>
+#include <memory>
+#include <utility>
+
+struct UserDefined {};
+
+struct CustomDeleter {
+  constexpr void operator()(int* ptr) const { delete ptr; }
+};
+
+// Only pointers that have a tombstone themselves and the default deleter get a tombstone
+static_assert(std::__has_tombstone_v<std::unique_ptr<int>>);
+static_assert(std::__has_tombstone_v<std::unique_ptr<int[]>>);
+static_assert(std::__has_tombstone_v<std::unique_ptr<int*>>);
+static_assert(!std::__has_tombstone_v<std::unique_ptr<char>>);
+static_assert(!std::__has_tombstone_v<std::unique_ptr<char[]>>);
+static_assert(!std::__has_tombstone_v<std::unique_ptr<UserDefined>>);
+static_assert(!std::__has_tombstone_v<std::unique_ptr<int, CustomDeleter>>);
+
+// Payloads that can fit into the available bytes given their padding
+
+struct Size7Align1 {
+  char payload[7] = {'h', 'e', 'l', 'l', 'o', '1', '\0'};
+
+  friend constexpr bool operator==(const Size7Align1&, const Size7Align1&) = default;
+};
+
+struct Size6Align2 {
+  short a = 1, b = 2, c = 3;
+
+  friend constexpr bool operator==(const Size6Align2&, const Size6Align2&) = default;
+};
+
+struct Size4Align4 {
+  int a = 1234;
+
+  friend constexpr bool operator==(const Size4Align4&, const Size4Align4&) = default;
+};
+
+template <class Payload>
+constexpr void test_single_object() {
+  // start engaged, disengage
+  {
+    std::__tombstoned_value<std::unique_ptr<int>, Payload> tombstone(std::__init_engaged, new int(3));
+    assert(sizeof(tombstone) == sizeof(std::unique_ptr<int>));
+
+    assert(tombstone.__is_engaged());
+    assert(*tombstone.__get_value() == 3);
+    assert(*std::as_const(tombstone).__get_value() == 3);
+
+    tombstone.__disengage(std::in_place, Payload{});
+    assert(!tombstone.__is_engaged());
+    assert(tombstone.__get_payload() == Payload{});
+  }
+
+  // start disengaged, then engage
+  {
+    std::__tombstoned_value<std::unique_ptr<int>, Payload> tombstone(std::__init_disengaged, Payload{});
+    assert(sizeof(tombstone) == sizeof(std::unique_ptr<int>));
+
+    assert(!tombstone.__is_engaged());
+    assert(tombstone.__get_payload() == Payload{});
+
+    tombstone.__engage(std::in_place, new int(3));
+    assert(tombstone.__is_engaged());
+    assert(*tombstone.__get_value() == 3);
+  }
+
+  // an empty unique_ptr is still engaged
+  {
+    std::__tombstoned_value<std::unique_ptr<int>, Payload> tombstone(std::__init_engaged);
+    assert(tombstone.__is_engaged());
+    assert(tombstone.__get_value() == nullptr);
+  }
+
+  // moving the value out leaves it engaged with an empty unique_ptr
+  {
+    std::__tombstoned_value<std::unique_ptr<int>, Payload> tombstone(std::__init_engaged, new int(3));
+    std::unique_ptr<int> moved = std::move(tombstone).__get_value();
+    assert(*moved == 3);
+
+    assert(tombstone.__is_engaged());
+    assert(tombstone.__get_value() == nullptr);
+  }
+}
+
+template <class Payload>
+constexpr void test_array() {
+  // start engaged, disengage
+  {
+    std::__tombstoned_value<std::unique_ptr<int[]>, Payload> tombstone(std::__init_engaged, new int[2]{3, 4});
+    assert(sizeof(tombstone) == sizeof(std::unique_ptr<int[]>));
+
+    assert(tombstone.__is_engaged());
+    assert(tombstone.__get_value()[0] == 3);
+    assert(tombstone.__get_value()[1] == 4);
+
+    tombstone.__disengage(std::in_place, Payload{});
+    assert(!tombstone.__is_engaged());
+    assert(tombstone.__get_payload() == Payload{});
+  }
+
+  // start disengaged, then engage
+  {
+    std::__tombstoned_value<std::unique_ptr<int[]>, Payload> tombstone(std::__init_disengaged, Payload{});
+    assert(sizeof(tombstone) == sizeof(std::unique_ptr<int[]>));
+
+    assert(!tombstone.__is_engaged());
+    assert(tombstone.__get_payload() == Payload{});
+
+    tombstone.__engage(std::in_place, new int[2]{3, 4});
+    assert(tombstone.__is_engaged());
+    assert(tombstone.__get_value()[0] == 3);
+    assert(tombstone.__get_value()[1] == 4);
+  }
+}
+
+constexpr bool test() {
+  test_single_object<Size7Align1>();
+  test_single_object<Size6Align2>();
+  test_single_object<Size4Align4>();
+
+  test_array<Size7Align1>();
+  test_array<Size6Align2>();
+  test_array<Size4Align4>();
+
+  return true;
+}
+
+int main(int, char**) {
+  test();
+  static_assert(test());
+
+  return 0;
+}

>From 708ec9be99b16b6a9c2b4c365b905faefecf57b4 Mon Sep 17 00:00:00 2001
From: William Tran-Viet <wtranviet at proton.me>
Date: Sat, 31 Oct 2026 02:32:42 -0400
Subject: [PATCH 10/12] Revert some changes

---
 libcxx/include/__utility/pair.h               |  2 +-
 libcxx/src/locale.cpp                         |  2 -
 .../test/libcxx/transitive_includes/cxx03.csv |  1 -
 .../test/libcxx/transitive_includes/cxx11.csv |  1 -
 .../test/libcxx/transitive_includes/cxx14.csv |  1 -
 .../test/libcxx/transitive_includes/cxx17.csv |  1 -
 .../test/libcxx/transitive_includes/cxx20.csv |  2 -
 .../test/libcxx/transitive_includes/cxx23.csv |  4 --
 .../test/libcxx/transitive_includes/cxx26.csv |  4 --
 .../optional/tombstone_types.pass.cpp         | 68 -------------------
 10 files changed, 1 insertion(+), 85 deletions(-)
 delete mode 100644 libcxx/test/std/utilities/optional/tombstone_types.pass.cpp

diff --git a/libcxx/include/__utility/pair.h b/libcxx/include/__utility/pair.h
index 86dc245d91493c..a65c178a9f0360 100644
--- a/libcxx/include/__utility/pair.h
+++ b/libcxx/include/__utility/pair.h
@@ -433,7 +433,7 @@ struct pair
 #if _LIBCPP_STD_VER >= 17
 template <class _T1, class _T2>
 pair(_T1, _T2) -> pair<_T1, _T2>;
-#endif // _LIBCPP_STD_VER >= 17
+#endif
 
 // [pairs.spec], specialized algorithms
 
diff --git a/libcxx/src/locale.cpp b/libcxx/src/locale.cpp
index 495c61696ccfdd..7795e9eab2fc7b 100644
--- a/libcxx/src/locale.cpp
+++ b/libcxx/src/locale.cpp
@@ -142,8 +142,6 @@ class _LIBCPP_HIDDEN locale::__imp : public facet {
   void install_from(const __imp& other);
 };
 
-static_assert(alignof(locale::__imp) == alignof(void*), "__tombstone_traits alignment is wrong!");
-
 locale::__imp::__imp(size_t refs) : facet(refs), facets_(N), name_("C") {
   facets_.clear();
   install(&make<std::collate<char> >(1u));
diff --git a/libcxx/test/libcxx/transitive_includes/cxx03.csv b/libcxx/test/libcxx/transitive_includes/cxx03.csv
index 929ba564d4381f..201fc2f36bf482 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx03.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx03.csv
@@ -234,7 +234,6 @@ experimental/iterator tuple
 experimental/iterator typeinfo
 experimental/iterator version
 experimental/memory cstdint
-experimental/memory cstdlib
 experimental/memory cstring
 experimental/memory version
 experimental/propagate_const version
diff --git a/libcxx/test/libcxx/transitive_includes/cxx11.csv b/libcxx/test/libcxx/transitive_includes/cxx11.csv
index adf7ebf2d7c80d..ab8791f9aa0747 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx11.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx11.csv
@@ -234,7 +234,6 @@ experimental/iterator tuple
 experimental/iterator typeinfo
 experimental/iterator version
 experimental/memory cstdint
-experimental/memory cstdlib
 experimental/memory cstring
 experimental/memory version
 experimental/propagate_const version
diff --git a/libcxx/test/libcxx/transitive_includes/cxx14.csv b/libcxx/test/libcxx/transitive_includes/cxx14.csv
index c1274500243f96..3d5030b5644e2b 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx14.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx14.csv
@@ -234,7 +234,6 @@ experimental/iterator tuple
 experimental/iterator typeinfo
 experimental/iterator version
 experimental/memory cstdint
-experimental/memory cstdlib
 experimental/memory cstring
 experimental/memory version
 experimental/propagate_const version
diff --git a/libcxx/test/libcxx/transitive_includes/cxx17.csv b/libcxx/test/libcxx/transitive_includes/cxx17.csv
index 0896b2f1b72673..8e3b1de5efd7ee 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx17.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx17.csv
@@ -243,7 +243,6 @@ experimental/iterator tuple
 experimental/iterator typeinfo
 experimental/iterator version
 experimental/memory cstdint
-experimental/memory cstdlib
 experimental/memory cstring
 experimental/memory version
 experimental/propagate_const version
diff --git a/libcxx/test/libcxx/transitive_includes/cxx20.csv b/libcxx/test/libcxx/transitive_includes/cxx20.csv
index 4ea0167247c080..b9d1dd17aa016f 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx20.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx20.csv
@@ -196,7 +196,6 @@ condition_variable typeinfo
 condition_variable version
 coroutine compare
 coroutine cstdint
-coroutine cstdlib
 coroutine cstring
 coroutine limits
 coroutine version
@@ -279,7 +278,6 @@ experimental/iterator typeinfo
 experimental/iterator variant
 experimental/iterator version
 experimental/memory cstdint
-experimental/memory cstdlib
 experimental/memory cstring
 experimental/memory version
 experimental/propagate_const version
diff --git a/libcxx/test/libcxx/transitive_includes/cxx23.csv b/libcxx/test/libcxx/transitive_includes/cxx23.csv
index 75120224ed18eb..83125257f35f54 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx23.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx23.csv
@@ -199,7 +199,6 @@ coroutine compare
 coroutine cstdint
 coroutine cstring
 coroutine limits
-coroutine new
 coroutine version
 cstddef version
 ctgmath bitset
@@ -283,7 +282,6 @@ experimental/iterator variant
 experimental/iterator version
 experimental/memory cstdint
 experimental/memory cstring
-experimental/memory new
 experimental/memory version
 experimental/propagate_const version
 experimental/simd cstdint
@@ -297,7 +295,6 @@ experimental/utility compare
 experimental/utility cstdint
 experimental/utility initializer_list
 experimental/utility limits
-experimental/utility new
 experimental/utility utility
 experimental/utility version
 filesystem cctype
@@ -1100,7 +1097,6 @@ utility compare
 utility cstdint
 utility initializer_list
 utility limits
-utility new
 utility version
 valarray cmath
 valarray cstdint
diff --git a/libcxx/test/libcxx/transitive_includes/cxx26.csv b/libcxx/test/libcxx/transitive_includes/cxx26.csv
index cb99de928efcc3..229e85afd106b7 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx26.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx26.csv
@@ -196,7 +196,6 @@ coroutine compare
 coroutine cstdint
 coroutine cstring
 coroutine limits
-coroutine new
 coroutine version
 cstddef version
 ctgmath bitset
@@ -280,7 +279,6 @@ experimental/iterator variant
 experimental/iterator version
 experimental/memory cstdint
 experimental/memory cstring
-experimental/memory new
 experimental/memory version
 experimental/propagate_const version
 experimental/simd cstdint
@@ -295,7 +293,6 @@ experimental/utility cstdint
 experimental/utility cstring
 experimental/utility initializer_list
 experimental/utility limits
-experimental/utility new
 experimental/utility utility
 experimental/utility version
 filesystem cctype
@@ -1093,7 +1090,6 @@ utility cstdint
 utility cstring
 utility initializer_list
 utility limits
-utility new
 utility version
 valarray cmath
 valarray cstdint
diff --git a/libcxx/test/std/utilities/optional/tombstone_types.pass.cpp b/libcxx/test/std/utilities/optional/tombstone_types.pass.cpp
deleted file mode 100644
index 43cab57d250713..00000000000000
--- a/libcxx/test/std/utilities/optional/tombstone_types.pass.cpp
+++ /dev/null
@@ -1,68 +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
-//
-//===----------------------------------------------------------------------===//
-
-// UNSUPPORTED: c++03, c++11, c++14
-// <optional>
-
-#include <cassert>
-#include <optional>
-#include <string>
-
-#include "test_macros.h"
-
-TEST_CONSTEXPR_CXX20 bool test() {
-  {
-    std::optional<bool> opt;
-    assert(!opt);
-    opt = true;
-    assert(opt);
-    assert(*opt);
-    opt = false;
-    assert(opt);
-    assert(!*opt);
-    opt.reset();
-    assert(!opt);
-  }
-
-  {
-    std::optional<std::string> opt;
-    assert(!opt);
-    opt = "";
-    assert(opt);
-    assert(*opt == "");
-    opt = "23 letter string to SSO";
-    assert(opt);
-    assert(*opt == "23 letter string to SSO");
-    opt.reset();
-    assert(!opt);
-  }
-
-  {
-    int i;
-    int j;
-    std::optional<int*> opt;
-    assert(!opt);
-    opt = &i;
-    assert(opt);
-    assert(*opt == &i);
-    opt = &j;
-    assert(opt);
-    assert(*opt == &j);
-    opt.reset();
-    assert(!opt);
-  }
-
-  return true;
-}
-
-int main(int, char**) {
-  test();
-#if TEST_STD_VER >= 20
-  static_assert(test());
-#endif
-}

>From bf1f0465560444688b3357bfdf50e11b350c3000 Mon Sep 17 00:00:00 2001
From: William Tran-Viet <wtranviet at proton.me>
Date: Sat, 31 Oct 2026 02:35:19 -0400
Subject: [PATCH 11/12] Update string_view

---
 libcxx/include/string_view                    |   8 +-
 .../tombstone_traits/string_view.pass.cpp     | 122 ++++++++++++++++++
 2 files changed, 127 insertions(+), 3 deletions(-)
 create mode 100644 libcxx/test/libcxx/memory/tombstone_traits/string_view.pass.cpp

diff --git a/libcxx/include/string_view b/libcxx/include/string_view
index 89f88aabc3dbf2..812448a6a54ac5 100644
--- a/libcxx/include/string_view
+++ b/libcxx/include/string_view
@@ -725,6 +725,10 @@ private:
 
   template <class, class, class>
   friend class basic_string;
+
+#  if _LIBCPP_STD_VER >= 20
+  friend struct __tombstone_traits<basic_string_view>;
+#  endif
 };
 _LIBCPP_CTAD_SUPPORTED_FOR_TYPE(basic_string_view);
 
@@ -734,15 +738,13 @@ inline constexpr bool ranges::enable_view<basic_string_view<_CharT, _Traits>> =
 
 template <class _CharT, class _Traits>
 inline constexpr bool ranges::enable_borrowed_range<basic_string_view<_CharT, _Traits> > = true;
-#  endif // _LIBCPP_STD_VER >= 20
 
-#if _LIBCPP_STD_VER >= 17
 template <class _CharT, class _Traits>
 struct __tombstone_traits<__enable_specialization_if<alignof(_CharT) >= 2, basic_string_view<_CharT, _Traits>>>
     : __tombstone_traits_assume_aligned_pointer<const _CharT*> {
   static_assert(__builtin_offsetof(basic_string_view<_CharT, _Traits>, __data_) == 0);
 };
-#endif
+#  endif // _LIBCPP_STD_VER >= 20
 
 // [string.view.deduct]
 
diff --git a/libcxx/test/libcxx/memory/tombstone_traits/string_view.pass.cpp b/libcxx/test/libcxx/memory/tombstone_traits/string_view.pass.cpp
new file mode 100644
index 00000000000000..00d9f91b057fa4
--- /dev/null
+++ b/libcxx/test/libcxx/memory/tombstone_traits/string_view.pass.cpp
@@ -0,0 +1,122 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: std-at-least-c++20
+
+// UNSUPPORTED: 32-bit-pointer
+// TODO: Expand tests to accommodate 32-bit pointers
+
+// tombstone_traits<basic_string_view>
+
+#include <__memory/tombstone_traits.h>
+#include <cassert>
+#include <string_view>
+#include <utility>
+
+#include "test_macros.h"
+
+// The tombstone relies on the low bit of the data pointer being unset, so characters must have an alignment of at
+// least 2.
+static_assert(!std::__has_tombstone_v<std::string_view>);
+#ifndef TEST_HAS_NO_CHAR8_T
+static_assert(!std::__has_tombstone_v<std::u8string_view>);
+#endif
+static_assert(std::__has_tombstone_v<std::u16string_view>);
+static_assert(std::__has_tombstone_v<std::u32string_view>);
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+static_assert(std::__has_tombstone_v<std::wstring_view>);
+#endif
+
+struct Empty {
+  friend constexpr bool operator==(const Empty&, const Empty&) = default;
+};
+
+// Payloads that can fit into the available bytes given their padding
+
+struct Size7Align1 {
+  char payload[7] = {'h', 'e', 'l', 'l', 'o', '1', '\0'};
+
+  friend constexpr bool operator==(const Size7Align1&, const Size7Align1&) = default;
+};
+
+struct Size6Align2 {
+  short a = 1, b = 2, c = 3;
+
+  friend constexpr bool operator==(const Size6Align2&, const Size6Align2&) = default;
+};
+
+struct Size4Align4 {
+  int a = 1234;
+
+  friend constexpr bool operator==(const Size4Align4&, const Size4Align4&) = default;
+};
+
+template <class View, class Payload>
+constexpr void test_payload(View expected) {
+  // start engaged, disengage
+  {
+    std::__tombstoned_value<View, Payload> tombstone(std::__init_engaged, expected);
+    assert(sizeof(tombstone) == sizeof(View));
+
+    assert(tombstone.__is_engaged());
+    assert(tombstone.__get_value().data() == expected.data());
+    assert(tombstone.__get_value().size() == expected.size());
+    assert(std::as_const(tombstone).__get_value() == expected);
+
+    tombstone.__disengage(std::in_place, Payload{});
+    assert(!tombstone.__is_engaged());
+    assert(tombstone.__get_payload() == Payload{});
+  }
+
+  // start disengaged, then engage
+  {
+    std::__tombstoned_value<View, Payload> tombstone(std::__init_disengaged, Payload{});
+    assert(sizeof(tombstone) == sizeof(View));
+
+    assert(!tombstone.__is_engaged());
+    assert(tombstone.__get_payload() == Payload{});
+
+    tombstone.__engage(std::in_place, expected.data(), expected.size());
+    assert(tombstone.__is_engaged());
+    assert(tombstone.__get_value().data() == expected.data());
+    assert(tombstone.__get_value().size() == expected.size());
+  }
+
+  // a default constructed string_view has a null data pointer, but it's still engaged
+  {
+    std::__tombstoned_value<View, Payload> tombstone(std::__init_engaged);
+    assert(tombstone.__is_engaged());
+    assert(tombstone.__get_value().data() == nullptr);
+    assert(tombstone.__get_value().empty());
+  }
+}
+
+template <class View>
+constexpr void test_view(View expected) {
+  test_payload<View, Empty>(expected);
+  test_payload<View, Size7Align1>(expected);
+  test_payload<View, Size6Align2>(expected);
+  test_payload<View, Size4Align4>(expected);
+}
+
+constexpr bool test() {
+  test_view<std::u16string_view>(u"hello");
+  test_view<std::u32string_view>(U"hello");
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+  test_view<std::wstring_view>(L"hello");
+#endif
+
+  return true;
+}
+
+int main(int, char**) {
+  test();
+  static_assert(test());
+
+  return 0;
+}

>From af411986a2ad1eccb062e8a9c62e2d8f212fa9a0 Mon Sep 17 00:00:00 2001
From: William Tran-Viet <wtranviet at proton.me>
Date: Sat, 31 Oct 2026 02:37:13 -0400
Subject: [PATCH 12/12] revert more things

---
 libcxx/include/__configuration/abi.h |  1 -
 libcxx/include/__memory/shared_ptr.h | 16 ++++++++--------
 2 files changed, 8 insertions(+), 9 deletions(-)

diff --git a/libcxx/include/__configuration/abi.h b/libcxx/include/__configuration/abi.h
index e637e217b5b8f7..9343eacf393449 100644
--- a/libcxx/include/__configuration/abi.h
+++ b/libcxx/include/__configuration/abi.h
@@ -86,7 +86,6 @@
 #  if defined(__FreeBSD__)
 #    define _LIBCPP_DEPRECATED_ABI_DISABLE_PAIR_TRIVIAL_COPY_CTOR
 #  endif
-
 #endif
 
 // We had some bugs where we use [[no_unique_address]] together with construct_at,
diff --git a/libcxx/include/__memory/shared_ptr.h b/libcxx/include/__memory/shared_ptr.h
index 21c311640b874c..0db58b37a6288b 100644
--- a/libcxx/include/__memory/shared_ptr.h
+++ b/libcxx/include/__memory/shared_ptr.h
@@ -654,6 +654,13 @@ class _LIBCPP_SHARED_PTR_TRIVIAL_ABI shared_ptr {
   friend class weak_ptr;
 };
 
+#if _LIBCPP_STD_VER >= 17
+template <class _Tp>
+shared_ptr(weak_ptr<_Tp>) -> shared_ptr<_Tp>;
+template <class _Tp, class _Dp>
+shared_ptr(unique_ptr<_Tp, _Dp>) -> shared_ptr<_Tp>;
+#endif
+
 //
 // std::allocate_shared and std::make_shared
 //
@@ -1288,19 +1295,12 @@ class _LIBCPP_SHARED_PTR_TRIVIAL_ABI weak_ptr {
   friend class weak_ptr;
   template <class _Up>
   friend class shared_ptr;
-
-  friend struct __tombstone_traits<weak_ptr<_Tp> >;
 };
 
 #if _LIBCPP_STD_VER >= 17
 template <class _Tp>
 weak_ptr(shared_ptr<_Tp>) -> weak_ptr<_Tp>;
-
-template <class _Tp>
-struct __tombstone_traits<weak_ptr<_Tp>> {
-
-};
-#endif // _LIBCPP_STD_VER >= 17
+#endif
 
 template <class _Tp>
 inline _LIBCPP_HIDE_FROM_ABI void swap(weak_ptr<_Tp>& __x, weak_ptr<_Tp>& __y) _NOEXCEPT {



More information about the libcxx-commits mailing list