[libcxx-commits] [libcxx] [libc++] Remove `optional::iterator` from experimental mode (PR #203782)

William Tran-Viet via libcxx-commits libcxx-commits at lists.llvm.org
Sun Jun 14 11:54:54 PDT 2026


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

>From 0daa357edac4824cb4d025e7e2a3c780e461080b Mon Sep 17 00:00:00 2001
From: William Tran-Viet <wtranviet at proton.me>
Date: Sun, 14 Jun 2026 14:49:29 -0400
Subject: [PATCH 1/2] Remove `optional::iterator` from experimental mode

---
 libcxx/docs/ReleaseNotes/23.rst               |  1 +
 libcxx/include/__configuration/experimental.h |  1 -
 libcxx/include/optional                       | 37 +++++++++----------
 libcxx/include/version                        |  4 +-
 libcxx/modules/std/optional.inc               |  4 +-
 .../fexperimental-library.compile.pass.cpp    |  4 --
 .../utilities/optional/nodiscard.verify.cpp   |  4 +-
 .../optional.version.compile.pass.cpp         | 16 +++-----
 .../version.version.compile.pass.cpp          | 16 +++-----
 .../generate_feature_test_macro_components.py |  2 -
 10 files changed, 32 insertions(+), 57 deletions(-)

diff --git a/libcxx/docs/ReleaseNotes/23.rst b/libcxx/docs/ReleaseNotes/23.rst
index 7823c2db39867..726e576ef4038 100644
--- a/libcxx/docs/ReleaseNotes/23.rst
+++ b/libcxx/docs/ReleaseNotes/23.rst
@@ -65,6 +65,7 @@ Improvements and New Features
   ``"std::visit: variant is valueless"``, ``"std::get: variant is valueless"``, or
   ``"std::get: wrong alternative for variant"``. The standard only requires ``what()`` to return an
   unspecified non-null string, so user code that does not match on the exact message remains correct.
+- ``optional::iterator`` is no longer experimental.
 
 Deprecations and Removals
 -------------------------
diff --git a/libcxx/include/__configuration/experimental.h b/libcxx/include/__configuration/experimental.h
index bb38d8297c63d..d14df3e5175f3 100644
--- a/libcxx/include/__configuration/experimental.h
+++ b/libcxx/include/__configuration/experimental.h
@@ -33,6 +33,5 @@
 #define _LIBCPP_HAS_EXPERIMENTAL_TZDB _LIBCPP_HAS_EXPERIMENTAL_LIBRARY
 #define _LIBCPP_HAS_EXPERIMENTAL_SYNCSTREAM _LIBCPP_HAS_EXPERIMENTAL_LIBRARY
 #define _LIBCPP_HAS_EXPERIMENTAL_HARDENING_OBSERVE_SEMANTIC _LIBCPP_HAS_EXPERIMENTAL_LIBRARY
-#define _LIBCPP_HAS_EXPERIMENTAL_OPTIONAL_ITERATOR _LIBCPP_HAS_EXPERIMENTAL_LIBRARY
 
 #endif // _LIBCPP___CONFIGURATION_EXPERIMENTAL_H
diff --git a/libcxx/include/optional b/libcxx/include/optional
index 66995435b5109..43e8511a95789 100644
--- a/libcxx/include/optional
+++ b/libcxx/include/optional
@@ -737,7 +737,7 @@ using __optional_sfinae_assign_base_t _LIBCPP_NODEBUG =
 template <class _Tp>
 class optional;
 
-#    if _LIBCPP_STD_VER >= 26 && _LIBCPP_HAS_EXPERIMENTAL_OPTIONAL_ITERATOR
+#    if _LIBCPP_STD_VER >= 26
 template <class _Tp>
 constexpr bool ranges::enable_view<optional<_Tp>> = true;
 
@@ -780,8 +780,6 @@ struct __optional_iterator_base<_Tp&> : __optional_storage_base<_Tp&> {
   using __optional_storage_base<_Tp&>::__optional_storage_base;
 };
 
-#      if _LIBCPP_HAS_EXPERIMENTAL_OPTIONAL_ITERATOR
-
 template <class _Tp>
   requires is_object_v<_Tp>
 struct __optional_iterator_base<_Tp> : __optional_move_assign_base<_Tp> {
@@ -792,33 +790,33 @@ private:
 public:
   using __optional_move_assign_base<_Tp>::__optional_move_assign_base;
 
-#        ifdef _LIBCPP_ABI_BOUNDED_ITERATORS_IN_OPTIONAL
+#      ifdef _LIBCPP_ABI_BOUNDED_ITERATORS_IN_OPTIONAL
   using iterator       = __bounded_iter<__pointer>;
   using const_iterator = __bounded_iter<__const_pointer>;
-#        else
+#      else
   using iterator       = __capacity_aware_iterator<__pointer, optional<_Tp>, 1>;
   using const_iterator = __capacity_aware_iterator<__const_pointer, optional<_Tp>, 1>;
-#        endif
+#      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
+#      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 const_iterator begin() const noexcept {
     auto* __ptr = std::addressof(this->__get());
 
-#        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<__const_pointer, optional<_Tp>, 1>(__ptr);
-#        endif
+#      endif
   }
 
   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr iterator end() noexcept {
@@ -838,22 +836,22 @@ private:
 public:
   using __optional_storage_base<_Tp&>::__optional_storage_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 {
@@ -861,8 +859,7 @@ public:
   }
 };
 
-#      endif // _LIBCPP_HAS_EXPERIMENTAL_OPTIONAL_ITERATOR
-#    endif   // _LIBCPP_STD_VER >= 26
+#    endif // _LIBCPP_STD_VER >= 26
 
 template <class _Tp>
 class _LIBCPP_DECLSPEC_EMPTY_BASES optional
diff --git a/libcxx/include/version b/libcxx/include/version
index 7f2dc9e4b72ab..9d3d7395f98e5 100644
--- a/libcxx/include/version
+++ b/libcxx/include/version
@@ -611,9 +611,7 @@ __cpp_lib_void_t                                        201411L <type_traits>
 # define __cpp_lib_not_fn                               202306L
 # undef  __cpp_lib_optional
 # define __cpp_lib_optional                             202506L
-# if _LIBCPP_HAS_EXPERIMENTAL_OPTIONAL_ITERATOR
-#   define __cpp_lib_optional_range_support             202406L
-# endif
+# define __cpp_lib_optional_range_support               202406L
 # undef  __cpp_lib_out_ptr
 # define __cpp_lib_out_ptr                              202311L
 // # define __cpp_lib_philox_engine                        202406L
diff --git a/libcxx/modules/std/optional.inc b/libcxx/modules/std/optional.inc
index 8196a8dde577c..88de0bb4db12b 100644
--- a/libcxx/modules/std/optional.inc
+++ b/libcxx/modules/std/optional.inc
@@ -10,7 +10,7 @@
 export namespace std {
   // [optional.optional], class template optional
   using std::optional;
-#if _LIBCPP_STD_VER >= 26 && _LIBCPP_HAS_EXPERIMENTAL_OPTIONAL_ITERATOR
+#if _LIBCPP_STD_VER >= 26
   // [optional.iterators], iterator support
   namespace ranges {
     using std::ranges::enable_borrowed_range;
@@ -24,7 +24,7 @@ export namespace std {
   // [optional.bad.access], class bad_optional_access
   using std::bad_optional_access;
 
-#if _LIBCPP_STD_VER >= 26 && _LIBCPP_HAS_EXPERIMENTAL_OPTIONAL_ITERATOR
+#if _LIBCPP_STD_VER >= 26
   using std::format_kind;
 #endif
 
diff --git a/libcxx/test/libcxx/experimental/fexperimental-library.compile.pass.cpp b/libcxx/test/libcxx/experimental/fexperimental-library.compile.pass.cpp
index 82fd1ad4d9a16..479b46a39e963 100644
--- a/libcxx/test/libcxx/experimental/fexperimental-library.compile.pass.cpp
+++ b/libcxx/test/libcxx/experimental/fexperimental-library.compile.pass.cpp
@@ -16,10 +16,6 @@
 
 #include <version>
 
-#if !_LIBCPP_HAS_EXPERIMENTAL_OPTIONAL_ITERATOR
-#  error "-fexperimental-library should enable optional::iterator"
-#endif
-
 #if !_LIBCPP_HAS_EXPERIMENTAL_PSTL
 #  error "-fexperimental-library should enable the PSTL"
 #endif
diff --git a/libcxx/test/libcxx/utilities/optional/nodiscard.verify.cpp b/libcxx/test/libcxx/utilities/optional/nodiscard.verify.cpp
index 0ae368b4f87ce..c49546cfdf4ad 100644
--- a/libcxx/test/libcxx/utilities/optional/nodiscard.verify.cpp
+++ b/libcxx/test/libcxx/utilities/optional/nodiscard.verify.cpp
@@ -32,7 +32,7 @@ void test() {
 
   opt.has_value(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
 
-#if TEST_STD_VER >= 26 && _LIBCPP_HAS_EXPERIMENTAL_OPTIONAL_ITERATOR
+#if TEST_STD_VER >= 26
   opt.begin();  // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
   cOpt.begin(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
   opt.end();    // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
@@ -92,10 +92,8 @@ void test() {
 
   optRef.has_value(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
 
-#  if _LIBCPP_HAS_EXPERIMENTAL_OPTIONAL_ITERATOR
   optRef.begin(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
   optRef.end();   // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
-#  endif
 
   *optRef;  // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
   *cOptRef; // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/optional.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/optional.version.compile.pass.cpp
index 9850c20afec87..c4e652979a4e6 100644
--- a/libcxx/test/std/language.support/support.limits/support.limits.general/optional.version.compile.pass.cpp
+++ b/libcxx/test/std/language.support/support.limits/support.limits.general/optional.version.compile.pass.cpp
@@ -146,17 +146,11 @@
 #    error "__cpp_lib_optional should have the value 202506L in c++26"
 #  endif
 
-#  if !defined(_LIBCPP_VERSION) || _LIBCPP_HAS_EXPERIMENTAL_OPTIONAL_ITERATOR
-#    ifndef __cpp_lib_optional_range_support
-#      error "__cpp_lib_optional_range_support should be defined in c++26"
-#    endif
-#    if __cpp_lib_optional_range_support != 202406L
-#      error "__cpp_lib_optional_range_support should have the value 202406L in c++26"
-#    endif
-#  else
-#    ifdef __cpp_lib_optional_range_support
-#      error "__cpp_lib_optional_range_support should not be defined when the requirement '!defined(_LIBCPP_VERSION) || _LIBCPP_HAS_EXPERIMENTAL_OPTIONAL_ITERATOR' is not met!"
-#    endif
+#  ifndef __cpp_lib_optional_range_support
+#    error "__cpp_lib_optional_range_support should be defined in c++26"
+#  endif
+#  if __cpp_lib_optional_range_support != 202406L
+#    error "__cpp_lib_optional_range_support should have the value 202406L in c++26"
 #  endif
 
 #endif // TEST_STD_VER > 23
diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp
index d9c78b73f7e23..ac4e0003347a6 100644
--- a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp
+++ b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp
@@ -7586,17 +7586,11 @@
 #    error "__cpp_lib_optional should have the value 202506L in c++26"
 #  endif
 
-#  if !defined(_LIBCPP_VERSION) || _LIBCPP_HAS_EXPERIMENTAL_OPTIONAL_ITERATOR
-#    ifndef __cpp_lib_optional_range_support
-#      error "__cpp_lib_optional_range_support should be defined in c++26"
-#    endif
-#    if __cpp_lib_optional_range_support != 202406L
-#      error "__cpp_lib_optional_range_support should have the value 202406L in c++26"
-#    endif
-#  else
-#    ifdef __cpp_lib_optional_range_support
-#      error "__cpp_lib_optional_range_support should not be defined when the requirement '!defined(_LIBCPP_VERSION) || _LIBCPP_HAS_EXPERIMENTAL_OPTIONAL_ITERATOR' is not met!"
-#    endif
+#  ifndef __cpp_lib_optional_range_support
+#    error "__cpp_lib_optional_range_support should be defined in c++26"
+#  endif
+#  if __cpp_lib_optional_range_support != 202406L
+#    error "__cpp_lib_optional_range_support should have the value 202406L in c++26"
 #  endif
 
 #  ifndef __cpp_lib_out_ptr
diff --git a/libcxx/utils/generate_feature_test_macro_components.py b/libcxx/utils/generate_feature_test_macro_components.py
index d764a1f677ba6..02e79ad7ca38f 100644
--- a/libcxx/utils/generate_feature_test_macro_components.py
+++ b/libcxx/utils/generate_feature_test_macro_components.py
@@ -1039,8 +1039,6 @@ def add_version_header(tc):
             "name": "__cpp_lib_optional_range_support",
             "values": {"c++26": 202406},  # P3168R2 Give std::optional Range Support
             "headers": ["optional"],
-            "test_suite_guard": "!defined(_LIBCPP_VERSION) || _LIBCPP_HAS_EXPERIMENTAL_OPTIONAL_ITERATOR",
-            "libcxx_guard": "_LIBCPP_HAS_EXPERIMENTAL_OPTIONAL_ITERATOR",
         },
         {
             "name": "__cpp_lib_out_ptr",

>From 3aff5a1dd1a74abe4ec54d669df3de0a72eedb36 Mon Sep 17 00:00:00 2001
From: William Tran-Viet <wtranviet at proton.me>
Date: Sun, 14 Jun 2026 14:54:46 -0400
Subject: [PATCH 2/2] Tests

---
 .../libcxx/utilities/optional/nodiscard.iterator.verify.cpp     | 2 --
 .../optional/optional.iterator/iterator.compile.pass.cpp        | 2 +-
 .../std/utilities/optional/optional.iterator/begin.pass.cpp     | 2 --
 .../optional/optional.iterator/borrowed_range.compile.pass.cpp  | 2 --
 .../std/utilities/optional/optional.iterator/compare.pass.cpp   | 1 -
 .../test/std/utilities/optional/optional.iterator/end.pass.cpp  | 2 --
 .../std/utilities/optional/optional.iterator/iterator.pass.cpp  | 2 --
 libcxx/utils/libcxx/test/params.py                              | 1 -
 8 files changed, 1 insertion(+), 13 deletions(-)

diff --git a/libcxx/test/libcxx/utilities/optional/nodiscard.iterator.verify.cpp b/libcxx/test/libcxx/utilities/optional/nodiscard.iterator.verify.cpp
index a3945000cbb77..7fd9649887012 100644
--- a/libcxx/test/libcxx/utilities/optional/nodiscard.iterator.verify.cpp
+++ b/libcxx/test/libcxx/utilities/optional/nodiscard.iterator.verify.cpp
@@ -8,8 +8,6 @@
 
 // REQUIRES: std-at-least-c++26
 
-// UNSUPPORTED: libcpp-has-no-experimental-optional-iterator
-
 // <optional>
 
 // Check that functions are marked [[nodiscard]]
diff --git a/libcxx/test/libcxx/utilities/optional/optional.iterator/iterator.compile.pass.cpp b/libcxx/test/libcxx/utilities/optional/optional.iterator/iterator.compile.pass.cpp
index 265d39c97cb39..b12d421adef7d 100644
--- a/libcxx/test/libcxx/utilities/optional/optional.iterator/iterator.compile.pass.cpp
+++ b/libcxx/test/libcxx/utilities/optional/optional.iterator/iterator.compile.pass.cpp
@@ -10,7 +10,7 @@
 
 // <optional>
 
-// UNSUPPORTED: libcpp-has-abi-bounded-iterators-in-optional, libcpp-has-no-experimental-optional-iterator
+// UNSUPPORTED: libcpp-has-abi-bounded-iterators-in-optional
 
 // Ensure that a std::optional<T>::iterator can only be converted to a std::optional<T>::iterator.
 
diff --git a/libcxx/test/std/utilities/optional/optional.iterator/begin.pass.cpp b/libcxx/test/std/utilities/optional/optional.iterator/begin.pass.cpp
index 7c75fe8b45076..81234525923a1 100644
--- a/libcxx/test/std/utilities/optional/optional.iterator/begin.pass.cpp
+++ b/libcxx/test/std/utilities/optional/optional.iterator/begin.pass.cpp
@@ -8,8 +8,6 @@
 
 // REQUIRES: std-at-least-c++26
 
-// UNSUPPORTED: libcpp-has-no-experimental-optional-iterator
-
 // <optional>
 
 // constexpr iterator optional::begin() noexcept;
diff --git a/libcxx/test/std/utilities/optional/optional.iterator/borrowed_range.compile.pass.cpp b/libcxx/test/std/utilities/optional/optional.iterator/borrowed_range.compile.pass.cpp
index 65edbd54ff5b8..a79d1d51a5b11 100644
--- a/libcxx/test/std/utilities/optional/optional.iterator/borrowed_range.compile.pass.cpp
+++ b/libcxx/test/std/utilities/optional/optional.iterator/borrowed_range.compile.pass.cpp
@@ -8,8 +8,6 @@
 
 // REQUIRES: std-at-least-c++26
 
-// UNSUPPORTED: libcpp-has-no-experimental-optional-iterator
-
 // <optional>
 
 // template <class T> class optional<T&>::iterator;
diff --git a/libcxx/test/std/utilities/optional/optional.iterator/compare.pass.cpp b/libcxx/test/std/utilities/optional/optional.iterator/compare.pass.cpp
index 4c48c54df3257..b3f778328c0cc 100644
--- a/libcxx/test/std/utilities/optional/optional.iterator/compare.pass.cpp
+++ b/libcxx/test/std/utilities/optional/optional.iterator/compare.pass.cpp
@@ -7,7 +7,6 @@
 //===----------------------------------------------------------------------===//
 
 // REQUIRES: std-at-least-c++26
-// UNSUPPORTED: libcpp-has-no-experimental-optional-iterator
 
 // <optional>
 
diff --git a/libcxx/test/std/utilities/optional/optional.iterator/end.pass.cpp b/libcxx/test/std/utilities/optional/optional.iterator/end.pass.cpp
index 563f160092a38..c62c9fc7746d6 100644
--- a/libcxx/test/std/utilities/optional/optional.iterator/end.pass.cpp
+++ b/libcxx/test/std/utilities/optional/optional.iterator/end.pass.cpp
@@ -8,8 +8,6 @@
 
 // REQUIRES: std-at-least-c++26
 
-// UNSUPPORTED: libcpp-has-no-experimental-optional-iterator
-
 // <optional>
 
 // constexpr iterator optional::end() noexcept;
diff --git a/libcxx/test/std/utilities/optional/optional.iterator/iterator.pass.cpp b/libcxx/test/std/utilities/optional/optional.iterator/iterator.pass.cpp
index 05b8b3572ef53..996811d078b86 100644
--- a/libcxx/test/std/utilities/optional/optional.iterator/iterator.pass.cpp
+++ b/libcxx/test/std/utilities/optional/optional.iterator/iterator.pass.cpp
@@ -8,8 +8,6 @@
 
 // REQUIRES: std-at-least-c++26
 
-// UNSUPPORTED: libcpp-has-no-experimental-optional-iterator
-
 // <optional>
 
 // template <class T> class optional::iterator;
diff --git a/libcxx/utils/libcxx/test/params.py b/libcxx/utils/libcxx/test/params.py
index d0bb38ab84df4..b0e0c48873eb3 100644
--- a/libcxx/utils/libcxx/test/params.py
+++ b/libcxx/utils/libcxx/test/params.py
@@ -362,7 +362,6 @@ def getSuitableClangTidy(cfg):
         if experimental
         else [
             AddFeature("libcpp-has-no-incomplete-pstl"),
-            AddFeature("libcpp-has-no-experimental-optional-iterator"),
             AddFeature("libcpp-has-no-experimental-tzdb"),
             AddFeature("libcpp-has-no-experimental-syncstream"),
             AddFeature("libcpp-has-no-experimental-hardening-observe-semantic"),



More information about the libcxx-commits mailing list