[libcxx-commits] [libcxx] [libc++] Don't double-wrap iterators when bounded iterators are used (PR #182264)
Nikolas Klauser via libcxx-commits
libcxx-commits at lists.llvm.org
Thu Feb 26 02:51:33 PST 2026
https://github.com/philnik777 updated https://github.com/llvm/llvm-project/pull/182264
>From 3aa28718af1726439c300cb8e22e5acdaa5abe79 Mon Sep 17 00:00:00 2001
From: Nikolas Klauser <nikolasklauser at berlin.de>
Date: Thu, 19 Feb 2026 14:23:40 +0100
Subject: [PATCH] [libc++] Dont' double-wrap the iterators in optional
---
libcxx/docs/ReleaseNotes/23.rst | 4 ++++
libcxx/include/__iterator/bounded_iter.h | 3 ---
libcxx/include/__vector/vector.h | 14 ++++--------
libcxx/include/optional | 22 +++++--------------
libcxx/include/string | 14 ++++--------
.../iterators/contiguous_iterators.verify.cpp | 2 --
6 files changed, 18 insertions(+), 41 deletions(-)
diff --git a/libcxx/docs/ReleaseNotes/23.rst b/libcxx/docs/ReleaseNotes/23.rst
index b8a8a088abec4..f01afb9c98269 100644
--- a/libcxx/docs/ReleaseNotes/23.rst
+++ b/libcxx/docs/ReleaseNotes/23.rst
@@ -70,5 +70,9 @@ ABI Affecting Changes
defining ``_LIBCPP_DEPRECATED_ABI_BITSET_CONST_SUBSCRIPT_RETURN_REF``. Please inform the libc++ team if you need this
flag, since it will be removed in LLVM 24 if there is no evidence that it's required.
+- ``vector::iterator`` and ``string::iterator`` no longer use ``__bounded_iter<__wrap_iter<Iter>>``, but instead
+ ``__bounded_iter<Iter>`` directly if ``_LIBCPP_ABI_BOUNDED_ITERATORS_IN_VECTOR`` and
+ ``_LIBCPP_ABI_BOUNDED_ITERATORS_IN_STRING`` are defined.
+
Build System Changes
--------------------
diff --git a/libcxx/include/__iterator/bounded_iter.h b/libcxx/include/__iterator/bounded_iter.h
index d2a09061126bd..84d4d8f4a98a8 100644
--- a/libcxx/include/__iterator/bounded_iter.h
+++ b/libcxx/include/__iterator/bounded_iter.h
@@ -53,9 +53,6 @@ _LIBCPP_BEGIN_NAMESPACE_STD
// optimizations deleting non-redundant bounds checks.
template <class _Iterator>
struct __bounded_iter {
- static_assert(__libcpp_is_contiguous_iterator<_Iterator>::value,
- "Only contiguous iterators can be adapted by __bounded_iter.");
-
using value_type = typename iterator_traits<_Iterator>::value_type;
using difference_type = typename iterator_traits<_Iterator>::difference_type;
using pointer = typename iterator_traits<_Iterator>::pointer;
diff --git a/libcxx/include/__vector/vector.h b/libcxx/include/__vector/vector.h
index d1c3f7ddcec1c..e95c828fd40ea 100644
--- a/libcxx/include/__vector/vector.h
+++ b/libcxx/include/__vector/vector.h
@@ -104,8 +104,8 @@ class vector {
// Users might provide custom allocators, and prior to C++20 we have no existing way to detect whether the allocator's
// pointer type is contiguous (though it has to be by the Standard). Using the wrapper type ensures the iterator is
// considered contiguous.
- using iterator = __bounded_iter<__wrap_iter<pointer> >;
- using const_iterator = __bounded_iter<__wrap_iter<const_pointer> >;
+ using iterator = __bounded_iter<pointer>;
+ using const_iterator = __bounded_iter<const_pointer>;
#else
using iterator = __wrap_iter<pointer>;
using const_iterator = __wrap_iter<const_pointer>;
@@ -676,10 +676,7 @@ class vector {
// current implementation, there is no connection between a bounded iterator and its associated container, so we
// don't have a way to update existing valid iterators when the container is resized and thus have to go with
// a laxer approach.
- return std::__make_bounded_iter(
- std::__wrap_iter<pointer>(__p),
- std::__wrap_iter<pointer>(this->__begin_),
- std::__wrap_iter<pointer>(this->__cap_));
+ return std::__make_bounded_iter(__p, this->__begin_, this->__cap_);
#else
return iterator(__p);
#endif // _LIBCPP_ABI_BOUNDED_ITERATORS_IN_VECTOR
@@ -688,10 +685,7 @@ class vector {
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_iterator __make_iter(const_pointer __p) const _NOEXCEPT {
#ifdef _LIBCPP_ABI_BOUNDED_ITERATORS_IN_VECTOR
// Bound the iterator according to the capacity, rather than the size.
- return std::__make_bounded_iter(
- std::__wrap_iter<const_pointer>(__p),
- std::__wrap_iter<const_pointer>(this->__begin_),
- std::__wrap_iter<const_pointer>(this->__cap_));
+ return std::__make_bounded_iter(__p, const_pointer(this->__begin_), const_pointer(this->__cap_));
#else
return const_iterator(__p);
#endif // _LIBCPP_ABI_BOUNDED_ITERATORS_IN_VECTOR
diff --git a/libcxx/include/optional b/libcxx/include/optional
index 9a8fb15c02dae..a928769d65c90 100644
--- a/libcxx/include/optional
+++ b/libcxx/include/optional
@@ -272,7 +272,6 @@ namespace std {
# include <__fwd/functional.h>
# include <__iterator/bounded_iter.h>
# include <__iterator/capacity_aware_iterator.h>
-# include <__iterator/wrap_iter.h>
# include <__memory/addressof.h>
# include <__memory/construct_at.h>
# include <__ranges/enable_borrowed_range.h>
@@ -719,8 +718,8 @@ private:
public:
# ifdef _LIBCPP_ABI_BOUNDED_ITERATORS_IN_OPTIONAL
- using iterator = __bounded_iter<__wrap_iter<__pointer>>;
- using const_iterator = __bounded_iter<__wrap_iter<__const_pointer>>;
+ 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>;
@@ -732,10 +731,7 @@ public:
auto* __ptr = std::addressof(__derived_self.__get());
# 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));
+ return std::__make_bounded_iter(__ptr, __ptr, __ptr + (__derived_self.has_value() ? 1 : 0));
# else
return std::__make_capacity_aware_iterator<__pointer, optional<_Tp>, 1>(__ptr);
# endif
@@ -746,10 +742,7 @@ public:
auto* __ptr = std::addressof(__derived_self.__get());
# 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));
+ return std::__make_bounded_iter(__ptr, __ptr, __ptr + (__derived_self.has_value() ? 1 : 0));
# else
return std::__make_capacity_aware_iterator<__const_pointer, optional<_Tp>, 1>(__ptr);
# endif
@@ -770,7 +763,7 @@ private:
public:
# ifdef _LIBCPP_ABI_BOUNDED_ITERATORS_IN_OPTIONAL
- using iterator = __bounded_iter<__wrap_iter<__pointer>>;
+ using iterator = __bounded_iter<__pointer>;
# else
using iterator = __capacity_aware_iterator<__pointer, optional<_Tp&>, 1>;
# endif
@@ -782,10 +775,7 @@ public:
auto* __ptr = __derived_self.has_value() ? std::addressof(__derived_self.__get()) : nullptr;
# 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));
+ return std::__make_bounded_iter(__ptr, __ptr, __ptr + (__derived_self.has_value() ? 1 : 0));
# else
return std::__make_capacity_aware_iterator<__pointer, optional<_Tp&>, 1>(__pointer(__ptr));
# endif
diff --git a/libcxx/include/string b/libcxx/include/string
index c4bf970e55004..3caf1ce9a6eca 100644
--- a/libcxx/include/string
+++ b/libcxx/include/string
@@ -809,8 +809,8 @@ public:
// Users might provide custom allocators, and prior to C++20 we have no existing way to detect whether the allocator's
// pointer type is contiguous (though it has to be by the Standard). Using the wrapper type ensures the iterator is
// considered contiguous.
- using iterator = __bounded_iter<__wrap_iter<pointer> >;
- using const_iterator = __bounded_iter<__wrap_iter<const_pointer> >;
+ using iterator = __bounded_iter<pointer>;
+ using const_iterator = __bounded_iter<const_pointer>;
# else
using iterator = __wrap_iter<pointer>;
using const_iterator = __wrap_iter<const_pointer>;
@@ -955,10 +955,7 @@ private:
// regardless of whether reallocation occurs. This allows us to check for out-of-bounds accesses using logical size,
// a stricter check, since correct code can never rely on being able to access newly-added elements via an existing
// iterator.
- return std::__make_bounded_iter(
- std::__wrap_iter<pointer>(__p),
- std::__wrap_iter<pointer>(__get_pointer()),
- std::__wrap_iter<pointer>(__get_pointer() + size()));
+ return std::__make_bounded_iter(__p, __get_pointer(), __get_pointer() + size());
# else
return iterator(__p);
# endif // _LIBCPP_ABI_BOUNDED_ITERATORS_IN_STRING
@@ -967,10 +964,7 @@ private:
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 const_iterator __make_const_iterator(const_pointer __p) const {
# ifdef _LIBCPP_ABI_BOUNDED_ITERATORS_IN_STRING
// Bound the iterator according to the size (and not the capacity, unlike vector).
- return std::__make_bounded_iter(
- std::__wrap_iter<const_pointer>(__p),
- std::__wrap_iter<const_pointer>(__get_pointer()),
- std::__wrap_iter<const_pointer>(__get_pointer() + size()));
+ return std::__make_bounded_iter(__p, __get_pointer(), __get_pointer() + size());
# else
return const_iterator(__p);
# endif // _LIBCPP_ABI_BOUNDED_ITERATORS_IN_STRING
diff --git a/libcxx/test/libcxx/iterators/contiguous_iterators.verify.cpp b/libcxx/test/libcxx/iterators/contiguous_iterators.verify.cpp
index 215e77b6605e2..3648f7db1257f 100644
--- a/libcxx/test/libcxx/iterators/contiguous_iterators.verify.cpp
+++ b/libcxx/test/libcxx/iterators/contiguous_iterators.verify.cpp
@@ -19,7 +19,5 @@
#include <vector>
#include <array>
-// expected-error-re@*:* {{static assertion failed due to requirement {{.*}}Only contiguous iterators can be adapted by __bounded_iter.}}
-std::__bounded_iter<std::deque<int>::iterator> bounded_iter;
// expected-error-re@*:* {{static assertion failed due to requirement {{.*}}Only contiguous iterators can be adapted by __static_bounded_iter.}}
std::__static_bounded_iter<std::deque<int>::iterator, 42> statically_bounded_iter;
More information about the libcxx-commits
mailing list