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

William Tran-Viet via libcxx-commits libcxx-commits at lists.llvm.org
Fri Oct 30 23:45:38 PDT 2026


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

Follows-up (or supersedes) #98498

The basic idea is that we can define tombstone traits for certain types which have an "obvious" invalid bit pattern in memory. Using this, we can optimize sum types like `optional` and `variant` because we no longer need a separate `bool` to announce that the held object is no longer valid.

This PR is deliberately more constrained than the #98498 so it's easier to review.

The following are not present here but are there:
  - `optional` integration
  - `shared_ptr` integration
  - `pair` integration
  - `vector` integration
  - `locale` integration

There is also a difference in that this is only available since C++20, but not C++17, which may complicate some later integration. I couldn't figure out a way around the `if consteval` checks.

### AI Disclosure
Tests were generated with AI assistance.

>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