[libcxx-commits] [libcxx] [libc++] Make optional::iterator experimental (PR #173470)

Louis Dionne via libcxx-commits libcxx-commits at lists.llvm.org
Wed Jan 7 07:19:52 PST 2026


https://github.com/ldionne updated https://github.com/llvm/llvm-project/pull/173470

>From f27475adf440e295a00f2596e68091fa2765a5cd Mon Sep 17 00:00:00 2001
From: Nikolas Klauser <nikolasklauser at berlin.de>
Date: Wed, 24 Dec 2025 10:29:28 +0100
Subject: [PATCH] [libc++] Make optional::iterator experimental

---
 libcxx/include/__configuration/experimental.h |  1 +
 libcxx/include/optional                       | 20 +++++++++----------
 libcxx/include/version                        |  4 +++-
 .../fexperimental-library.compile.pass.cpp    |  4 ++++
 .../utilities/optional/nodiscard.verify.cpp   |  2 +-
 .../optional.version.compile.pass.cpp         | 16 ++++++++++-----
 .../version.version.compile.pass.cpp          | 16 ++++++++++-----
 .../optional/optional.iterator/begin.pass.cpp |  2 ++
 .../borrowed_range.compile.pass.cpp           |  2 ++
 .../optional/optional.iterator/end.pass.cpp   |  2 ++
 .../optional.iterator/iterator.pass.cpp       |  2 ++
 .../generate_feature_test_macro_components.py |  2 ++
 libcxx/utils/libcxx/test/params.py            |  1 +
 13 files changed, 52 insertions(+), 22 deletions(-)

diff --git a/libcxx/include/__configuration/experimental.h b/libcxx/include/__configuration/experimental.h
index d14df3e5175f3..bb38d8297c63d 100644
--- a/libcxx/include/__configuration/experimental.h
+++ b/libcxx/include/__configuration/experimental.h
@@ -33,5 +33,6 @@
 #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 568c86556d156..88debedf47e90 100644
--- a/libcxx/include/optional
+++ b/libcxx/include/optional
@@ -703,7 +703,7 @@ inline constexpr bool __is_constructible_for_optional_initializer_list_v<_Tp&, _
 template <class _Tp, class = void>
 struct __optional_iterator {};
 
-#    if _LIBCPP_STD_VER >= 26
+#    if _LIBCPP_STD_VER >= 26 && _LIBCPP_HAS_EXPERIMENTAL_OPTIONAL_ITERATOR
 
 template <class _Tp>
 struct __optional_iterator<_Tp, enable_if_t<!is_lvalue_reference_v<_Tp>>> {
@@ -715,38 +715,38 @@ public:
 #      ifdef _LIBCPP_ABI_BOUNDED_ITERATORS_IN_OPTIONAL
   using iterator       = __bounded_iter<__wrap_iter<__pointer>>;
   using const_iterator = __bounded_iter<__wrap_iter<__const_pointer>>;
-#      else
+#        else
   using iterator       = __wrap_iter<__pointer>;
   using const_iterator = __wrap_iter<__const_pointer>;
-#      endif
+#        endif
 
   // [optional.iterators], iterator support
   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr iterator begin() noexcept {
     auto& __derived_self = static_cast<optional<_Tp>&>(*this);
     auto* __ptr          = std::addressof(__derived_self.__get());
 
-#      ifdef _LIBCPP_ABI_BOUNDED_ITERATORS_IN_OPTIONAL
+#        ifdef _LIBCPP_ABI_BOUNDED_ITERATORS_IN_OPTIONAL
     return std::__make_bounded_iter(
         __wrap_iter<__pointer>(__ptr),
         __wrap_iter<__pointer>(__ptr),
         __wrap_iter<__pointer>(__ptr) + (__derived_self.has_value() ? 1 : 0));
-#      else
+#        else
     return iterator(__ptr);
-#      endif
+#        endif
   }
 
   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr const_iterator begin() const noexcept {
     auto& __derived_self = static_cast<const optional<_Tp>&>(*this);
     auto* __ptr          = std::addressof(__derived_self.__get());
 
-#      ifdef _LIBCPP_ABI_BOUNDED_ITERATORS_IN_OPTIONAL
+#        ifdef _LIBCPP_ABI_BOUNDED_ITERATORS_IN_OPTIONAL
     return std::__make_bounded_iter(
         __wrap_iter<__const_pointer>(__ptr),
         __wrap_iter<__const_pointer>(__ptr),
         __wrap_iter<__const_pointer>(__ptr) + (__derived_self.has_value() ? 1 : 0));
-#      else
+#        else
     return const_iterator(__ptr);
-#      endif
+#        endif
   }
 
   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr iterator end() noexcept {
@@ -790,7 +790,7 @@ public:
   }
 };
 
-#    endif // _LIBCPP_STD_VER >= 26
+#    endif // _LIBCPP_STD_VER >= 26 && _LIBCPP_HAS_EXPERIMENTAL_OPTIONAL_ITERATOR
 
 template <class _Tp>
 class _LIBCPP_DECLSPEC_EMPTY_BASES optional
diff --git a/libcxx/include/version b/libcxx/include/version
index ab781466f5ed5..2d493c45e2b87 100644
--- a/libcxx/include/version
+++ b/libcxx/include/version
@@ -600,7 +600,9 @@ __cpp_lib_void_t                                        201411L <type_traits>
 # define __cpp_lib_not_fn                               202306L
 # undef  __cpp_lib_optional
 # define __cpp_lib_optional                             202506L
-# define __cpp_lib_optional_range_support               202406L
+# if _LIBCPP_HAS_EXPERIMENTAL_OPTIONAL_ITERATOR
+#   define __cpp_lib_optional_range_support             202406L
+# endif
 # undef  __cpp_lib_out_ptr
 # define __cpp_lib_out_ptr                              202311L
 // # define __cpp_lib_philox_engine                        202406L
diff --git a/libcxx/test/libcxx/experimental/fexperimental-library.compile.pass.cpp b/libcxx/test/libcxx/experimental/fexperimental-library.compile.pass.cpp
index 479b46a39e963..82fd1ad4d9a16 100644
--- a/libcxx/test/libcxx/experimental/fexperimental-library.compile.pass.cpp
+++ b/libcxx/test/libcxx/experimental/fexperimental-library.compile.pass.cpp
@@ -16,6 +16,10 @@
 
 #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 c49546cfdf4ad..1dd2aec233d73 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
+#if TEST_STD_VER >= 26 && _LIBCPP_HAS_EXPERIMENTAL_OPTIONAL_ITERATOR
   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}}
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 c4e652979a4e6..9850c20afec87 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,11 +146,17 @@
 #    error "__cpp_lib_optional should have the value 202506L in c++26"
 #  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"
+#  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
 #  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 b3b424a1d77ce..1d22211c0f5ce 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
@@ -7513,11 +7513,17 @@
 #    error "__cpp_lib_optional should have the value 202506L in c++26"
 #  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"
+#  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
 #  endif
 
 #  ifndef __cpp_lib_out_ptr
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 81234525923a1..7c75fe8b45076 100644
--- a/libcxx/test/std/utilities/optional/optional.iterator/begin.pass.cpp
+++ b/libcxx/test/std/utilities/optional/optional.iterator/begin.pass.cpp
@@ -8,6 +8,8 @@
 
 // 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 a79d1d51a5b11..65edbd54ff5b8 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,6 +8,8 @@
 
 // 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/end.pass.cpp b/libcxx/test/std/utilities/optional/optional.iterator/end.pass.cpp
index c62c9fc7746d6..563f160092a38 100644
--- a/libcxx/test/std/utilities/optional/optional.iterator/end.pass.cpp
+++ b/libcxx/test/std/utilities/optional/optional.iterator/end.pass.cpp
@@ -8,6 +8,8 @@
 
 // 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 1be86305b449c..1581c640136c6 100644
--- a/libcxx/test/std/utilities/optional/optional.iterator/iterator.pass.cpp
+++ b/libcxx/test/std/utilities/optional/optional.iterator/iterator.pass.cpp
@@ -8,6 +8,8 @@
 
 // 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/generate_feature_test_macro_components.py b/libcxx/utils/generate_feature_test_macro_components.py
index f61d6f991cb15..b10659ec1a0e5 100644
--- a/libcxx/utils/generate_feature_test_macro_components.py
+++ b/libcxx/utils/generate_feature_test_macro_components.py
@@ -1028,6 +1028,8 @@ 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",
diff --git a/libcxx/utils/libcxx/test/params.py b/libcxx/utils/libcxx/test/params.py
index 299aa28777fd5..07158dcf8fbab 100644
--- a/libcxx/utils/libcxx/test/params.py
+++ b/libcxx/utils/libcxx/test/params.py
@@ -362,6 +362,7 @@ 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