[libcxx-commits] [libcxx] [libc++][WIP] ADL-proof `std::__wrap_iter` (PR #107766)
Mital Ashok via libcxx-commits
libcxx-commits at lists.llvm.org
Sun Sep 8 09:07:22 PDT 2024
https://github.com/MitalAshok updated https://github.com/llvm/llvm-project/pull/107766
>From ffff9dfb0ef8547207b70e5161ef4727bff66cee Mon Sep 17 00:00:00 2001
From: Mital Ashok <mital at mitalashok.co.uk>
Date: Sun, 8 Sep 2024 16:51:58 +0100
Subject: [PATCH] wip
---
libcxx/include/__configuration/abi.h | 8 +
libcxx/include/__format/buffer.h | 2 +-
libcxx/include/__iterator/iterator_traits.h | 10 +
libcxx/include/__iterator/wrap_iter.h | 223 +++++++++++-------
libcxx/include/__memory/pointer_traits.h | 38 ++-
libcxx/include/array | 8 +-
libcxx/include/regex | 21 ++
libcxx/include/span | 4 +-
libcxx/include/string | 32 ++-
libcxx/include/string_view | 2 +-
libcxx/include/vector | 20 +-
.../iterators/contiguous_iterators.pass.cpp | 39 ++-
.../libcxx/iterators/unwrap_iter.pass.cpp | 8 +-
.../iterators/wrap_iter_adl.compile.pass.cpp | 58 +++++
...range_concept_conformance.compile.pass.cpp | 48 ++--
...rator_concept_conformance.compile.pass.cpp | 131 +++++-----
libcxx/test/support/nasty_string.h | 7 +
17 files changed, 454 insertions(+), 205 deletions(-)
create mode 100644 libcxx/test/libcxx/iterators/wrap_iter_adl.compile.pass.cpp
diff --git a/libcxx/include/__configuration/abi.h b/libcxx/include/__configuration/abi.h
index 8efbb42d1d8470..a368586ceb8adf 100644
--- a/libcxx/include/__configuration/abi.h
+++ b/libcxx/include/__configuration/abi.h
@@ -98,6 +98,14 @@
// and WCHAR_MAX. This ABI setting determines whether we should instead track whether the fill
// value has been initialized using a separate boolean, which changes the ABI.
# define _LIBCPP_ABI_IOS_ALLOW_ARBITRARY_FILL_VALUE
+// Change std::__wrap_iter<T> to not associate the namespaces associated with
+// T when unqualified lookup (e.g., with operators) is done. Also make it so
+// only std::__wrap_iter<pointer> and std::__wrap_iter<const_pointer> can
+// be used together (for comparison, conversion, etc.) instead of with any
+// wrapped iterator. So comprison between std::__wrap_iter<fancy_pointer<T>>
+// and std::__wrap_iter<T*> will no longer compile even if fancy_pointer<T>
+// is comparable with T*.
+# define _LIBCPP_ABI_WRAP_ITER_ADL_PROOF
#elif _LIBCPP_ABI_VERSION == 1
# if !(defined(_LIBCPP_OBJECT_FORMAT_COFF) || defined(_LIBCPP_OBJECT_FORMAT_XCOFF))
// Enable compiling copies of now inline methods into the dylib to support
diff --git a/libcxx/include/__format/buffer.h b/libcxx/include/__format/buffer.h
index ce9ac0c81e315a..048af2a00f8ae3 100644
--- a/libcxx/include/__format/buffer.h
+++ b/libcxx/include/__format/buffer.h
@@ -258,7 +258,7 @@ concept __enable_direct_output =
(same_as<_OutIt, _CharT*>
// TODO(hardening): the following check might not apply to hardened iterators and might need to be wrapped in an
// `#ifdef`.
- || same_as<_OutIt, __wrap_iter<_CharT*>>);
+ || same_as<_OutIt, __wrap_mut_iter<_CharT*, const _CharT*>>);
/// Write policy for directly writing to the underlying output.
template <class _OutIt, __fmt_char_type _CharT>
diff --git a/libcxx/include/__iterator/iterator_traits.h b/libcxx/include/__iterator/iterator_traits.h
index 4d9ad480cc4a29..a06f9660c8d739 100644
--- a/libcxx/include/__iterator/iterator_traits.h
+++ b/libcxx/include/__iterator/iterator_traits.h
@@ -453,6 +453,14 @@ template <class _Tp>
struct __libcpp_is_contiguous_iterator
: _Or< __has_iterator_category_convertible_to<_Tp, contiguous_iterator_tag>,
__has_iterator_concept_convertible_to<_Tp, contiguous_iterator_tag> > {};
+#elif defined(_LIBCPP_ABI_WRAP_ITER_ADL_PROOF)
+template <class _It, class = void>
+struct __is_contiguous_wrap_iter : false_type {};
+template <class _It>
+struct __is_contiguous_wrap_iter<_It, __void_t<typename _Tp::__is_wrap_iter> > : true_type {};
+
+template <class _Tp>
+struct __libcpp_is_contiguous_iterator : __is_contiguous_wrap_iter<_Tp> {};
#else
template <class _Tp>
struct __libcpp_is_contiguous_iterator : false_type {};
@@ -462,8 +470,10 @@ struct __libcpp_is_contiguous_iterator : false_type {};
template <class _Up>
struct __libcpp_is_contiguous_iterator<_Up*> : true_type {};
+#ifndef _LIBCPP_ABI_WRAP_ITER_ADL_PROOF
template <class _Iter>
class __wrap_iter;
+#endif
template <class _Tp>
using __has_exactly_input_iterator_category =
diff --git a/libcxx/include/__iterator/wrap_iter.h b/libcxx/include/__iterator/wrap_iter.h
index 549d8ff2dbd7db..f61d7a6ede6665 100644
--- a/libcxx/include/__iterator/wrap_iter.h
+++ b/libcxx/include/__iterator/wrap_iter.h
@@ -16,9 +16,11 @@
#include <__iterator/iterator_traits.h>
#include <__memory/addressof.h>
#include <__memory/pointer_traits.h>
+#include <__type_traits/conditional.h>
#include <__type_traits/enable_if.h>
#include <__type_traits/integral_constant.h>
#include <__type_traits/is_convertible.h>
+#include <__type_traits/void_t.h>
#include <cstddef>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
@@ -27,15 +29,25 @@
_LIBCPP_BEGIN_NAMESPACE_STD
+#ifdef _LIBCPP_ABI_WRAP_ITER_ADL_PROOF
+template <class _MutableIter, class _ConstIter>
+struct __wrap_iter_impl {
+ template <bool _IsConst>
+#else
template <class _Iter>
-class __wrap_iter {
-public:
- typedef _Iter iterator_type;
- typedef typename iterator_traits<iterator_type>::value_type value_type;
- typedef typename iterator_traits<iterator_type>::difference_type difference_type;
- typedef typename iterator_traits<iterator_type>::pointer pointer;
- typedef typename iterator_traits<iterator_type>::reference reference;
- typedef typename iterator_traits<iterator_type>::iterator_category iterator_category;
+#endif
+ class __wrap_iter {
+
+ public:
+#ifdef _LIBCPP_ABI_WRAP_ITER_ADL_PROOF
+ using _Iter = __conditional_t<_IsConst, _ConstIter, _MutableIter>;
+#endif
+ typedef _Iter iterator_type;
+ typedef typename iterator_traits<iterator_type>::value_type value_type;
+ typedef typename iterator_traits<iterator_type>::difference_type difference_type;
+ typedef typename iterator_traits<iterator_type>::pointer pointer;
+ typedef typename iterator_traits<iterator_type>::reference reference;
+ typedef typename iterator_traits<iterator_type>::iterator_category iterator_category;
#if _LIBCPP_STD_VER >= 20
typedef contiguous_iterator_tag iterator_concept;
#endif
@@ -45,9 +57,15 @@ class __wrap_iter {
public:
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 __wrap_iter() _NOEXCEPT : __i_() {}
+#ifdef _LIBCPP_ABI_WRAP_ITER_ADL_PROOF
+ template <bool _B, __enable_if_t<!_B, int> = 0>
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 __wrap_iter(const __wrap_iter<_B>& __u) _NOEXCEPT
+ : __i_(__u.base()) {}
+#else
template <class _Up, __enable_if_t<is_convertible<_Up, iterator_type>::value, int> = 0>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 __wrap_iter(const __wrap_iter<_Up>& __u) _NOEXCEPT
: __i_(__u.base()) {}
+#endif
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 reference operator*() const _NOEXCEPT { return *__i_; }
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pointer operator->() const _NOEXCEPT {
return std::__to_address(__i_);
@@ -96,7 +114,13 @@ class __wrap_iter {
private:
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 explicit __wrap_iter(iterator_type __x) _NOEXCEPT : __i_(__x) {}
+#ifdef _LIBCPP_ABI_WRAP_ITER_ADL_PROOF
+ using __is_wrap_iter = void;
+
+ template <bool _OtherConst>
+#else
template <class _Up>
+#endif
friend class __wrap_iter;
template <class _CharT, class _Traits, class _Alloc>
friend class basic_string;
@@ -108,85 +132,99 @@ class __wrap_iter {
friend class _LIBCPP_TEMPLATE_VIS span;
template <class _Tp, size_t _Size>
friend struct array;
-};
+ };
+
+#ifdef _LIBCPP_ABI_WRAP_ITER_ADL_PROOF
+# define _LIBCPP_WRAP_ITER_SINGLE_TEMPLATE_HEAD \
+ template <bool _Iter1> \
+ friend
+# define _LIBCPP_WRAP_ITER_PAIR_TEMPLATE_HEAD \
+ template <bool _Iter1, bool _Iter2> \
+ friend
+#else
+# define _LIBCPP_WRAP_ITER_SINGLE_TEMPLATE_HEAD template <class _Iter1>
+# define _LIBCPP_WRAP_ITER_PAIR_TEMPLATE_HEAD template <class _Iter1, class _Iter2>
+#endif
-template <class _Iter1>
-_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool
-operator==(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter1>& __y) _NOEXCEPT {
- return __x.base() == __y.base();
-}
+ _LIBCPP_WRAP_ITER_SINGLE_TEMPLATE_HEAD
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool
+ operator==(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter1>& __y) _NOEXCEPT {
+ return __x.base() == __y.base();
+ }
-template <class _Iter1, class _Iter2>
-_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool
-operator==(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) _NOEXCEPT {
- return __x.base() == __y.base();
-}
+ _LIBCPP_WRAP_ITER_PAIR_TEMPLATE_HEAD
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool
+ operator==(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) _NOEXCEPT {
+ return __x.base() == __y.base();
+ }
-template <class _Iter1>
-_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 bool
-operator<(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter1>& __y) _NOEXCEPT {
- return __x.base() < __y.base();
-}
+ _LIBCPP_WRAP_ITER_SINGLE_TEMPLATE_HEAD
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 bool
+ operator<(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter1>& __y) _NOEXCEPT {
+ return __x.base() < __y.base();
+ }
-template <class _Iter1, class _Iter2>
-_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 bool
-operator<(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) _NOEXCEPT {
- return __x.base() < __y.base();
-}
+ _LIBCPP_WRAP_ITER_PAIR_TEMPLATE_HEAD
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 bool
+ operator<(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) _NOEXCEPT {
+ return __x.base() < __y.base();
+ }
#if _LIBCPP_STD_VER <= 17
-template <class _Iter1>
-_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool
-operator!=(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter1>& __y) _NOEXCEPT {
- return !(__x == __y);
-}
+ _LIBCPP_WRAP_ITER_SINGLE_TEMPLATE_HEAD
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool
+ operator!=(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter1>& __y) _NOEXCEPT {
+ return !(__x == __y);
+ }
-template <class _Iter1, class _Iter2>
-_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool
-operator!=(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) _NOEXCEPT {
- return !(__x == __y);
-}
-template <class _Iter1>
-_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool
-operator>(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter1>& __y) _NOEXCEPT {
- return __y < __x;
-}
+ _LIBCPP_WRAP_ITER_PAIR_TEMPLATE_HEAD
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool
+ operator!=(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) _NOEXCEPT {
+ return !(__x == __y);
+ }
+ _LIBCPP_WRAP_ITER_SINGLE_TEMPLATE_HEAD
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool
+ operator>(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter1>& __y) _NOEXCEPT {
+ return __y < __x;
+ }
-template <class _Iter1, class _Iter2>
-_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool
-operator>(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) _NOEXCEPT {
- return __y < __x;
-}
+ _LIBCPP_WRAP_ITER_PAIR_TEMPLATE_HEAD
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool
+ operator>(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) _NOEXCEPT {
+ return __y < __x;
+ }
-template <class _Iter1>
-_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool
-operator>=(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter1>& __y) _NOEXCEPT {
- return !(__x < __y);
-}
+ _LIBCPP_WRAP_ITER_SINGLE_TEMPLATE_HEAD
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool
+ operator>=(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter1>& __y) _NOEXCEPT {
+ return !(__x < __y);
+ }
-template <class _Iter1, class _Iter2>
-_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool
-operator>=(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) _NOEXCEPT {
- return !(__x < __y);
-}
+ _LIBCPP_WRAP_ITER_PAIR_TEMPLATE_HEAD
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool
+ operator>=(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) _NOEXCEPT {
+ return !(__x < __y);
+ }
-template <class _Iter1>
-_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool
-operator<=(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter1>& __y) _NOEXCEPT {
- return !(__y < __x);
-}
+ _LIBCPP_WRAP_ITER_SINGLE_TEMPLATE_HEAD
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool
+ operator<=(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter1>& __y) _NOEXCEPT {
+ return !(__y < __x);
+ }
-template <class _Iter1, class _Iter2>
-_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool
-operator<=(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) _NOEXCEPT {
- return !(__y < __x);
-}
+ _LIBCPP_WRAP_ITER_PAIR_TEMPLATE_HEAD
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool
+ operator<=(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) _NOEXCEPT {
+ return !(__y < __x);
+ }
#else
-template <class _Iter1, class _Iter2>
+_LIBCPP_WRAP_ITER_PAIR_TEMPLATE_HEAD
_LIBCPP_HIDE_FROM_ABI constexpr strong_ordering
operator<=>(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) noexcept {
- if constexpr (three_way_comparable_with<_Iter1, _Iter2, strong_ordering>) {
+ if constexpr (three_way_comparable_with<typename __wrap_iter<_Iter1>::iterator_type,
+ typename __wrap_iter<_Iter2>::iterator_type,
+ strong_ordering>) {
return __x.base() <=> __y.base();
} else {
if (__x.base() < __y.base())
@@ -200,31 +238,38 @@ operator<=>(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) noex
}
#endif // _LIBCPP_STD_VER >= 20
-template <class _Iter1, class _Iter2>
-_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14
+ _LIBCPP_WRAP_ITER_PAIR_TEMPLATE_HEAD
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14
#ifndef _LIBCPP_CXX03_LANG
- auto
- operator-(const __wrap_iter<_Iter1>& __x,
- const __wrap_iter<_Iter2>& __y) _NOEXCEPT->decltype(__x.base() - __y.base())
+ auto
+ operator-(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) _NOEXCEPT->decltype(__x.base() - __y.base())
#else
typename __wrap_iter<_Iter1>::difference_type
operator-(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) _NOEXCEPT
#endif // C++03
-{
+ {
return __x.base() - __y.base();
-}
+ }
-template <class _Iter1>
-_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 __wrap_iter<_Iter1>
-operator+(typename __wrap_iter<_Iter1>::difference_type __n, __wrap_iter<_Iter1> __x) _NOEXCEPT {
- __x += __n;
- return __x;
-}
+ _LIBCPP_WRAP_ITER_SINGLE_TEMPLATE_HEAD
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 __wrap_iter<_Iter1>
+ operator+(typename __wrap_iter<_Iter1>::difference_type __n, __wrap_iter<_Iter1> __x) _NOEXCEPT {
+ __x += __n;
+ return __x;
+ }
-#if _LIBCPP_STD_VER <= 17
+#ifdef _LIBCPP_ABI_WRAP_ITER_ADL_PROOF
+};
+
+template <class _MutableIter, class _ConstIter>
+using __wrap_mut_iter = typename __wrap_iter_impl<_MutableIter, _ConstIter>::template __wrap_iter<false>;
+template <class _MutableIter, class _ConstIter>
+using __wrap_const_iter = typename __wrap_iter_impl<_MutableIter, _ConstIter>::template __wrap_iter<true>;
+#else
+# if _LIBCPP_STD_VER <= 17
template <class _It>
struct __libcpp_is_contiguous_iterator<__wrap_iter<_It> > : true_type {};
-#endif
+# endif
template <class _It>
struct _LIBCPP_TEMPLATE_VIS pointer_traits<__wrap_iter<_It> > {
@@ -237,6 +282,12 @@ struct _LIBCPP_TEMPLATE_VIS pointer_traits<__wrap_iter<_It> > {
}
};
+template <class _MutableIter, class _ConstIter>
+using __wrap_mut_iter = __wrap_iter<_MutableIter>;
+template <class _MutableIter, class _ConstIter>
+using __wrap_const_iter = __wrap_iter<_ConstIter>;
+#endif
+
_LIBCPP_END_NAMESPACE_STD
#endif // _LIBCPP___ITERATOR_WRAP_ITER_H
diff --git a/libcxx/include/__memory/pointer_traits.h b/libcxx/include/__memory/pointer_traits.h
index 8e08eb74413ee5..0e4196625af4e9 100644
--- a/libcxx/include/__memory/pointer_traits.h
+++ b/libcxx/include/__memory/pointer_traits.h
@@ -43,6 +43,7 @@ _LIBCPP_BEGIN_NAMESPACE_STD
_LIBCPP_CLASS_TRAITS_HAS_XXX(__has_pointer, pointer);
_LIBCPP_CLASS_TRAITS_HAS_XXX(__has_element_type, element_type);
+_LIBCPP_CLASS_TRAITS_HAS_XXX(__is_wrap_iter, __is_wrap_iter);
template <class _Ptr, bool = __has_element_type<_Ptr>::value>
struct __pointer_traits_element_type {};
@@ -115,11 +116,21 @@ struct __pointer_traits_rebind<_Sp<_Tp, _Args...>, _Up, false> {
typedef _Sp<_Up, _Args...> type;
};
+#ifdef _LIBCPP_ABI_WRAP_ITER_ADL_PROOF
+template <class _Ptr, bool, class = void>
+struct __pointer_traits_impl {};
+
+template <class _Ptr>
+struct __pointer_traits_impl<_Ptr,
+ false,
+#else
template <class _Ptr, class = void>
struct __pointer_traits_impl {};
template <class _Ptr>
-struct __pointer_traits_impl<_Ptr, __void_t<typename __pointer_traits_element_type<_Ptr>::type> > {
+struct __pointer_traits_impl<_Ptr,
+#endif
+ __void_t<typename __pointer_traits_element_type<_Ptr>::type> > {
typedef _Ptr pointer;
typedef typename __pointer_traits_element_type<pointer>::type element_type;
typedef typename __pointer_traits_difference_type<pointer>::type difference_type;
@@ -144,8 +155,25 @@ struct __pointer_traits_impl<_Ptr, __void_t<typename __pointer_traits_element_ty
}
};
+#ifdef _LIBCPP_ABI_WRAP_ITER_ADL_PROOF
+template <class _Ptr>
+struct _LIBCPP_TEMPLATE_VIS pointer_traits;
+
+template <class _WrapIt>
+struct __pointer_traits_impl<_WrapIt, true, void> {
+ using pointer = _WrapIt;
+ using element_type = typename pointer_traits<typename _WrapIt::iterator_type>::element_type;
+ using difference_type = typename pointer_traits<typename _WrapIt::iterator_type>::difference_type;
+
+ inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR static element_type* to_address(pointer __w) _NOEXCEPT;
+};
+
+template <class _Ptr>
+struct _LIBCPP_TEMPLATE_VIS pointer_traits : __pointer_traits_impl<_Ptr, __is_wrap_iter<_Ptr>::value> {};
+#else
template <class _Ptr>
struct _LIBCPP_TEMPLATE_VIS pointer_traits : __pointer_traits_impl<_Ptr> {};
+#endif
template <class _Tp>
struct _LIBCPP_TEMPLATE_VIS pointer_traits<_Tp*> {
@@ -237,6 +265,14 @@ struct __to_address_helper<_Pointer,
}
};
+#ifdef _LIBCPP_ABI_WRAP_ITER_ADL_PROOF
+template <class _WrapIt>
+inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR typename __pointer_traits_impl<_WrapIt, true, void>::element_type*
+__pointer_traits_impl<_WrapIt, true, void>::to_address(pointer __w) _NOEXCEPT {
+ return std::__to_address(__w);
+}
+#endif
+
#if _LIBCPP_STD_VER >= 20
template <class _Tp>
inline _LIBCPP_HIDE_FROM_ABI constexpr auto to_address(_Tp* __p) noexcept {
diff --git a/libcxx/include/array b/libcxx/include/array
index 588664ace0162a..36fb4963b875c8 100644
--- a/libcxx/include/array
+++ b/libcxx/include/array
@@ -177,8 +177,8 @@ struct _LIBCPP_TEMPLATE_VIS array {
using pointer = value_type*;
using const_pointer = const value_type*;
#if defined(_LIBCPP_ABI_USE_WRAP_ITER_IN_STD_ARRAY)
- using iterator = __wrap_iter<pointer>;
- using const_iterator = __wrap_iter<const_pointer>;
+ using iterator = __wrap_mut_iter<pointer, const_pointer>;
+ using const_iterator = __wrap_const_iter<pointer, const_pointer>;
#else
using iterator = pointer;
using const_iterator = const_pointer;
@@ -277,8 +277,8 @@ struct _LIBCPP_TEMPLATE_VIS array<_Tp, 0> {
using pointer = value_type*;
using const_pointer = const value_type*;
#if defined(_LIBCPP_ABI_USE_WRAP_ITER_IN_STD_ARRAY)
- using iterator = __wrap_iter<pointer>;
- using const_iterator = __wrap_iter<const_pointer>;
+ using iterator = __wrap_mut_iter<pointer, const_pointer>;
+ using const_iterator = __wrap_const_iter<pointer, const_pointer>;
#else
using iterator = pointer;
using const_iterator = const_pointer;
diff --git a/libcxx/include/regex b/libcxx/include/regex
index 08aebc2266f5de..0e3e90cc5c634a 100644
--- a/libcxx/include/regex
+++ b/libcxx/include/regex
@@ -2632,6 +2632,16 @@ private:
const basic_regex<_Cp, _Tp>& __e,
regex_constants::match_flag_type __flags);
+#ifdef _LIBCPP_ABI_WRAP_ITER_ADL_PROOF
+ template <class _WrapIter, class _Ap, class _Cp, class _Tp, typename _WrapIter::__is_wrap_iter*>
+ friend bool
+ regex_search(_WrapIter __first,
+ _WrapIter __last,
+ match_results<_WrapIter, _Ap>& __m,
+ const basic_regex<_Cp, _Tp>& __e,
+ regex_constants::match_flag_type __flags);
+
+#else
template <class _Iter, class _Ap, class _Cp, class _Tp>
friend bool
regex_search(__wrap_iter<_Iter> __first,
@@ -2639,6 +2649,7 @@ private:
match_results<__wrap_iter<_Iter>, _Ap>& __m,
const basic_regex<_Cp, _Tp>& __e,
regex_constants::match_flag_type __flags);
+#endif
template <class, class>
friend class __lookahead;
@@ -5149,6 +5160,15 @@ regex_search(_BidirectionalIterator __first,
return __r;
}
+#ifdef _LIBCPP_ABI_WRAP_ITER_ADL_PROOF
+template <class _WrapIter, class _Allocator, class _CharT, class _Traits, typename _WrapIter::__is_wrap_iter* = nullptr>
+inline _LIBCPP_HIDE_FROM_ABI bool
+regex_search(_WrapIter __first,
+ _WrapIter __last,
+ match_results<_WrapIter, _Allocator>& __m,
+ const basic_regex<_CharT, _Traits>& __e,
+ regex_constants::match_flag_type __flags = regex_constants::match_default) {
+#else
template <class _Iter, class _Allocator, class _CharT, class _Traits>
inline _LIBCPP_HIDE_FROM_ABI bool
regex_search(__wrap_iter<_Iter> __first,
@@ -5156,6 +5176,7 @@ regex_search(__wrap_iter<_Iter> __first,
match_results<__wrap_iter<_Iter>, _Allocator>& __m,
const basic_regex<_CharT, _Traits>& __e,
regex_constants::match_flag_type __flags = regex_constants::match_default) {
+#endif
match_results<const _CharT*> __mc;
bool __r = __e.__search(__first.base(), __last.base(), __mc, __flags);
__m.__assign(__first, __last, __mc, __flags & regex_constants::__no_update_pos);
diff --git a/libcxx/include/span b/libcxx/include/span
index a32f7a372e2ae1..a691ba7e8623e4 100644
--- a/libcxx/include/span
+++ b/libcxx/include/span
@@ -239,7 +239,7 @@ public:
# ifdef _LIBCPP_ABI_BOUNDED_ITERATORS
using iterator = __bounded_iter<pointer>;
# else
- using iterator = __wrap_iter<pointer>;
+ using iterator = __wrap_mut_iter<pointer, pointer>;
# endif
using reverse_iterator = std::reverse_iterator<iterator>;
@@ -420,7 +420,7 @@ public:
# ifdef _LIBCPP_ABI_BOUNDED_ITERATORS
using iterator = __bounded_iter<pointer>;
# else
- using iterator = __wrap_iter<pointer>;
+ using iterator = __wrap_mut_iter<pointer, pointer>;
# endif
using reverse_iterator = std::reverse_iterator<iterator>;
diff --git a/libcxx/include/string b/libcxx/include/string
index 3480b57375c118..a4ccaaec4c9c21 100644
--- a/libcxx/include/string
+++ b/libcxx/include/string
@@ -732,6 +732,17 @@ operator+(type_identity_t<basic_string_view<_CharT, _Traits>> __lhs, basic_strin
extern template _LIBCPP_EXPORTED_FROM_ABI string operator+
<char, char_traits<char>, allocator<char> >(char const*, string const&);
+#ifdef _LIBCPP_ABI_WRAP_ITER_ADL_PROOF
+template <class _Iter, class = void>
+struct __string_is_trivial_iterator : public false_type {};
+
+template <class _Tp>
+struct __string_is_trivial_iterator<_Tp*, void> : public is_arithmetic<_Tp> {};
+
+template <class _WrapIter>
+struct __string_is_trivial_iterator<_WrapIter, __void_t<typename _WrapIter::__is_wrap_iter> >
+ : public __string_is_trivial_iterator<typename _WrapIter::iterator_type> {};
+#else
template <class _Iter>
struct __string_is_trivial_iterator : public false_type {};
@@ -740,6 +751,7 @@ struct __string_is_trivial_iterator<_Tp*> : public is_arithmetic<_Tp> {};
template <class _Iter>
struct __string_is_trivial_iterator<__wrap_iter<_Iter> > : public __string_is_trivial_iterator<_Iter> {};
+#endif
template <class _CharT, class _Traits, class _Tp>
struct __can_be_converted_to_string_view
@@ -828,11 +840,11 @@ 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.
- typedef __bounded_iter<__wrap_iter<pointer> > iterator;
- typedef __bounded_iter<__wrap_iter<const_pointer> > const_iterator;
+ typedef __bounded_iter<__wrap_mut_iter<pointer, const_pointer> > iterator;
+ typedef __bounded_iter<__wrap_const_iter<pointer, const_pointer> > const_iterator;
#else
- typedef __wrap_iter<pointer> iterator;
- typedef __wrap_iter<const_pointer> const_iterator;
+ typedef __wrap_mut_iter<pointer, const_pointer> iterator;
+ typedef __wrap_const_iter<pointer, const_pointer> const_iterator;
#endif
typedef std::reverse_iterator<iterator> reverse_iterator;
typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
@@ -958,9 +970,9 @@ private:
// 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()));
+ __wrap_mut_iter<pointer, const_pointer>(__p),
+ __wrap_mut_iter<pointer, const_pointer>(__get_pointer()),
+ __wrap_mut_iter<pointer, const_pointer>(__get_pointer() + size()));
#else
return iterator(__p);
#endif // _LIBCPP_ABI_BOUNDED_ITERATORS_IN_STRING
@@ -970,9 +982,9 @@ private:
#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()));
+ __wrap_const_iter<pointer, const_pointer>(__p),
+ __wrap_const_iter<pointer, const_pointer>(__get_pointer()),
+ __wrap_const_iter<pointer, const_pointer>(__get_pointer() + size()));
#else
return const_iterator(__p);
#endif // _LIBCPP_ABI_BOUNDED_ITERATORS_IN_STRING
diff --git a/libcxx/include/string_view b/libcxx/include/string_view
index cf97e3a9be314d..451b50fb7a7b71 100644
--- a/libcxx/include/string_view
+++ b/libcxx/include/string_view
@@ -284,7 +284,7 @@ public:
#if defined(_LIBCPP_ABI_BOUNDED_ITERATORS)
using const_iterator = __bounded_iter<const_pointer>;
#elif defined(_LIBCPP_ABI_USE_WRAP_ITER_IN_STD_STRING_VIEW)
- using const_iterator = __wrap_iter<const_pointer>;
+ using const_iterator = __wrap_const_iter<const_pointer, const_pointer>;
#else
using const_iterator = const_pointer;
#endif
diff --git a/libcxx/include/vector b/libcxx/include/vector
index 2442852c764a63..2bf296fef5d063 100644
--- a/libcxx/include/vector
+++ b/libcxx/include/vector
@@ -404,11 +404,11 @@ 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.
- typedef __bounded_iter<__wrap_iter<pointer> > iterator;
- typedef __bounded_iter<__wrap_iter<const_pointer> > const_iterator;
+ typedef __bounded_iter<__wrap_mut_iter<pointer, const_pointer> > iterator;
+ typedef __bounded_iter<__wrap_const_iter<pointer, const_pointer> > const_iterator;
#else
- typedef __wrap_iter<pointer> iterator;
- typedef __wrap_iter<const_pointer> const_iterator;
+ typedef __wrap_mut_iter<pointer, const_pointer> iterator;
+ typedef __wrap_const_iter<pointer, const_pointer> const_iterator;
#endif
typedef std::reverse_iterator<iterator> reverse_iterator;
typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
@@ -847,9 +847,9 @@ private:
// 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->__end_cap()));
+ __wrap_mut_iter<pointer, const_pointer>(__p),
+ __wrap_mut_iter<pointer, const_pointer>(this->__begin_),
+ __wrap_mut_iter<pointer, const_pointer>(this->__end_cap()));
#else
return iterator(__p);
#endif // _LIBCPP_ABI_BOUNDED_ITERATORS_IN_VECTOR
@@ -859,9 +859,9 @@ private:
#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->__end_cap()));
+ __wrap_const_iter<pointer, const_pointer>(__p),
+ __wrap_const_iter<pointer, const_pointer>(this->__begin_),
+ __wrap_const_iter<pointer, const_pointer>(this->__end_cap()));
#else
return const_iterator(__p);
#endif // _LIBCPP_ABI_BOUNDED_ITERATORS_IN_VECTOR
diff --git a/libcxx/test/libcxx/iterators/contiguous_iterators.pass.cpp b/libcxx/test/libcxx/iterators/contiguous_iterators.pass.cpp
index f00ca4e8794031..a5b1123b269f71 100644
--- a/libcxx/test/libcxx/iterators/contiguous_iterators.pass.cpp
+++ b/libcxx/test/libcxx/iterators/contiguous_iterators.pass.cpp
@@ -181,20 +181,35 @@ int main(int, char**)
static_assert((!std::__libcpp_is_contiguous_iterator<std::reverse_iterator<my_contiguous_iterator> >::value), "");
#endif
- static_assert(( std::__libcpp_is_contiguous_iterator<std::__wrap_iter<char *> >::value), "");
- static_assert(( std::__libcpp_is_contiguous_iterator<std::__wrap_iter<const char *> >::value), "");
- static_assert(( std::__libcpp_is_contiguous_iterator<std::__wrap_iter<int *> >::value), "");
+ static_assert((std::__libcpp_is_contiguous_iterator<std::__wrap_mut_iter<char*, const char*> >::value), "");
+ static_assert((std::__libcpp_is_contiguous_iterator<std::__wrap_const_iter<char*, const char*> >::value), "");
+ static_assert((std::__libcpp_is_contiguous_iterator<std::__wrap_mut_iter<int*, const int*> >::value), "");
- static_assert(( std::__libcpp_is_contiguous_iterator<std::__wrap_iter<T *> >::value), "");
- static_assert(( std::__libcpp_is_contiguous_iterator<std::__wrap_iter<std::__wrap_iter<T *> > >::value), "");
+ static_assert((std::__libcpp_is_contiguous_iterator<std::__wrap_mut_iter<T*, const T*> >::value), "");
+ static_assert(
+ (std::__libcpp_is_contiguous_iterator<
+ std::__wrap_mut_iter<std::__wrap_mut_iter<T*, const T*>, std::__wrap_mut_iter<T*, const T*> > >::value),
+ "");
// Here my_random_access_iterator is standing in for some user's fancy pointer type, written pre-C++20.
- static_assert(( std::__libcpp_is_contiguous_iterator<std::__wrap_iter<my_random_access_iterator> >::value), "");
- static_assert(( std::__libcpp_is_contiguous_iterator<std::__wrap_iter<std::__wrap_iter<my_random_access_iterator> > >::value), "");
+ static_assert((std::__libcpp_is_contiguous_iterator<
+ std::__wrap_mut_iter<my_random_access_iterator, my_random_access_iterator> >::value),
+ "");
+ static_assert(
+ (std::__libcpp_is_contiguous_iterator<
+ std::__wrap_mut_iter<std::__wrap_mut_iter<my_random_access_iterator, my_random_access_iterator>,
+ std::__wrap_mut_iter<my_random_access_iterator, my_random_access_iterator> > >::value),
+ "");
#if TEST_STD_VER >= 20
- static_assert(( std::__libcpp_is_contiguous_iterator<std::__wrap_iter<my_contiguous_iterator> >::value), "");
- static_assert(( std::__libcpp_is_contiguous_iterator<std::__wrap_iter<std::__wrap_iter<my_contiguous_iterator> > >::value), "");
+ static_assert((std::__libcpp_is_contiguous_iterator<
+ std::__wrap_mut_iter<my_contiguous_iterator, my_contiguous_iterator> >::value),
+ "");
+ static_assert(
+ (std::__libcpp_is_contiguous_iterator<
+ std::__wrap_mut_iter<std::__wrap_mut_iter<my_contiguous_iterator, my_contiguous_iterator>,
+ std::__wrap_mut_iter<my_contiguous_iterator, my_contiguous_iterator> > >::value),
+ "");
#endif
// iterators in the libc++ test suite
@@ -218,9 +233,11 @@ int main(int, char**)
static_assert(( std::__libcpp_is_contiguous_iterator<std::vector<int>::const_iterator> ::value), "");
static_assert((!std::__libcpp_is_contiguous_iterator<std::vector<int>::reverse_iterator> ::value), "");
static_assert((!std::__libcpp_is_contiguous_iterator<std::vector<int>::const_reverse_iterator> ::value), "");
- static_assert(( std::__libcpp_is_contiguous_iterator<std::__wrap_iter<std::vector<int>::iterator> >::value), "");
+ static_assert((std::__libcpp_is_contiguous_iterator<
+ std::__wrap_mut_iter<std::vector<int>::iterator, std::vector<int>::const_iterator> >::value),
+ "");
-// string
+ // string
static_assert(( std::__libcpp_is_contiguous_iterator<std::string::iterator> ::value), "");
static_assert(( std::__libcpp_is_contiguous_iterator<std::string::const_iterator> ::value), "");
static_assert((!std::__libcpp_is_contiguous_iterator<std::string::reverse_iterator> ::value), "");
diff --git a/libcxx/test/libcxx/iterators/unwrap_iter.pass.cpp b/libcxx/test/libcxx/iterators/unwrap_iter.pass.cpp
index 8ef2be2b010743..c2956cd6120ecc 100644
--- a/libcxx/test/libcxx/iterators/unwrap_iter.pass.cpp
+++ b/libcxx/test/libcxx/iterators/unwrap_iter.pass.cpp
@@ -26,11 +26,13 @@ template <class Iter>
using rev_rev_iter = rev_iter<rev_iter<Iter> >;
static_assert(std::is_same<UnwrapT<int*>, int*>::value, "");
-static_assert(std::is_same<UnwrapT<std::__wrap_iter<int*> >, int*>::value, "");
+static_assert(std::is_same<UnwrapT<std::__wrap_mut_iter<int*, const int*> >, int*>::value, "");
static_assert(std::is_same<UnwrapT<rev_iter<int*> >, std::reverse_iterator<int*> >::value, "");
static_assert(std::is_same<UnwrapT<rev_rev_iter<int*> >, int*>::value, "");
-static_assert(std::is_same<UnwrapT<rev_rev_iter<std::__wrap_iter<int*> > >, int*>::value, "");
-static_assert(std::is_same<UnwrapT<rev_rev_iter<rev_iter<std::__wrap_iter<int*> > > >, rev_iter<std::__wrap_iter<int*> > >::value, "");
+static_assert(std::is_same<UnwrapT<rev_rev_iter<std::__wrap_mut_iter<int*, const int*> > >, int*>::value, "");
+static_assert(std::is_same<UnwrapT<rev_rev_iter<rev_iter<std::__wrap_mut_iter<int*, const int*> > > >,
+ rev_iter<std::__wrap_mut_iter<int*, const int*> > >::value,
+ "");
static_assert(std::is_same<UnwrapT<random_access_iterator<int*> >, random_access_iterator<int*> >::value, "");
static_assert(std::is_same<UnwrapT<rev_iter<random_access_iterator<int*> > >, rev_iter<random_access_iterator<int*> > >::value, "");
diff --git a/libcxx/test/libcxx/iterators/wrap_iter_adl.compile.pass.cpp b/libcxx/test/libcxx/iterators/wrap_iter_adl.compile.pass.cpp
new file mode 100644
index 00000000000000..d2cfbf16870ff6
--- /dev/null
+++ b/libcxx/test/libcxx/iterators/wrap_iter_adl.compile.pass.cpp
@@ -0,0 +1,58 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// Check that whats used for __wrap_iter<T> does not try to look into T
+// for ADL
+
+#include <__iterator/wrap_iter.h>
+#include <vector>
+#include <array>
+#include <iterator>
+
+#include "test_macros.h"
+
+#ifdef _LIBCPP_ABI_WRAP_ITER_ADL_PROOF
+
+struct incomplete;
+template <class T>
+struct holder {
+ T t;
+};
+
+struct nefarious {
+ friend void operator<=>(std::vector<nefarious>::iterator, std::vector<nefarious>::iterator) = delete;
+ friend void operator==(std::vector<nefarious>::const_iterator, std::vector<nefarious>::const_iterator) = delete;
+};
+
+template <class Container>
+void test() {
+ using iterator = typename Container::iterator;
+ using const_iterator = typename Container::const_iterator;
+
+ (void)(iterator() < iterator());
+ (void)(iterator() < const_iterator());
+ (void)(const_iterator() < const_iterator());
+ (void)(iterator() == iterator());
+ (void)(iterator() == const_iterator());
+ (void)(const_iterator() == const_iterator());
+
+# if TEST_STD_VER >= 20
+ static_assert(std::contiguous_iterator<iterator>);
+ static_assert(std::contiguous_iterator<const_iterator>);
+ static_assert(std::ranges::contiguous_range<Container>);
+ static_assert(std::ranges::contiguous_range<const Container>);
+# endif
+}
+
+void tests() {
+ test<std::vector<holder<incomplete>*>>();
+ test<std::array<holder<incomplete>*, 10>>();
+ test<std::vector<nefarious>>();
+ test<std::array<nefarious, 10>>();
+}
+#endif
diff --git a/libcxx/test/std/strings/basic.string/range_concept_conformance.compile.pass.cpp b/libcxx/test/std/strings/basic.string/range_concept_conformance.compile.pass.cpp
index b6afc20e3cccb0..4712f85078a306 100644
--- a/libcxx/test/std/strings/basic.string/range_concept_conformance.compile.pass.cpp
+++ b/libcxx/test/std/strings/basic.string/range_concept_conformance.compile.pass.cpp
@@ -15,20 +15,34 @@
#include <concepts>
#include <ranges>
-static_assert(std::same_as<std::ranges::iterator_t<std::string>, std::string::iterator>);
-static_assert(std::ranges::common_range<std::string>);
-static_assert(std::ranges::random_access_range<std::string>);
-static_assert(std::ranges::contiguous_range<std::string>);
-static_assert(!std::ranges::view<std::string>);
-static_assert(std::ranges::sized_range<std::string>);
-static_assert(!std::ranges::borrowed_range<std::string>);
-static_assert(std::ranges::viewable_range<std::string>);
-
-static_assert(std::same_as<std::ranges::iterator_t<std::string const>, std::string::const_iterator>);
-static_assert(std::ranges::common_range<std::string const>);
-static_assert(std::ranges::random_access_range<std::string const>);
-static_assert(std::ranges::contiguous_range<std::string const>);
-static_assert(!std::ranges::view<std::string const>);
-static_assert(std::ranges::sized_range<std::string const>);
-static_assert(!std::ranges::borrowed_range<std::string const>);
-static_assert(!std::ranges::viewable_range<std::string const>);
+#include "nasty_string.h"
+#include "test_macros.h"
+
+template <class String>
+void test() {
+ static_assert(std::same_as<std::ranges::iterator_t<String>, typename String::iterator>);
+ static_assert(std::ranges::common_range<String>);
+ static_assert(std::ranges::random_access_range<String>);
+ static_assert(std::ranges::contiguous_range<String>);
+ static_assert(!std::ranges::view<String>);
+ static_assert(std::ranges::sized_range<String>);
+ static_assert(!std::ranges::borrowed_range<String>);
+ static_assert(std::ranges::viewable_range<String>);
+
+ static_assert(std::same_as<std::ranges::iterator_t<String const>, typename String::const_iterator>);
+ static_assert(std::ranges::common_range<String const>);
+ static_assert(std::ranges::random_access_range<String const>);
+ static_assert(std::ranges::contiguous_range<String const>);
+ static_assert(!std::ranges::view<String const>);
+ static_assert(std::ranges::sized_range<String const>);
+ static_assert(!std::ranges::borrowed_range<String const>);
+ static_assert(!std::ranges::viewable_range<String const>);
+}
+
+void tests() {
+ test<std::string>();
+ test<std::wstring>();
+#ifndef TEST_HAS_NO_NASTY_STRING
+ test<nasty_string>();
+#endif
+}
diff --git a/libcxx/test/std/strings/basic.string/string.iterators/iterator_concept_conformance.compile.pass.cpp b/libcxx/test/std/strings/basic.string/string.iterators/iterator_concept_conformance.compile.pass.cpp
index bde2f9e9cde327..77212e24d7a644 100644
--- a/libcxx/test/std/strings/basic.string/string.iterators/iterator_concept_conformance.compile.pass.cpp
+++ b/libcxx/test/std/strings/basic.string/string.iterators/iterator_concept_conformance.compile.pass.cpp
@@ -14,64 +14,77 @@
#include <iterator>
-using iterator = std::string::iterator;
-using const_iterator = std::string::const_iterator;
-using reverse_iterator = std::string::reverse_iterator;
-using const_reverse_iterator = std::string::const_reverse_iterator;
-using value_type = char;
+#include "nasty_string.h"
-static_assert(std::contiguous_iterator<iterator>);
-static_assert(std::indirectly_writable<iterator, value_type>);
-static_assert(std::sentinel_for<iterator, iterator>);
-static_assert(std::sentinel_for<iterator, const_iterator>);
-static_assert(!std::sentinel_for<iterator, reverse_iterator>);
-static_assert(!std::sentinel_for<iterator, const_reverse_iterator>);
-static_assert(std::sized_sentinel_for<iterator, iterator>);
-static_assert(std::sized_sentinel_for<iterator, const_iterator>);
-static_assert(!std::sized_sentinel_for<iterator, reverse_iterator>);
-static_assert(!std::sized_sentinel_for<iterator, const_reverse_iterator>);
-static_assert(std::indirectly_movable<iterator, iterator>);
-static_assert(std::indirectly_movable_storable<iterator, iterator>);
-static_assert(!std::indirectly_movable<iterator, const_iterator>);
-static_assert(!std::indirectly_movable_storable<iterator, const_iterator>);
-static_assert(std::indirectly_movable<iterator, reverse_iterator>);
-static_assert(std::indirectly_movable_storable<iterator, reverse_iterator>);
-static_assert(!std::indirectly_movable<iterator, const_reverse_iterator>);
-static_assert(!std::indirectly_movable_storable<iterator, const_reverse_iterator>);
-static_assert(std::indirectly_copyable<iterator, iterator>);
-static_assert(std::indirectly_copyable_storable<iterator, iterator>);
-static_assert(!std::indirectly_copyable<iterator, const_iterator>);
-static_assert(!std::indirectly_copyable_storable<iterator, const_iterator>);
-static_assert(std::indirectly_copyable<iterator, reverse_iterator>);
-static_assert(std::indirectly_copyable_storable<iterator, reverse_iterator>);
-static_assert(!std::indirectly_copyable<iterator, const_reverse_iterator>);
-static_assert(!std::indirectly_copyable_storable<iterator, const_reverse_iterator>);
-static_assert(std::indirectly_swappable<iterator, iterator>);
+template <class String>
+void test() {
+ using iterator = typename String::iterator;
+ using const_iterator = typename String::const_iterator;
+ using reverse_iterator = typename String::reverse_iterator;
+ using const_reverse_iterator = typename String::const_reverse_iterator;
+ using value_type = typename String::value_type;
-static_assert(std::contiguous_iterator<const_iterator>);
-static_assert(!std::indirectly_writable<const_iterator, value_type>);
-static_assert(std::sentinel_for<const_iterator, iterator>);
-static_assert(std::sentinel_for<const_iterator, const_iterator>);
-static_assert(!std::sentinel_for<const_iterator, reverse_iterator>);
-static_assert(!std::sentinel_for<const_iterator, const_reverse_iterator>);
-static_assert(std::sized_sentinel_for<const_iterator, iterator>);
-static_assert(std::sized_sentinel_for<const_iterator, const_iterator>);
-static_assert(!std::sized_sentinel_for<const_iterator, reverse_iterator>);
-static_assert(!std::sized_sentinel_for<const_iterator, const_reverse_iterator>);
-static_assert(std::indirectly_movable<const_iterator, iterator>);
-static_assert(std::indirectly_movable_storable<const_iterator, iterator>);
-static_assert(!std::indirectly_movable<const_iterator, const_iterator>);
-static_assert(!std::indirectly_movable_storable<const_iterator, const_iterator>);
-static_assert(std::indirectly_movable<const_iterator, reverse_iterator>);
-static_assert(std::indirectly_movable_storable<const_iterator, reverse_iterator>);
-static_assert(!std::indirectly_movable<const_iterator, const_reverse_iterator>);
-static_assert(!std::indirectly_movable_storable<const_iterator, const_reverse_iterator>);
-static_assert(std::indirectly_copyable<const_iterator, iterator>);
-static_assert(std::indirectly_copyable_storable<const_iterator, iterator>);
-static_assert(!std::indirectly_copyable<const_iterator, const_iterator>);
-static_assert(!std::indirectly_copyable_storable<const_iterator, const_iterator>);
-static_assert(std::indirectly_copyable<const_iterator, reverse_iterator>);
-static_assert(std::indirectly_copyable_storable<const_iterator, reverse_iterator>);
-static_assert(!std::indirectly_copyable<const_iterator, const_reverse_iterator>);
-static_assert(!std::indirectly_copyable_storable<const_iterator, const_reverse_iterator>);
-static_assert(!std::indirectly_swappable<const_iterator, const_iterator>);
+ static_assert(std::contiguous_iterator<iterator>);
+ static_assert(std::indirectly_writable<iterator, value_type>);
+ static_assert(std::sentinel_for<iterator, iterator>);
+ static_assert(std::sentinel_for<iterator, const_iterator>);
+ static_assert(!std::sentinel_for<iterator, reverse_iterator>);
+ static_assert(!std::sentinel_for<iterator, const_reverse_iterator>);
+ static_assert(std::sized_sentinel_for<iterator, iterator>);
+ static_assert(std::sized_sentinel_for<iterator, const_iterator>);
+ static_assert(!std::sized_sentinel_for<iterator, reverse_iterator>);
+ static_assert(!std::sized_sentinel_for<iterator, const_reverse_iterator>);
+ static_assert(std::indirectly_movable<iterator, iterator>);
+ static_assert(std::indirectly_movable_storable<iterator, iterator>);
+ static_assert(!std::indirectly_movable<iterator, const_iterator>);
+ static_assert(!std::indirectly_movable_storable<iterator, const_iterator>);
+ static_assert(std::indirectly_movable<iterator, reverse_iterator>);
+ static_assert(std::indirectly_movable_storable<iterator, reverse_iterator>);
+ static_assert(!std::indirectly_movable<iterator, const_reverse_iterator>);
+ static_assert(!std::indirectly_movable_storable<iterator, const_reverse_iterator>);
+ static_assert(std::indirectly_copyable<iterator, iterator>);
+ static_assert(std::indirectly_copyable_storable<iterator, iterator>);
+ static_assert(!std::indirectly_copyable<iterator, const_iterator>);
+ static_assert(!std::indirectly_copyable_storable<iterator, const_iterator>);
+ static_assert(std::indirectly_copyable<iterator, reverse_iterator>);
+ static_assert(std::indirectly_copyable_storable<iterator, reverse_iterator>);
+ static_assert(!std::indirectly_copyable<iterator, const_reverse_iterator>);
+ static_assert(!std::indirectly_copyable_storable<iterator, const_reverse_iterator>);
+ static_assert(std::indirectly_swappable<iterator, iterator>);
+
+ static_assert(std::contiguous_iterator<const_iterator>);
+ static_assert(!std::indirectly_writable<const_iterator, value_type>);
+ static_assert(std::sentinel_for<const_iterator, iterator>);
+ static_assert(std::sentinel_for<const_iterator, const_iterator>);
+ static_assert(!std::sentinel_for<const_iterator, reverse_iterator>);
+ static_assert(!std::sentinel_for<const_iterator, const_reverse_iterator>);
+ static_assert(std::sized_sentinel_for<const_iterator, iterator>);
+ static_assert(std::sized_sentinel_for<const_iterator, const_iterator>);
+ static_assert(!std::sized_sentinel_for<const_iterator, reverse_iterator>);
+ static_assert(!std::sized_sentinel_for<const_iterator, const_reverse_iterator>);
+ static_assert(std::indirectly_movable<const_iterator, iterator>);
+ static_assert(std::indirectly_movable_storable<const_iterator, iterator>);
+ static_assert(!std::indirectly_movable<const_iterator, const_iterator>);
+ static_assert(!std::indirectly_movable_storable<const_iterator, const_iterator>);
+ static_assert(std::indirectly_movable<const_iterator, reverse_iterator>);
+ static_assert(std::indirectly_movable_storable<const_iterator, reverse_iterator>);
+ static_assert(!std::indirectly_movable<const_iterator, const_reverse_iterator>);
+ static_assert(!std::indirectly_movable_storable<const_iterator, const_reverse_iterator>);
+ static_assert(std::indirectly_copyable<const_iterator, iterator>);
+ static_assert(std::indirectly_copyable_storable<const_iterator, iterator>);
+ static_assert(!std::indirectly_copyable<const_iterator, const_iterator>);
+ static_assert(!std::indirectly_copyable_storable<const_iterator, const_iterator>);
+ static_assert(std::indirectly_copyable<const_iterator, reverse_iterator>);
+ static_assert(std::indirectly_copyable_storable<const_iterator, reverse_iterator>);
+ static_assert(!std::indirectly_copyable<const_iterator, const_reverse_iterator>);
+ static_assert(!std::indirectly_copyable_storable<const_iterator, const_reverse_iterator>);
+ static_assert(!std::indirectly_swappable<const_iterator, const_iterator>);
+}
+
+void tests() {
+ test<std::string>();
+ test<std::wstring>();
+#if !defined(TEST_HAS_NO_NASTY_STRING)
+ test<nasty_string>();
+#endif
+}
diff --git a/libcxx/test/support/nasty_string.h b/libcxx/test/support/nasty_string.h
index ea9d83ccf282aa..e526ccd3365b6f 100644
--- a/libcxx/test/support/nasty_string.h
+++ b/libcxx/test/support/nasty_string.h
@@ -40,8 +40,15 @@
#ifndef TEST_HAS_NO_NASTY_STRING
// Make sure the char-like operations in strings do not depend on the char-like type.
struct nasty_char {
+# if defined(_LIBCPP_VERSION) && !defined(_LIBCPP_ABI_WRAP_ITER_ADL_PROOF)
+ // T, T would win overload resolution when comparing two wrap_iters, so
+ // make sure this is less specific
+ template <typename T, typename U>
+ friend auto operator<=>(T, U) = delete;
+# else
template <typename T>
friend auto operator<=>(T, T) = delete;
+# endif
template <typename T>
friend void operator+(T&&) = delete;
More information about the libcxx-commits
mailing list