[libcxx-commits] [libcxx] e830ee8 - [libc++] Don't double-wrap iterators when bounded iterators are used (#182264)

via libcxx-commits libcxx-commits at lists.llvm.org
Sat Mar 7 00:12:30 PST 2026


Author: Nikolas Klauser
Date: 2026-03-07T09:12:25+01:00
New Revision: e830ee80063531fdfb1273cc112634b62926c66f

URL: https://github.com/llvm/llvm-project/commit/e830ee80063531fdfb1273cc112634b62926c66f
DIFF: https://github.com/llvm/llvm-project/commit/e830ee80063531fdfb1273cc112634b62926c66f.diff

LOG: [libc++] Don't double-wrap iterators when bounded iterators are used (#182264)

There is no reason to double-wrap iterators, since we can already
achieve anything we want within `__bounded_iter`itself.

This is technically ABI breaking, but people using bounded iterators
shouldn't require ABI stability currently.

Fixes #178521

Added: 
    

Modified: 
    libcxx/docs/ReleaseNotes/23.rst
    libcxx/include/__iterator/bounded_iter.h
    libcxx/include/__vector/vector.h
    libcxx/include/optional
    libcxx/include/string
    libcxx/test/libcxx/iterators/contiguous_iterators.verify.cpp

Removed: 
    


################################################################################
diff  --git a/libcxx/docs/ReleaseNotes/23.rst b/libcxx/docs/ReleaseNotes/23.rst
index 7563ca60e75a4..bcf527869ac94 100644
--- a/libcxx/docs/ReleaseNotes/23.rst
+++ b/libcxx/docs/ReleaseNotes/23.rst
@@ -75,5 +75,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 
diff erence_type   = typename iterator_traits<_Iterator>::
diff erence_type;
   using pointer           = typename iterator_traits<_Iterator>::pointer;

diff  --git a/libcxx/include/__vector/vector.h b/libcxx/include/__vector/vector.h
index 181230df819ea..229287b43e702 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 fb04eb67d0297..c59684c32a3fe 100644
--- a/libcxx/include/string
+++ b/libcxx/include/string
@@ -785,8 +785,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>;
@@ -931,10 +931,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
@@ -943,10 +940,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..03b3bb08d1388 100644
--- a/libcxx/test/libcxx/iterators/contiguous_iterators.verify.cpp
+++ b/libcxx/test/libcxx/iterators/contiguous_iterators.verify.cpp
@@ -9,17 +9,17 @@
 
 // <iterator>
 
-// __bounded_iter<_Iter>
+// __static_bounded_iter<_Iter>
 
-// Verify that __bounded_iter does not accept non-contiguous iterators as determined by __libcpp_is_contiguous_iterator.
+// Verify that __static_bounded_iter does not accept non-contiguous iterators as determined by
+// __libcpp_is_contiguous_iterator.
 // static_assert should be used, see https://llvm.org/PR115002.
-// __wrap_iter cannot be so handled because it may directly wrap user-defined fancy pointers in libc++'s vector.
+// __wrap_iter and __bounded_iter cannot be so handled because it may directly wrap user-defined fancy pointers in
+// libc++'s vector.
 
 #include <deque>
 #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