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

via libcxx-commits libcxx-commits at lists.llvm.org
Sat Aug 8 12:43:39 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-libcxx

Author: William Tran-Viet (smallp-o-p)

<details>
<summary>Changes</summary>

- Remove the shared `__optional_storage_base` base class and associated partial specializations to handle the `T&` case in `optional<T>`
- Refactor and rename `optional<T&>`'s base classes.

---
Full diff: https://github.com/llvm/llvm-project/pull/215012.diff


3 Files Affected:

- (modified) libcxx/include/__optional/common.h (-3) 
- (modified) libcxx/include/__optional/optional.h (+11-6) 
- (modified) libcxx/include/__optional/optional_ref.h (+21-28) 


``````````diff
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..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_;
@@ -136,7 +146,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;
@@ -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");
 
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
 

``````````

</details>


https://github.com/llvm/llvm-project/pull/215012


More information about the libcxx-commits mailing list