[libcxx-commits] [libcxx] [libc++] Decouple `optional<T>` and `optional<T&>` base classes (PR #215012)

William Tran-Viet via libcxx-commits libcxx-commits at lists.llvm.org
Sun Aug 9 12:29:47 PDT 2026


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

>From 76da03f5c3f475c241cb12ed58db39a327a956ec Mon Sep 17 00:00:00 2001
From: William Tran-Viet <wtranviet at proton.me>
Date: Fri, 7 Aug 2026 16:19:10 -0400
Subject: [PATCH 1/9] [libc++] Decouple `optional<T>` and `optional<T&>` base
 classes

---
 libcxx/include/__optional/common.h       |  3 --
 libcxx/include/__optional/optional.h     |  2 +-
 libcxx/include/__optional/optional_ref.h | 49 ++++++++++--------------
 3 files changed, 22 insertions(+), 32 deletions(-)

diff --git a/libcxx/include/__optional/common.h b/libcxx/include/__optional/common.h
index 5ddb993f3e376..26031f658a904 100644
--- a/libcxx/include/__optional/common.h
+++ b/libcxx/include/__optional/common.h
@@ -64,9 +64,6 @@ inline constexpr bool __is_std_optional_v = false;
 template <class _Tp>
 inline constexpr bool __is_std_optional_v<optional<_Tp>> = true;
 
-template <class _Tp, bool = is_reference<_Tp>::value>
-struct __optional_storage_base;
-
 #  if _LIBCPP_STD_VER < 26
 template <class _Tp>
 inline constexpr bool __is_valid_optional_contained_type = is_object_v<_Tp>;
diff --git a/libcxx/include/__optional/optional.h b/libcxx/include/__optional/optional.h
index 8d6a9fbed8599..3cadbae1fcf14 100644
--- a/libcxx/include/__optional/optional.h
+++ b/libcxx/include/__optional/optional.h
@@ -136,7 +136,7 @@ struct __optional_destruct_base<_Tp, true> {
   }
 };
 
-template <class _Tp, bool>
+template <class _Tp>
 struct __optional_storage_base : __optional_destruct_base<_Tp> {
   using __base _LIBCPP_NODEBUG = __optional_destruct_base<_Tp>;
   using value_type             = _Tp;
diff --git a/libcxx/include/__optional/optional_ref.h b/libcxx/include/__optional/optional_ref.h
index d137b3c40c7e6..e99fc8cf8f143 100644
--- a/libcxx/include/__optional/optional_ref.h
+++ b/libcxx/include/__optional/optional_ref.h
@@ -49,17 +49,17 @@
 _LIBCPP_PUSH_MACROS
 #include <__undef_macros>
 
-#if _LIBCPP_STD_VER >= 17
+#if _LIBCPP_STD_VER >= 26
 
 _LIBCPP_BEGIN_NAMESPACE_STD
 
 template <class _Tp>
-struct __optional_storage_base<_Tp, true> {
+struct __optional_ref_base {
   using value_type                 = _Tp;
   using __raw_type _LIBCPP_NODEBUG = remove_reference_t<_Tp>;
   __raw_type* __value_;
 
-  _LIBCPP_HIDE_FROM_ABI constexpr __optional_storage_base() noexcept : __value_(nullptr) {}
+  _LIBCPP_HIDE_FROM_ABI constexpr __optional_ref_base() noexcept : __value_(nullptr) {}
 
   template <class _Up>
   _LIBCPP_HIDE_FROM_ABI constexpr void __convert_init_ref_val(_Up&& __val) {
@@ -68,7 +68,7 @@ struct __optional_storage_base<_Tp, true> {
   }
 
   template <class _UArg>
-  _LIBCPP_HIDE_FROM_ABI constexpr explicit __optional_storage_base(in_place_t, _UArg&& __uarg) {
+  _LIBCPP_HIDE_FROM_ABI constexpr explicit __optional_ref_base(in_place_t, _UArg&& __uarg) {
     static_assert(!__reference_constructs_from_temporary_v<_Tp, _UArg>,
                   "Attempted to construct a reference element in optional from a "
                   "possible temporary");
@@ -77,7 +77,7 @@ struct __optional_storage_base<_Tp, true> {
 
 #  if _LIBCPP_STD_VER >= 23
   template <class _Fp, class... _Args>
-  constexpr __optional_storage_base(__optional_construct_from_invoke_tag, _Fp&& __f, _Args&&... __args) {
+  constexpr __optional_ref_base(__optional_construct_from_invoke_tag, _Fp&& __f, _Args&&... __args) {
     __convert_init_ref_val(std::forward<invoke_result_t<_Fp, _Args...>>(
         std::invoke(std::forward<_Fp>(__f), std::forward<_Args>(__args)...)));
   }
@@ -116,7 +116,7 @@ struct __optional_storage_base<_Tp, true> {
     }
   }
 
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __swap(__optional_storage_base& __rhs) noexcept {
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __swap(__optional_ref_base& __rhs) noexcept {
     std::swap(__value_, __rhs.__value_);
   }
 
@@ -138,43 +138,38 @@ struct __optional_storage_base<_Tp, true> {
   }
 };
 
-#  if _LIBCPP_STD_VER >= 26
-
-template <class _Tp>
-struct __optional_iterator_base;
-
 template <class _Tp>
-struct __optional_iterator_base<_Tp&> : __optional_storage_base<_Tp&> {
-  using __optional_storage_base<_Tp&>::__optional_storage_base;
+struct __optional_ref_iterator_base : __optional_ref_base<_Tp&> {
+  using __optional_ref_base<_Tp&>::__optional_ref_base;
 };
 
-#    if _LIBCPP_HAS_EXPERIMENTAL_OPTIONAL_ITERATOR
+#  if _LIBCPP_HAS_EXPERIMENTAL_OPTIONAL_ITERATOR
 
 template <class _Tp>
   requires(is_object_v<_Tp> && !__is_unbounded_array_v<_Tp>)
-struct __optional_iterator_base<_Tp&> : __optional_storage_base<_Tp&> {
+struct __optional_ref_iterator_base<_Tp&> : __optional_ref_base<_Tp&> {
 private:
   using __pointer _LIBCPP_NODEBUG = add_pointer_t<_Tp>;
 
 public:
-  using __optional_storage_base<_Tp&>::__optional_storage_base;
+  using __optional_ref_base<_Tp&>::__optional_ref_base;
 
-#      ifdef _LIBCPP_ABI_BOUNDED_ITERATORS_IN_OPTIONAL
+#    ifdef _LIBCPP_ABI_BOUNDED_ITERATORS_IN_OPTIONAL
   using iterator = __bounded_iter<__pointer>;
-#      else
+#    else
   using iterator = __capacity_aware_iterator<__pointer, optional<_Tp&>, 1>;
-#      endif
+#    endif
 
   // [optional.ref.iterators], iterator support
 
   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto begin() const noexcept {
     auto* __ptr = this->has_value() ? std::addressof(this->__get()) : nullptr;
 
-#      ifdef _LIBCPP_ABI_BOUNDED_ITERATORS_IN_OPTIONAL
+#    ifdef _LIBCPP_ABI_BOUNDED_ITERATORS_IN_OPTIONAL
     return std::__make_bounded_iter(__ptr, __ptr, __ptr + (this->has_value() ? 1 : 0));
-#      else
+#    else
     return std::__make_capacity_aware_iterator<__pointer, optional<_Tp&>, 1>(__ptr);
-#      endif
+#    endif
   }
 
   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto end() const noexcept {
@@ -182,11 +177,11 @@ struct __optional_iterator_base<_Tp&> : __optional_storage_base<_Tp&> {
   }
 };
 
-#    endif
+#  endif
 
 template <class _Tp>
-class optional<_Tp&> : public __optional_iterator_base<_Tp&> {
-  using __base _LIBCPP_NODEBUG = __optional_iterator_base<_Tp&>;
+class optional<_Tp&> : public __optional_ref_iterator_base<_Tp&> {
+  using __base _LIBCPP_NODEBUG = __optional_ref_iterator_base<_Tp&>;
 
   template <class _Up, class _QualUp>
   static constexpr bool __check_optionalU_ctor =
@@ -346,11 +341,9 @@ class optional<_Tp&> : public __optional_iterator_base<_Tp&> {
   using __base::reset;
 };
 
-#  endif // _LIBCPP_STD_VER >= 26
-
 _LIBCPP_END_NAMESPACE_STD
 
-#endif // _LIBCPP_STD_VER >= 17
+#endif // _LIBCPP_STD_VER >= 26
 
 _LIBCPP_POP_MACROS
 

>From 0e679078af8f75b00b5448a3c5c80dbef6605873 Mon Sep 17 00:00:00 2001
From: William Tran-Viet <wtranviet at proton.me>
Date: Sat, 8 Aug 2026 15:37:28 -0400
Subject: [PATCH 2/9] Fix static assert error message

---
 libcxx/include/__optional/optional.h | 15 ++++++++++-----
 1 file changed, 10 insertions(+), 5 deletions(-)

diff --git a/libcxx/include/__optional/optional.h b/libcxx/include/__optional/optional.h
index 3cadbae1fcf14..7955ea2812d32 100644
--- a/libcxx/include/__optional/optional.h
+++ b/libcxx/include/__optional/optional.h
@@ -73,6 +73,11 @@ struct __optional_destruct_base;
 template <class _Tp>
 struct __optional_destruct_base<_Tp, false> {
   typedef _Tp value_type;
+#  if _LIBCPP_STD_VER >= 26
+  static_assert(!is_rvalue_reference_v<_Tp>, "instantiation of optional with an rvalue reference type is ill-formed");
+#  else
+  static_assert(!is_reference_v<_Tp>, "instantiation of optional with a reference type is ill-formed");
+#  endif
   static_assert(is_object_v<value_type>, "instantiation of optional with a non-object type is undefined behavior");
   union {
     char __null_state_;
@@ -109,6 +114,11 @@ struct __optional_destruct_base<_Tp, false> {
 template <class _Tp>
 struct __optional_destruct_base<_Tp, true> {
   typedef _Tp value_type;
+#  if _LIBCPP_STD_VER >= 26
+  static_assert(!is_rvalue_reference_v<_Tp>, "instantiation of optional with an rvalue reference type is ill-formed");
+#  else
+  static_assert(!is_reference_v<_Tp>, "instantiation of optional with a reference type is ill-formed");
+#  endif
   static_assert(is_object_v<value_type>, "instantiation of optional with a non-object type is undefined behavior");
   union {
     char __null_state_;
@@ -419,11 +429,6 @@ class _LIBCPP_DECLSPEC_EMPTY_BASES optional
 private:
   static_assert(!is_same_v<remove_cv_t<_Tp>, in_place_t>, "instantiation of optional with in_place_t is ill-formed");
   static_assert(!is_same_v<remove_cv_t<_Tp>, nullopt_t>, "instantiation of optional with nullopt_t is ill-formed");
-#  if _LIBCPP_STD_VER >= 26
-  static_assert(!is_rvalue_reference_v<_Tp>, "instantiation of optional with an rvalue reference type is ill-formed");
-#  else
-  static_assert(!is_reference_v<_Tp>, "instantiation of optional with a reference type is ill-formed");
-#  endif
   static_assert(is_destructible_v<_Tp>, "instantiation of optional with a non-destructible type is ill-formed");
   static_assert(!is_array_v<_Tp>, "instantiation of optional with an array type is ill-formed");
 

>From e90f5cc1012eed7bbae0e1dd09dfe303296a42c4 Mon Sep 17 00:00:00 2001
From: William Tran-Viet <wtranviet at proton.me>
Date: Sun, 9 Aug 2026 15:02:54 -0400
Subject: [PATCH 3/9] Inline optional<T> iterator base

---
 libcxx/include/__optional/optional.h | 107 ++++++++++++---------------
 1 file changed, 49 insertions(+), 58 deletions(-)

diff --git a/libcxx/include/__optional/optional.h b/libcxx/include/__optional/optional.h
index 7955ea2812d32..f864f5eddb90b 100644
--- a/libcxx/include/__optional/optional.h
+++ b/libcxx/include/__optional/optional.h
@@ -358,68 +358,12 @@ using __optional_sfinae_assign_base_t _LIBCPP_NODEBUG =
     __sfinae_assign_base< (is_copy_constructible_v<_Tp> && is_copy_assignable_v<_Tp>),
                           (is_move_constructible_v<_Tp> && is_move_assignable_v<_Tp>)>;
 
-template <class _Tp>
-struct __optional_iterator_base : __optional_move_assign_base<_Tp> {
-  using __optional_move_assign_base<_Tp>::__optional_move_assign_base;
-};
-
-#  if _LIBCPP_STD_VER >= 26 && _LIBCPP_HAS_EXPERIMENTAL_OPTIONAL_ITERATOR
-
-template <class _Tp>
-  requires is_object_v<_Tp>
-struct __optional_iterator_base<_Tp> : __optional_move_assign_base<_Tp> {
-private:
-  using __pointer _LIBCPP_NODEBUG       = add_pointer_t<_Tp>;
-  using __const_pointer _LIBCPP_NODEBUG = add_pointer_t<const _Tp>;
-
-public:
-  using __optional_move_assign_base<_Tp>::__optional_move_assign_base;
-
-#    ifdef _LIBCPP_ABI_BOUNDED_ITERATORS_IN_OPTIONAL
-  using iterator       = __bounded_iter<__pointer>;
-  using const_iterator = __bounded_iter<__const_pointer>;
-#    else
-  using iterator       = __capacity_aware_iterator<__pointer, optional<_Tp>, 1>;
-  using const_iterator = __capacity_aware_iterator<__const_pointer, optional<_Tp>, 1>;
-#    endif
-
-  // [optional.iterators], iterator support
-  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr iterator begin() noexcept {
-    auto* __ptr = std::addressof(this->__get());
-
-#    ifdef _LIBCPP_ABI_BOUNDED_ITERATORS_IN_OPTIONAL
-    return std::__make_bounded_iter(__ptr, __ptr, __ptr + (this->has_value() ? 1 : 0));
-#    else
-    return std::__make_capacity_aware_iterator<__pointer, optional<_Tp>, 1>(__ptr);
-#    endif
-  }
-
-  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr const_iterator begin() const noexcept {
-    auto* __ptr = std::addressof(this->__get());
-
-#    ifdef _LIBCPP_ABI_BOUNDED_ITERATORS_IN_OPTIONAL
-    return std::__make_bounded_iter(__ptr, __ptr, __ptr + (this->has_value() ? 1 : 0));
-#    else
-    return std::__make_capacity_aware_iterator<__const_pointer, optional<_Tp>, 1>(__ptr);
-#    endif
-  }
-
-  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr iterator end() noexcept {
-    return begin() + (this->has_value() ? 1 : 0);
-  }
-  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr const_iterator end() const noexcept {
-    return begin() + (this->has_value() ? 1 : 0);
-  }
-};
-
-#  endif // _LIBCPP_STD_VER >= 26 && _LIBCPP_HAS_EXPERIMENTAL_OPTIONAL_ITERATOR
-
 template <class _Tp>
 class _LIBCPP_DECLSPEC_EMPTY_BASES optional
-    : public __optional_iterator_base<_Tp>,
+    : public __optional_move_assign_base<_Tp>,
       private __optional_sfinae_ctor_base_t<_Tp>,
       private __optional_sfinae_assign_base_t<_Tp> {
-  using __base _LIBCPP_NODEBUG = __optional_iterator_base<_Tp>;
+  using __base _LIBCPP_NODEBUG = __optional_move_assign_base<_Tp>;
 
 public:
   using value_type = __libcpp_remove_reference_t<_Tp>;
@@ -750,6 +694,53 @@ class _LIBCPP_DECLSPEC_EMPTY_BASES optional
 #  endif // _LIBCPP_STD_VER >= 23
 
   using __base::reset;
+
+#  if _LIBCPP_STD_VER >= 26 && _LIBCPP_HAS_EXPERIMENTAL_OPTIONAL_ITERATOR
+
+private:
+  using __pointer _LIBCPP_NODEBUG       = add_pointer_t<_Tp>;
+  using __const_pointer _LIBCPP_NODEBUG = add_pointer_t<const _Tp>;
+
+public:
+  using __optional_move_assign_base<_Tp>::__optional_move_assign_base;
+
+#    ifdef _LIBCPP_ABI_BOUNDED_ITERATORS_IN_OPTIONAL
+  using iterator       = __bounded_iter<__pointer>;
+  using const_iterator = __bounded_iter<__const_pointer>;
+#    else
+  using iterator       = __capacity_aware_iterator<__pointer, optional<_Tp>, 1>;
+  using const_iterator = __capacity_aware_iterator<__const_pointer, optional<_Tp>, 1>;
+#    endif
+
+  // [optional.iterators], iterator support
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr iterator begin() noexcept {
+    auto* __ptr = std::addressof(this->__get());
+
+#    ifdef _LIBCPP_ABI_BOUNDED_ITERATORS_IN_OPTIONAL
+    return std::__make_bounded_iter(__ptr, __ptr, __ptr + (this->has_value() ? 1 : 0));
+#    else
+    return std::__make_capacity_aware_iterator<__pointer, optional<_Tp>, 1>(__ptr);
+#    endif
+  }
+
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr const_iterator begin() const noexcept {
+    auto* __ptr = std::addressof(this->__get());
+
+#    ifdef _LIBCPP_ABI_BOUNDED_ITERATORS_IN_OPTIONAL
+    return std::__make_bounded_iter(__ptr, __ptr, __ptr + (this->has_value() ? 1 : 0));
+#    else
+    return std::__make_capacity_aware_iterator<__const_pointer, optional<_Tp>, 1>(__ptr);
+#    endif
+  }
+
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr iterator end() noexcept {
+    return begin() + (this->has_value() ? 1 : 0);
+  }
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr const_iterator end() const noexcept {
+    return begin() + (this->has_value() ? 1 : 0);
+  }
+
+#  endif // _LIBCPP_STD_VER >= 26 && _LIBCPP_HAS_EXPERIMENTAL_OPTIONAL_ITERATOR
 };
 
 _LIBCPP_END_NAMESPACE_STD

>From a34f19711cf9924d2802d1cfd3755d634633b3db Mon Sep 17 00:00:00 2001
From: William Tran-Viet <wtranviet at proton.me>
Date: Sun, 9 Aug 2026 15:20:03 -0400
Subject: [PATCH 4/9] Inline optional<T> optional.observe

---
 libcxx/include/__optional/optional.h | 111 +++++++++++++--------------
 1 file changed, 53 insertions(+), 58 deletions(-)

diff --git a/libcxx/include/__optional/optional.h b/libcxx/include/__optional/optional.h
index f864f5eddb90b..99ee2578d4ff8 100644
--- a/libcxx/include/__optional/optional.h
+++ b/libcxx/include/__optional/optional.h
@@ -201,61 +201,6 @@ struct __optional_storage_base : __optional_destruct_base<_Tp> {
       }
     }
   }
-
-  // [optional.observe]
-  _LIBCPP_HIDE_FROM_ABI constexpr add_pointer_t<_Tp const> operator->() const noexcept {
-    _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(this->has_value(), "optional operator-> called on a disengaged value");
-    return std::addressof(this->__get());
-  }
-
-  _LIBCPP_HIDE_FROM_ABI constexpr add_pointer_t<_Tp> operator->() noexcept {
-    _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(this->has_value(), "optional operator-> called on a disengaged value");
-    return std::addressof(this->__get());
-  }
-
-  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr const _Tp& operator*() const& noexcept {
-    _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(this->has_value(), "optional operator* called on a disengaged value");
-    return this->__get();
-  }
-
-  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp& operator*() & noexcept {
-    _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(this->has_value(), "optional operator* called on a disengaged value");
-    return this->__get();
-  }
-
-  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp&& operator*() && noexcept {
-    _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(this->has_value(), "optional operator* called on a disengaged value");
-    return std::move(this->__get());
-  }
-
-  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr const _Tp&& operator*() const&& noexcept {
-    _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(this->has_value(), "optional operator* called on a disengaged value");
-    return std::move(this->__get());
-  }
-
-  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp const& value() const& {
-    if (!this->has_value())
-      std::__throw_bad_optional_access();
-    return this->__get();
-  }
-
-  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp& value() & {
-    if (!this->has_value())
-      std::__throw_bad_optional_access();
-    return this->__get();
-  }
-
-  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp&& value() && {
-    if (!this->has_value())
-      std::__throw_bad_optional_access();
-    return std::move(this->__get());
-  }
-
-  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp const&& value() const&& {
-    if (!this->has_value())
-      std::__throw_bad_optional_access();
-    return std::move(this->__get());
-  }
 };
 
 template <class _Tp, bool = is_trivially_copy_constructible_v<_Tp>>
@@ -554,14 +499,64 @@ class _LIBCPP_DECLSPEC_EMPTY_BASES optional
     this->__swap(__opt);
   }
 
-  using __base::operator*;
-  using __base::operator->;
+  // [optional.observe]
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr const _Tp& operator*() const& noexcept {
+    _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(this->has_value(), "optional operator* called on a disengaged value");
+    return this->__get();
+  }
+
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp& operator*() & noexcept {
+    _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(this->has_value(), "optional operator* called on a disengaged value");
+    return this->__get();
+  }
+
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp&& operator*() && noexcept {
+    _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(this->has_value(), "optional operator* called on a disengaged value");
+    return std::move(this->__get());
+  }
+
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr const _Tp&& operator*() const&& noexcept {
+    _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(this->has_value(), "optional operator* called on a disengaged value");
+    return std::move(this->__get());
+  }
+  _LIBCPP_HIDE_FROM_ABI constexpr add_pointer_t<_Tp const> operator->() const noexcept {
+    _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(this->has_value(), "optional operator-> called on a disengaged value");
+    return std::addressof(this->__get());
+  }
+
+  _LIBCPP_HIDE_FROM_ABI constexpr add_pointer_t<_Tp> operator->() noexcept {
+    _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(this->has_value(), "optional operator-> called on a disengaged value");
+    return std::addressof(this->__get());
+  }
+
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp const& value() const& {
+    if (!this->has_value())
+      std::__throw_bad_optional_access();
+    return this->__get();
+  }
+
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp& value() & {
+    if (!this->has_value())
+      std::__throw_bad_optional_access();
+    return this->__get();
+  }
+
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp&& value() && {
+    if (!this->has_value())
+      std::__throw_bad_optional_access();
+    return std::move(this->__get());
+  }
+
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp const&& value() const&& {
+    if (!this->has_value())
+      std::__throw_bad_optional_access();
+    return std::move(this->__get());
+  }
 
   _LIBCPP_HIDE_FROM_ABI constexpr explicit operator bool() const noexcept { return has_value(); }
 
   using __base::__get;
   using __base::has_value;
-  using __base::value;
 
   template <class _Up = remove_cv_t<_Tp>>
   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp value_or(_Up&& __v) const& {

>From a8c64b867945fd9addda6fcafc6613ad2d1a67b3 Mon Sep 17 00:00:00 2001
From: William Tran-Viet <wtranviet at proton.me>
Date: Sun, 9 Aug 2026 15:21:12 -0400
Subject: [PATCH 5/9] Inline optional<T> swap

---
 libcxx/include/__optional/optional.h | 31 ++++++++++++----------------
 1 file changed, 13 insertions(+), 18 deletions(-)

diff --git a/libcxx/include/__optional/optional.h b/libcxx/include/__optional/optional.h
index 99ee2578d4ff8..5aa3c936760b7 100644
--- a/libcxx/include/__optional/optional.h
+++ b/libcxx/include/__optional/optional.h
@@ -184,23 +184,6 @@ struct __optional_storage_base : __optional_destruct_base<_Tp> {
         __construct(std::forward<_That>(__opt).__get());
     }
   }
-
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void
-  __swap(__optional_storage_base& __rhs) noexcept(is_nothrow_move_constructible_v<_Tp> && is_nothrow_swappable_v<_Tp>) {
-    using std::swap;
-    if (this->has_value() == __rhs.has_value()) {
-      if (this->has_value())
-        swap(this->__get(), __rhs.__get());
-    } else {
-      if (this->has_value()) {
-        __rhs.__construct(std::move(this->__get()));
-        this->reset();
-      } else {
-        this->__construct(std::move(__rhs.__get()));
-        __rhs.reset();
-      }
-    }
-  }
 };
 
 template <class _Tp, bool = is_trivially_copy_constructible_v<_Tp>>
@@ -496,7 +479,19 @@ class _LIBCPP_DECLSPEC_EMPTY_BASES optional
 
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void
   swap(optional& __opt) noexcept((is_nothrow_move_constructible_v<_Tp> && is_nothrow_swappable_v<_Tp>)) {
-    this->__swap(__opt);
+    using std::swap;
+    if (this->has_value() == __opt.has_value()) {
+      if (this->has_value())
+        swap(this->__get(), __opt.__get());
+    } else {
+      if (this->has_value()) {
+        __opt.__construct(std::move(this->__get()));
+        this->reset();
+      } else {
+        this->__construct(std::move(__opt.__get()));
+        __opt.reset();
+      }
+    }
   }
 
   // [optional.observe]

>From 6cc48cf353c116af85969cfba240f2f675d5ee7e Mon Sep 17 00:00:00 2001
From: William Tran-Viet <wtranviet at proton.me>
Date: Sun, 9 Aug 2026 15:23:09 -0400
Subject: [PATCH 6/9] Inline optional.ref.observer

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

diff --git a/libcxx/include/__optional/optional_ref.h b/libcxx/include/__optional/optional_ref.h
index e99fc8cf8f143..37a9d91b961b5 100644
--- a/libcxx/include/__optional/optional_ref.h
+++ b/libcxx/include/__optional/optional_ref.h
@@ -119,23 +119,6 @@ struct __optional_ref_base {
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __swap(__optional_ref_base& __rhs) noexcept {
     std::swap(__value_, __rhs.__value_);
   }
-
-  // [optional.ref.observe]
-  _LIBCPP_HIDE_FROM_ABI constexpr add_pointer_t<_Tp> operator->() const noexcept {
-    _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(this->has_value(), "optional operator-> called on a disengaged value");
-    return std::addressof(this->__get());
-  }
-
-  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp& operator*() const noexcept {
-    _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(this->has_value(), "optional operator* called on a disengaged value");
-    return this->__get();
-  }
-
-  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp& value() const {
-    if (!this->has_value())
-      std::__throw_bad_optional_access();
-    return this->__get();
-  }
 };
 
 template <class _Tp>
@@ -288,13 +271,26 @@ class optional<_Tp&> : public __optional_ref_iterator_base<_Tp&> {
 
   constexpr void swap(optional& __rhs) noexcept { this->__swap(__rhs); }
 
-  using __base::operator->;
-  using __base::operator*;
+  // [optional.ref.observe]
+  _LIBCPP_HIDE_FROM_ABI constexpr add_pointer_t<_Tp> operator->() const noexcept {
+    _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(this->has_value(), "optional operator-> called on a disengaged value");
+    return std::addressof(this->__get());
+  }
+
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp& operator*() const noexcept {
+    _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(this->has_value(), "optional operator* called on a disengaged value");
+    return this->__get();
+  }
 
   constexpr explicit operator bool() const noexcept { return has_value(); }
 
   using __base::has_value;
-  using __base::value;
+
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp& value() const {
+    if (!this->has_value())
+      std::__throw_bad_optional_access();
+    return this->__get();
+  }
 
   template <class _Up = remove_cv_t<_Tp>>
     requires(!is_array_v<_Tp> && is_object_v<_Tp>)

>From 2cc421cee195a42940dc5a729cb2d0f38ea21131 Mon Sep 17 00:00:00 2001
From: William Tran-Viet <wtranviet at proton.me>
Date: Sun, 9 Aug 2026 15:23:21 -0400
Subject: [PATCH 7/9] Delete redundant __assign_from

---
 libcxx/include/__optional/optional_ref.h | 13 -------------
 1 file changed, 13 deletions(-)

diff --git a/libcxx/include/__optional/optional_ref.h b/libcxx/include/__optional/optional_ref.h
index 37a9d91b961b5..b280b8cff40e7 100644
--- a/libcxx/include/__optional/optional_ref.h
+++ b/libcxx/include/__optional/optional_ref.h
@@ -103,19 +103,6 @@ struct __optional_ref_base {
       __construct(std::forward<_That>(__opt).__get());
   }
 
-  template <class _That>
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __assign_from(_That&& __opt) {
-    if (has_value() == __opt.has_value()) {
-      if (has_value())
-        *__value_ = std::forward<_That>(__opt).__get();
-    } else {
-      if (has_value())
-        reset();
-      else
-        __construct(std::forward<_That>(__opt).__get());
-    }
-  }
-
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __swap(__optional_ref_base& __rhs) noexcept {
     std::swap(__value_, __rhs.__value_);
   }

>From f3d29330849d61b7e9f6a16696ba923911b5ab17 Mon Sep 17 00:00:00 2001
From: William Tran-Viet <wtranviet at proton.me>
Date: Sun, 9 Aug 2026 15:25:31 -0400
Subject: [PATCH 8/9] Inline optional<T&> swap

---
 libcxx/include/__optional/optional_ref.h | 6 +-----
 1 file changed, 1 insertion(+), 5 deletions(-)

diff --git a/libcxx/include/__optional/optional_ref.h b/libcxx/include/__optional/optional_ref.h
index b280b8cff40e7..29809e2d8c4f3 100644
--- a/libcxx/include/__optional/optional_ref.h
+++ b/libcxx/include/__optional/optional_ref.h
@@ -102,10 +102,6 @@ struct __optional_ref_base {
     if (__opt.has_value())
       __construct(std::forward<_That>(__opt).__get());
   }
-
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __swap(__optional_ref_base& __rhs) noexcept {
-    std::swap(__value_, __rhs.__value_);
-  }
 };
 
 template <class _Tp>
@@ -256,7 +252,7 @@ class optional<_Tp&> : public __optional_ref_iterator_base<_Tp&> {
     return this->__get();
   }
 
-  constexpr void swap(optional& __rhs) noexcept { this->__swap(__rhs); }
+  constexpr void swap(optional& __rhs) noexcept { std::swap(this->__value_, __rhs.__value_); }
 
   // [optional.ref.observe]
   _LIBCPP_HIDE_FROM_ABI constexpr add_pointer_t<_Tp> operator->() const noexcept {

>From 0c02a21769efeaf3bd385a8f7919d60b9b4d470e Mon Sep 17 00:00:00 2001
From: William Tran-Viet <wtranviet at proton.me>
Date: Sun, 9 Aug 2026 15:26:11 -0400
Subject: [PATCH 9/9] Replace redundant _LIBCPP_CONSTEXPR_SINCE_CXX20

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

diff --git a/libcxx/include/__optional/optional_ref.h b/libcxx/include/__optional/optional_ref.h
index 29809e2d8c4f3..9207d22f8f9b7 100644
--- a/libcxx/include/__optional/optional_ref.h
+++ b/libcxx/include/__optional/optional_ref.h
@@ -83,14 +83,14 @@ struct __optional_ref_base {
   }
 #  endif
 
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void reset() noexcept { __value_ = nullptr; }
+  _LIBCPP_HIDE_FROM_ABI constexpr void reset() noexcept { __value_ = nullptr; }
 
   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool has_value() const noexcept { return __value_ != nullptr; }
 
   _LIBCPP_HIDE_FROM_ABI constexpr value_type& __get() const noexcept { return *__value_; }
 
   template <class _UArg>
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __construct(_UArg&& __val) {
+  _LIBCPP_HIDE_FROM_ABI constexpr void __construct(_UArg&& __val) {
     static_assert(!__reference_constructs_from_temporary_v<_Tp, _UArg>,
                   "Attempted to construct a reference element in tuple from a "
                   "possible temporary");
@@ -98,7 +98,7 @@ struct __optional_ref_base {
   }
 
   template <class _That>
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __construct_from(_That&& __opt) {
+  _LIBCPP_HIDE_FROM_ABI constexpr void __construct_from(_That&& __opt) {
     if (__opt.has_value())
       __construct(std::forward<_That>(__opt).__get());
   }



More information about the libcxx-commits mailing list