[libcxx-commits] [libcxx] [libc++] Only allow operations between const and non-const __wrap_iter specializations (PR #215788)

Nikolas Klauser via libcxx-commits libcxx-commits at lists.llvm.org
Wed Aug 12 05:24:02 PDT 2026


https://github.com/philnik777 updated https://github.com/llvm/llvm-project/pull/215788

>From 4d106e037b51950fee7433493e07f3bec470c6de Mon Sep 17 00:00:00 2001
From: Nikolas Klauser <nikolasklauser at berlin.de>
Date: Wed, 12 Aug 2026 14:21:09 +0200
Subject: [PATCH] [libc++] Only allow operations between const and non-const
 __wrap_iter specializations

---
 libcxx/include/__iterator/wrap_iter.h | 67 +++++++++++++--------------
 libcxx/test/support/min_allocator.h   |  2 +-
 2 files changed, 32 insertions(+), 37 deletions(-)

diff --git a/libcxx/include/__iterator/wrap_iter.h b/libcxx/include/__iterator/wrap_iter.h
index 89ddb9658c697..c3ac3f6fd027d 100644
--- a/libcxx/include/__iterator/wrap_iter.h
+++ b/libcxx/include/__iterator/wrap_iter.h
@@ -12,17 +12,14 @@
 
 #include <__compare/ordering.h>
 #include <__compare/three_way_comparable.h>
+#include <__concepts/same_as.h>
 #include <__config>
 #include <__cstddef/size_t.h>
 #include <__iterator/iterator_traits.h>
 #include <__memory/pointer_traits.h>
-#include <__type_traits/conjunction.h>
-#include <__type_traits/disjunction.h>
 #include <__type_traits/enable_if.h>
 #include <__type_traits/integral_constant.h>
-#include <__type_traits/is_convertible.h>
 #include <__type_traits/is_same.h>
-#include <__type_traits/make_const_lvalue_ref.h>
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #  pragma GCC system_header
@@ -45,16 +42,15 @@ class _LIBCPP_WARN_UNUSED __wrap_iter {
 private:
   _Iter __i_;
 
+  using __mutable_iter _LIBCPP_NODEBUG = __wrap_iter<__rebind_pointer_t<_Iter, value_type> >;
+
 public:
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 __wrap_iter() _NOEXCEPT : __i_() {}
-  template <class _OtherIter,
-            __enable_if_t<
-                _And<is_convertible<const _OtherIter&, _Iter>,
-                     _Or<is_same<reference, __iterator_reference<_OtherIter> >,
-                         is_same<reference, __make_const_lvalue_ref<__iterator_reference<_OtherIter> > > > >::value,
-                int> = 0>
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 __wrap_iter(const __wrap_iter<_OtherIter>& __u) _NOEXCEPT
+
+  template <class _MutableIter = __mutable_iter, __enable_if_t<!is_same<_MutableIter, __wrap_iter>::value, int> = 0>
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 __wrap_iter(const __mutable_iter& __u) _NOEXCEPT
       : __i_(__u.__i_) {}
+
   [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 reference operator*() const _NOEXCEPT {
     return *__i_;
   }
@@ -125,9 +121,9 @@ class _LIBCPP_WARN_UNUSED __wrap_iter {
     return __x.__i_ == __y.__i_;
   }
 
-  template <class _Iter2>
+  template <class _MutableIter = __mutable_iter, __enable_if_t<!is_same<_MutableIter, __wrap_iter>::value, int> = 0>
   _LIBCPP_HIDE_FROM_ABI friend _LIBCPP_CONSTEXPR bool
-  operator==(const __wrap_iter& __x, const __wrap_iter<_Iter2>& __y) _NOEXCEPT {
+  operator==(const __wrap_iter& __x, const __mutable_iter& __y) _NOEXCEPT {
     return __x.__i_ == __y.__i_;
   }
 
@@ -136,9 +132,9 @@ class _LIBCPP_WARN_UNUSED __wrap_iter {
     return __x.__i_ < __y.__i_;
   }
 
-  template <class _Iter2>
+  template <class _MutableIter = __mutable_iter, __enable_if_t<!is_same<_MutableIter, __wrap_iter>::value, int> = 0>
   _LIBCPP_HIDE_FROM_ABI friend _LIBCPP_CONSTEXPR bool
-  operator<(const __wrap_iter& __x, const __wrap_iter<_Iter2>& __y) _NOEXCEPT {
+  operator<(const __wrap_iter& __x, const __mutable_iter& __y) _NOEXCEPT {
     return __x.__i_ < __y.__i_;
   }
 
@@ -147,9 +143,9 @@ class _LIBCPP_WARN_UNUSED __wrap_iter {
     return !(__x == __y);
   }
 
-  template <class _Iter2>
+  template <class _MutableIter = __mutable_iter, __enable_if_t<!is_same<_MutableIter, __wrap_iter>::value, int> = 0>
   _LIBCPP_HIDE_FROM_ABI friend _LIBCPP_CONSTEXPR bool
-  operator!=(const __wrap_iter& __x, const __wrap_iter<_Iter2>& __y) _NOEXCEPT {
+  operator!=(const __wrap_iter& __x, const __mutable_iter& __y) _NOEXCEPT {
     return !(__x == __y);
   }
 
@@ -158,9 +154,9 @@ class _LIBCPP_WARN_UNUSED __wrap_iter {
     return __y < __x;
   }
 
-  template <class _Iter2>
+  template <class _MutableIter = __mutable_iter, __enable_if_t<!is_same<_MutableIter, __wrap_iter>::value, int> = 0>
   _LIBCPP_HIDE_FROM_ABI friend _LIBCPP_CONSTEXPR bool
-  operator>(const __wrap_iter& __x, const __wrap_iter<_Iter2>& __y) _NOEXCEPT {
+  operator>(const __wrap_iter& __x, const __mutable_iter& __y) _NOEXCEPT {
     return __y < __x;
   }
 
@@ -169,9 +165,9 @@ class _LIBCPP_WARN_UNUSED __wrap_iter {
     return !(__x < __y);
   }
 
-  template <class _Iter2>
+  template <class _MutableIter = __mutable_iter, __enable_if_t<!is_same<_MutableIter, __wrap_iter>::value, int> = 0>
   _LIBCPP_HIDE_FROM_ABI friend _LIBCPP_CONSTEXPR bool
-  operator>=(const __wrap_iter& __x, const __wrap_iter<_Iter2>& __y) _NOEXCEPT {
+  operator>=(const __wrap_iter& __x, const __mutable_iter& __y) _NOEXCEPT {
     return !(__x < __y);
   }
 
@@ -180,22 +176,23 @@ class _LIBCPP_WARN_UNUSED __wrap_iter {
     return !(__y < __x);
   }
 
-  template <class _Iter2>
+  template <class _MutableIter = __mutable_iter, __enable_if_t<!is_same<_MutableIter, __wrap_iter>::value, int> = 0>
   _LIBCPP_HIDE_FROM_ABI friend _LIBCPP_CONSTEXPR bool
-  operator<=(const __wrap_iter& __x, const __wrap_iter<_Iter2>& __y) _NOEXCEPT {
+  operator<=(const __wrap_iter& __x, const __mutable_iter& __y) _NOEXCEPT {
     return !(__y < __x);
   }
 
 #else
   _LIBCPP_HIDE_FROM_ABI friend bool operator==(const __wrap_iter&, const __wrap_iter&) = default;
 
-  template <class _Iter2>
-  _LIBCPP_HIDE_FROM_ABI friend constexpr bool
-  operator==(const __wrap_iter& __x, const __wrap_iter<_Iter2>& __y) noexcept {
+  _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const __wrap_iter& __x, const __mutable_iter& __y) noexcept
+    requires(!same_as<__wrap_iter, __mutable_iter>)
+  {
     return __x.__i_ == __y.__i_;
   }
 
   template <class _Iter2>
+    requires same_as<_Iter, _Iter2> || same_as<__wrap_iter<_Iter2>, __mutable_iter>
   _LIBCPP_HIDE_FROM_ABI friend constexpr strong_ordering
   operator<=>(const __wrap_iter& __x, const __wrap_iter<_Iter2>& __y) noexcept {
     if constexpr (three_way_comparable_with<_Iter, _Iter2, strong_ordering>) {
@@ -212,21 +209,19 @@ class _LIBCPP_WARN_UNUSED __wrap_iter {
   }
 #endif // _LIBCPP_STD_VER >= 20
 
-#ifndef _LIBCPP_CXX03_LANG
-  template <class _Iter2>
-  [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI friend _LIBCPP_CONSTEXPR_SINCE_CXX14 auto
-  operator-(const __wrap_iter& __x, const __wrap_iter<_Iter2>& __y) _NOEXCEPT->decltype(__x.__i_ - __y.__i_)
-#else
-  template <class _Iter2>
   [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI friend _LIBCPP_CONSTEXPR_SINCE_CXX14
-  typename __wrap_iter::difference_type operator-(const __wrap_iter& __x, const __wrap_iter<_Iter2>& __y) _NOEXCEPT
-#endif // C++03
-  {
+  difference_type operator-(const __wrap_iter& __x, const __wrap_iter& __y) _NOEXCEPT {
+    return __x.__i_ - __y.__i_;
+  }
+
+  template <class _MutableIter = __mutable_iter, __enable_if_t<!is_same<_MutableIter, __wrap_iter>::value, int> = 0>
+  [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI friend _LIBCPP_CONSTEXPR_SINCE_CXX14 difference_type
+  operator-(const __wrap_iter& __x, const __mutable_iter& __y) _NOEXCEPT {
     return __x.__i_ - __y.__i_;
   }
 
   [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI friend _LIBCPP_CONSTEXPR_SINCE_CXX14 __wrap_iter
-  operator+(typename __wrap_iter::difference_type __n, __wrap_iter __x) _NOEXCEPT {
+  operator+(difference_type __n, __wrap_iter __x) _NOEXCEPT {
     __x += __n;
     return __x;
   }
diff --git a/libcxx/test/support/min_allocator.h b/libcxx/test/support/min_allocator.h
index 193fc5b4d81c4..51f3c06ac35f3 100644
--- a/libcxx/test/support/min_allocator.h
+++ b/libcxx/test/support/min_allocator.h
@@ -337,7 +337,7 @@ class min_pointer<const T, ID> {
   typedef std::ptrdiff_t difference_type;
   typedef const T& reference;
   typedef const T* pointer;
-  typedef const T value_type;
+  typedef T value_type;
   typedef std::random_access_iterator_tag iterator_category;
 
   TEST_CONSTEXPR_CXX14 reference operator*() const { return *ptr_; }



More information about the libcxx-commits mailing list