[libcxx-commits] [libcxx] [libc++] Make optional::iterator experimental (PR #173470)
Nikolas Klauser via libcxx-commits
libcxx-commits at lists.llvm.org
Thu Jan 8 02:25:32 PST 2026
https://github.com/philnik777 updated https://github.com/llvm/llvm-project/pull/173470
>From 3ffc105b95a7d0a0a308944287f015c861586c59 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/docs/ReleaseNotes/22.rst | 3 ++-
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 | 4 +++-
.../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 +
14 files changed, 56 insertions(+), 23 deletions(-)
diff --git a/libcxx/docs/ReleaseNotes/22.rst b/libcxx/docs/ReleaseNotes/22.rst
index 3e2b3e6633bb1..e655e4156b02f 100644
--- a/libcxx/docs/ReleaseNotes/22.rst
+++ b/libcxx/docs/ReleaseNotes/22.rst
@@ -51,7 +51,8 @@ Implemented Papers
(`Github <https://llvm.org/PR105381>`__)
- P2835R7: Expose ``std::atomic_ref``'s object address (`Github <https://llvm.org/PR118377>`__)
- P2944R3: Comparisons for ``reference_wrapper`` (`Github <https://llvm.org/PR105424>`__)
-- P3168R2: Give ``std::optional`` Range Support (`Github <https://llvm.org/PR105430>`__)
+- P3168R2: Give ``std::optional`` Range Support
+ (guarded by ``-fexperimental-library``, `Github <https://llvm.org/PR105430>`__)
- P3567R2: ``flat_meow`` Fixes (`Github <https://llvm.org/PR162022>`__)
- P3836R2: Make ``optional<T&>`` trivially copyable (`Github <https://llvm.org/PR171275>`__)
- P1789R3: Library Support for Expansion Statements (`Github <https://llvm.org/PR167184>`__)
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 1d2422e64ba0f..d47f0cb6cd41c 100644
--- a/libcxx/include/version
+++ b/libcxx/include/version
@@ -598,7 +598,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..0ae368b4f87ce 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}}
@@ -92,8 +92,10 @@ 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 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 d54e229a87fcb..aacccc0451693 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
@@ -7489,11 +7489,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 370bc5d26b535..a847042bf47c0 100644
--- a/libcxx/utils/generate_feature_test_macro_components.py
+++ b/libcxx/utils/generate_feature_test_macro_components.py
@@ -1026,6 +1026,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