From 8e34763532677fccaf6b8e95c6a3615403c5b610 Mon Sep 17 00:00:00 2001 From: Hristo Hristov Date: Fri, 3 Apr 2026 08:43:06 +0300 Subject: [PATCH 01/33] [libc++][ranges] P3059R2: Making user-defined constructors of view iterators/sentinels private Implements https://wg21.link/P3059R2 Closes #189599 --- libcxx/include/__ranges/elements_view.h | 12 ++++++++---- libcxx/include/__ranges/filter_view.h | 20 ++++++++++++------- libcxx/include/__ranges/iota_view.h | 15 ++++++++------ libcxx/include/__ranges/istream_view.h | 8 +++++--- libcxx/include/__ranges/join_view.h | 6 ++++-- libcxx/include/__ranges/lazy_split_view.h | 24 +++++++++++++---------- libcxx/include/__ranges/split_view.h | 18 ++++++++++------- libcxx/include/__ranges/take_view.h | 6 ++++-- libcxx/include/__ranges/take_while_view.h | 8 +++++--- libcxx/include/__ranges/transform_view.h | 14 ++++++++----- 10 files changed, 82 insertions(+), 49 deletions(-) diff --git a/libcxx/include/__ranges/elements_view.h b/libcxx/include/__ranges/elements_view.h index 33c152bbd03b4..706744ae652e1 100644 --- a/libcxx/include/__ranges/elements_view.h +++ b/libcxx/include/__ranges/elements_view.h @@ -165,6 +165,8 @@ template template class elements_view<_View, _Np>::__iterator : public __elements_view_iterator_category_base<__maybe_const<_Const, _View>, _Np> { + friend class elements_view<_View, _Np>; + template friend class __iterator; @@ -175,6 +177,8 @@ class elements_view<_View, _Np>::__iterator iterator_t<_Base> __current_ = iterator_t<_Base>(); + _LIBCPP_HIDE_FROM_ABI constexpr explicit __iterator(iterator_t<_Base> __current) : __current_(std::move(__current)) {} + _LIBCPP_HIDE_FROM_ABI static constexpr decltype(auto) __get_element(const iterator_t<_Base>& __i) { if constexpr (is_reference_v>) { return std::get<_Np>(*__i); @@ -205,8 +209,6 @@ class elements_view<_View, _Np>::__iterator requires default_initializable> = default; - _LIBCPP_HIDE_FROM_ABI constexpr explicit __iterator(iterator_t<_Base> __current) : __current_(std::move(__current)) {} - _LIBCPP_HIDE_FROM_ABI constexpr __iterator(__iterator __i) requires _Const && convertible_to, iterator_t<_Base>> : __current_(std::move(__i.__current_)) {} @@ -339,6 +341,10 @@ class elements_view<_View, _Np>::__sentinel { using _Base _LIBCPP_NODEBUG = __maybe_const<_Const, _View>; _LIBCPP_NO_UNIQUE_ADDRESS sentinel_t<_Base> __end_ = sentinel_t<_Base>(); + _LIBCPP_HIDE_FROM_ABI constexpr explicit __sentinel(sentinel_t<_Base> __end) : __end_(std::move(__end)) {} + + friend class elements_view<_View, _Np>; + template friend class __sentinel; @@ -350,8 +356,6 @@ class elements_view<_View, _Np>::__sentinel { public: _LIBCPP_HIDE_FROM_ABI __sentinel() = default; - _LIBCPP_HIDE_FROM_ABI constexpr explicit __sentinel(sentinel_t<_Base> __end) : __end_(std::move(__end)) {} - _LIBCPP_HIDE_FROM_ABI constexpr __sentinel(__sentinel __other) requires _Const && convertible_to, sentinel_t<_Base>> : __end_(std::move(__other.__end_)) {} diff --git a/libcxx/include/__ranges/filter_view.h b/libcxx/include/__ranges/filter_view.h index 7ec53dac4a84f..3004e830173f1 100644 --- a/libcxx/include/__ranges/filter_view.h +++ b/libcxx/include/__ranges/filter_view.h @@ -127,10 +127,16 @@ struct __filter_iterator_category<_View> { template > _Pred> requires view<_View> && is_object_v<_Pred> class filter_view<_View, _Pred>::__iterator : public __filter_iterator_category<_View> { -public: +private: _LIBCPP_NO_UNIQUE_ADDRESS iterator_t<_View> __current_ = iterator_t<_View>(); _LIBCPP_NO_UNIQUE_ADDRESS filter_view* __parent_ = nullptr; + _LIBCPP_HIDE_FROM_ABI constexpr __iterator(filter_view& __parent, iterator_t<_View> __current) + : __current_(std::move(__current)), __parent_(std::addressof(__parent)) {} + + friend class filter_view<_View, _Pred>; + +public: using iterator_concept = _If, bidirectional_iterator_tag, @@ -145,9 +151,6 @@ class filter_view<_View, _Pred>::__iterator : public __filter_iterator_category< requires default_initializable> = default; - _LIBCPP_HIDE_FROM_ABI constexpr __iterator(filter_view& __parent, iterator_t<_View> __current) - : __current_(std::move(__current)), __parent_(std::addressof(__parent)) {} - [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr iterator_t<_View> const& base() const& noexcept { return __current_; } [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr iterator_t<_View> base() && { return std::move(__current_); } @@ -211,13 +214,16 @@ class filter_view<_View, _Pred>::__iterator : public __filter_iterator_category< template > _Pred> requires view<_View> && is_object_v<_Pred> class filter_view<_View, _Pred>::__sentinel { -public: +private: sentinel_t<_View> __end_ = sentinel_t<_View>(); - _LIBCPP_HIDE_FROM_ABI __sentinel() = default; - _LIBCPP_HIDE_FROM_ABI constexpr explicit __sentinel(filter_view& __parent) : __end_(ranges::end(__parent.__base_)) {} + friend class filter_view<_View, _Pred>; + +public: + _LIBCPP_HIDE_FROM_ABI __sentinel() = default; + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr sentinel_t<_View> base() const { return __end_; } _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(__iterator const& __x, __sentinel const& __y) { diff --git a/libcxx/include/__ranges/iota_view.h b/libcxx/include/__ranges/iota_view.h index 38e0ccaf2849e..9d87138d29e23 100644 --- a/libcxx/include/__ranges/iota_view.h +++ b/libcxx/include/__ranges/iota_view.h @@ -110,6 +110,12 @@ template && copyable<_Start> class iota_view : public view_interface> { struct __iterator : public __iota_iterator_category<_Start> { + private: + _Start __value_ = _Start(); + + _LIBCPP_HIDE_FROM_ABI constexpr explicit __iterator(_Start __value) : __value_(std::move(__value)) {} + + public: friend class iota_view; using iterator_concept = @@ -124,14 +130,10 @@ class iota_view : public view_interface> { using value_type = _Start; using difference_type = _IotaDiffT<_Start>; - _Start __value_ = _Start(); - _LIBCPP_HIDE_FROM_ABI __iterator() requires default_initializable<_Start> = default; - _LIBCPP_HIDE_FROM_ABI constexpr explicit __iterator(_Start __value) : __value_(std::move(__value)) {} - [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Start operator*() const noexcept(is_nothrow_copy_constructible_v<_Start>) { return __value_; @@ -282,11 +284,12 @@ class iota_view : public view_interface> { private: _BoundSentinel __bound_sentinel_ = _BoundSentinel(); - public: - _LIBCPP_HIDE_FROM_ABI __sentinel() = default; _LIBCPP_HIDE_FROM_ABI constexpr explicit __sentinel(_BoundSentinel __bound_sentinel) : __bound_sentinel_(std::move(__bound_sentinel)) {} + public: + _LIBCPP_HIDE_FROM_ABI __sentinel() = default; + _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const __iterator& __x, const __sentinel& __y) { return __x.__value_ == __y.__bound_sentinel_; } diff --git a/libcxx/include/__ranges/istream_view.h b/libcxx/include/__ranges/istream_view.h index 7c64463108e1a..1bee6e69f2186 100644 --- a/libcxx/include/__ranges/istream_view.h +++ b/libcxx/include/__ranges/istream_view.h @@ -66,9 +66,6 @@ class basic_istream_view<_Val, _CharT, _Traits>::__iterator { using difference_type = ptrdiff_t; using value_type = _Val; - _LIBCPP_HIDE_FROM_ABI constexpr explicit __iterator(basic_istream_view<_Val, _CharT, _Traits>& __parent) noexcept - : __parent_(std::addressof(__parent)) {} - __iterator(const __iterator&) = delete; _LIBCPP_HIDE_FROM_ABI __iterator(__iterator&&) = default; @@ -91,9 +88,14 @@ class basic_istream_view<_Val, _CharT, _Traits>::__iterator { private: basic_istream_view<_Val, _CharT, _Traits>* __parent_; + _LIBCPP_HIDE_FROM_ABI constexpr explicit __iterator(basic_istream_view<_Val, _CharT, _Traits>& __parent) noexcept + : __parent_(std::addressof(__parent)) {} + _LIBCPP_HIDE_FROM_ABI constexpr basic_istream<_CharT, _Traits>* __get_parent_stream() const { return __parent_->__stream_; } + + friend class basic_istream_view<_Val, _CharT, _Traits>; }; template diff --git a/libcxx/include/__ranges/join_view.h b/libcxx/include/__ranges/join_view.h index f80b75c839d4a..4f3f8d1c1e5b4 100644 --- a/libcxx/include/__ranges/join_view.h +++ b/libcxx/include/__ranges/join_view.h @@ -160,11 +160,13 @@ struct join_view<_View>::__sentinel { using _Base _LIBCPP_NODEBUG = __maybe_const<_Const, _View>; sentinel_t<_Base> __end_ = sentinel_t<_Base>(); + _LIBCPP_HIDE_FROM_ABI constexpr explicit __sentinel(_Parent& __parent) : __end_(ranges::end(__parent.__base_)) {} + + friend class join_view<_View>; + public: _LIBCPP_HIDE_FROM_ABI __sentinel() = default; - _LIBCPP_HIDE_FROM_ABI constexpr explicit __sentinel(_Parent& __parent) : __end_(ranges::end(__parent.__base_)) {} - _LIBCPP_HIDE_FROM_ABI constexpr __sentinel(__sentinel __s) requires _Const && convertible_to, sentinel_t<_Base>> : __end_(std::move(__s.__end_)) {} diff --git a/libcxx/include/__ranges/lazy_split_view.h b/libcxx/include/__ranges/lazy_split_view.h index be2b86772fa0d..9c44d26faf1e7 100644 --- a/libcxx/include/__ranges/lazy_split_view.h +++ b/libcxx/include/__ranges/lazy_split_view.h @@ -143,6 +143,8 @@ class lazy_split_view : public view_interface> template struct __outer_iterator : __outer_iterator_category<__maybe_const<_Const, _View>> { private: + friend class lazy_split_view<_View, _Pattern>; + template friend struct __inner_iterator; friend __outer_iterator; @@ -155,6 +157,14 @@ class lazy_split_view : public view_interface> _LIBCPP_NO_UNIQUE_ADDRESS _MaybeCurrent __current_ = _MaybeCurrent(); bool __trailing_empty_ = false; + _LIBCPP_HIDE_FROM_ABI constexpr explicit __outer_iterator(_Parent& __parent) + requires(!forward_range<_Base>) + : __parent_(std::addressof(__parent)) {} + + _LIBCPP_HIDE_FROM_ABI constexpr __outer_iterator(_Parent& __parent, iterator_t<_Base> __current) + requires forward_range<_Base> + : __parent_(std::addressof(__parent)), __current_(std::move(__current)) {} + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto& __current() noexcept { if constexpr (forward_range<_View>) { return __current_; @@ -196,14 +206,6 @@ class lazy_split_view : public view_interface> _LIBCPP_HIDE_FROM_ABI __outer_iterator() = default; - _LIBCPP_HIDE_FROM_ABI constexpr explicit __outer_iterator(_Parent& __parent) - requires(!forward_range<_Base>) - : __parent_(std::addressof(__parent)) {} - - _LIBCPP_HIDE_FROM_ABI constexpr __outer_iterator(_Parent& __parent, iterator_t<_Base> __current) - requires forward_range<_Base> - : __parent_(std::addressof(__parent)), __current_(std::move(__current)) {} - _LIBCPP_HIDE_FROM_ABI constexpr __outer_iterator(__outer_iterator __i) requires _Const && convertible_to, iterator_t<_Base>> : __parent_(__i.__parent_), __current_(std::move(__i.__current_)) {} @@ -286,12 +288,16 @@ class lazy_split_view : public view_interface> template struct __inner_iterator : __inner_iterator_category<__maybe_const<_Const, _View>> { private: + friend class lazy_split_view<_View, _Pattern>; + using _Base _LIBCPP_NODEBUG = __maybe_const<_Const, _View>; // Workaround for a GCC issue. static constexpr bool _OuterConst = _Const; __outer_iterator<_Const> __i_ = __outer_iterator<_OuterConst>(); bool __incremented_ = false; + _LIBCPP_HIDE_FROM_ABI constexpr explicit __inner_iterator(__outer_iterator<_Const> __i) : __i_(std::move(__i)) {} + // Note: these private functions are necessary because GCC doesn't allow calls to private members of `__i_` from // free functions that are friends of `inner-iterator`. @@ -342,8 +348,6 @@ class lazy_split_view : public view_interface> _LIBCPP_HIDE_FROM_ABI __inner_iterator() = default; - _LIBCPP_HIDE_FROM_ABI constexpr explicit __inner_iterator(__outer_iterator<_Const> __i) : __i_(std::move(__i)) {} - [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr const iterator_t<_Base>& base() const& noexcept { return __i_.__current(); } diff --git a/libcxx/include/__ranges/split_view.h b/libcxx/include/__ranges/split_view.h index 10148e0e64764..7295e33a282f0 100644 --- a/libcxx/include/__ranges/split_view.h +++ b/libcxx/include/__ranges/split_view.h @@ -127,6 +127,12 @@ struct split_view<_View, _Pattern>::__iterator { _LIBCPP_NO_UNIQUE_ADDRESS subrange> __next_ = subrange>(); bool __trailing_empty_ = false; + _LIBCPP_HIDE_FROM_ABI constexpr __iterator( + split_view<_View, _Pattern>& __parent, iterator_t<_View> __current, subrange> __next) + : __parent_(std::addressof(__parent)), __cur_(std::move(__current)), __next_(std::move(__next)) {} + + friend class split_view<_View, _Pattern>; + friend struct __sentinel; public: @@ -137,10 +143,6 @@ struct split_view<_View, _Pattern>::__iterator { _LIBCPP_HIDE_FROM_ABI __iterator() = default; - _LIBCPP_HIDE_FROM_ABI constexpr __iterator( - split_view<_View, _Pattern>& __parent, iterator_t<_View> __current, subrange> __next) - : __parent_(std::addressof(__parent)), __cur_(std::move(__current)), __next_(std::move(__next)) {} - [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr iterator_t<_View> base() const { return __cur_; } [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr value_type operator*() const { return {__cur_, __next_.begin()}; } @@ -179,16 +181,18 @@ struct split_view<_View, _Pattern>::__sentinel { private: _LIBCPP_NO_UNIQUE_ADDRESS sentinel_t<_View> __end_ = sentinel_t<_View>(); + _LIBCPP_HIDE_FROM_ABI constexpr explicit __sentinel(split_view<_View, _Pattern>& __parent) + : __end_(ranges::end(__parent.__base_)) {} + _LIBCPP_HIDE_FROM_ABI static constexpr bool __equals(const __iterator& __x, const __sentinel& __y) { return __x.__cur_ == __y.__end_ && !__x.__trailing_empty_; } + friend class split_view<_View, _Pattern>; + public: _LIBCPP_HIDE_FROM_ABI __sentinel() = default; - _LIBCPP_HIDE_FROM_ABI constexpr explicit __sentinel(split_view<_View, _Pattern>& __parent) - : __end_(ranges::end(__parent.__base_)) {} - _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const __iterator& __x, const __sentinel& __y) { return __equals(__x, __y); } diff --git a/libcxx/include/__ranges/take_view.h b/libcxx/include/__ranges/take_view.h index 999f686537f2c..ee62d49f71d8b 100644 --- a/libcxx/include/__ranges/take_view.h +++ b/libcxx/include/__ranges/take_view.h @@ -165,14 +165,16 @@ class take_view<_View>::__sentinel { using _Iter _LIBCPP_NODEBUG = counted_iterator>>; _LIBCPP_NO_UNIQUE_ADDRESS sentinel_t<_Base> __end_ = sentinel_t<_Base>(); + _LIBCPP_HIDE_FROM_ABI constexpr explicit __sentinel(sentinel_t<_Base> __end) : __end_(std::move(__end)) {} + + friend class take_view<_View>; + template friend class take_view<_View>::__sentinel; public: _LIBCPP_HIDE_FROM_ABI __sentinel() = default; - _LIBCPP_HIDE_FROM_ABI constexpr explicit __sentinel(sentinel_t<_Base> __end) : __end_(std::move(__end)) {} - _LIBCPP_HIDE_FROM_ABI constexpr __sentinel(__sentinel __s) requires _Const && convertible_to, sentinel_t<_Base>> : __end_(std::move(__s.__end_)) {} diff --git a/libcxx/include/__ranges/take_while_view.h b/libcxx/include/__ranges/take_while_view.h index 0aee306807c8b..e77b79665d1f6 100644 --- a/libcxx/include/__ranges/take_while_view.h +++ b/libcxx/include/__ranges/take_while_view.h @@ -108,14 +108,16 @@ class take_while_view<_View, _Pred>::__sentinel { sentinel_t<_Base> __end_ = sentinel_t<_Base>(); const _Pred* __pred_ = nullptr; + _LIBCPP_HIDE_FROM_ABI constexpr explicit __sentinel(sentinel_t<_Base> __end, const _Pred* __pred) + : __end_(std::move(__end)), __pred_(__pred) {} + + friend class take_while_view<_View, _Pred>; + friend class __sentinel; public: _LIBCPP_HIDE_FROM_ABI __sentinel() = default; - _LIBCPP_HIDE_FROM_ABI constexpr explicit __sentinel(sentinel_t<_Base> __end, const _Pred* __pred) - : __end_(std::move(__end)), __pred_(__pred) {} - _LIBCPP_HIDE_FROM_ABI constexpr __sentinel(__sentinel __s) requires _Const && convertible_to, sentinel_t<_Base>> : __end_(std::move(__s.__end_)), __pred_(__s.__pred_) {} diff --git a/libcxx/include/__ranges/transform_view.h b/libcxx/include/__ranges/transform_view.h index 06ace86bbfafa..807f1cf19a0ac 100644 --- a/libcxx/include/__ranges/transform_view.h +++ b/libcxx/include/__ranges/transform_view.h @@ -192,6 +192,11 @@ class transform_view<_View, _Fn>::__iterator _Parent* __parent_ = nullptr; + _LIBCPP_HIDE_FROM_ABI constexpr __iterator(_Parent& __parent, iterator_t<_Base> __current) + : __parent_(std::addressof(__parent)), __current_(std::move(__current)) {} + + friend class transform_view<_View, _Fn>; + template friend class transform_view<_View, _Fn>::__iterator; @@ -209,9 +214,6 @@ class transform_view<_View, _Fn>::__iterator requires default_initializable> = default; - _LIBCPP_HIDE_FROM_ABI constexpr __iterator(_Parent& __parent, iterator_t<_Base> __current) - : __parent_(std::addressof(__parent)), __current_(std::move(__current)) {} - // Note: `__i` should always be `__iterator`, but directly using // `__iterator` is ill-formed when `_Const` is false // (see http://wg21.link/class.copy.ctor#5). @@ -354,6 +356,10 @@ class transform_view<_View, _Fn>::__sentinel { sentinel_t<_Base> __end_ = sentinel_t<_Base>(); + _LIBCPP_HIDE_FROM_ABI constexpr explicit __sentinel(sentinel_t<_Base> __end) : __end_(__end) {} + + friend class transform_view<_View, _Fn>; + template friend class transform_view<_View, _Fn>::__iterator; @@ -363,8 +369,6 @@ class transform_view<_View, _Fn>::__sentinel { public: _LIBCPP_HIDE_FROM_ABI __sentinel() = default; - _LIBCPP_HIDE_FROM_ABI constexpr explicit __sentinel(sentinel_t<_Base> __end) : __end_(__end) {} - // Note: `__i` should always be `__sentinel`, but directly using // `__sentinel` is ill-formed when `_Const` is false // (see http://wg21.link/class.copy.ctor#5). From e9a32ca543f440348c3b4762ac897f5b30b0e49c Mon Sep 17 00:00:00 2001 From: Hristo Hristov Date: Mon, 6 Apr 2026 00:45:01 +0300 Subject: [PATCH 02/33] Tests: `split_view` --- .../range.split/iterator/base.pass.cpp | 28 +++++++++++++------ .../range.split/iterator/ctor.base.pass.cpp | 4 +-- .../range.split/iterator/deref.pass.cpp | 28 ++++++++++++------- .../range.split/sentinel/ctor.parent.pass.cpp | 5 +--- 4 files changed, 40 insertions(+), 25 deletions(-) diff --git a/libcxx/test/std/ranges/range.adaptors/range.split/iterator/base.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.split/iterator/base.pass.cpp index 325189a0e521e..66c2914ba1919 100644 --- a/libcxx/test/std/ranges/range.adaptors/range.split/iterator/base.pass.cpp +++ b/libcxx/test/std/ranges/range.adaptors/range.split/iterator/base.pass.cpp @@ -16,9 +16,20 @@ #include "../types.h" struct Iter : ForwardIterBase { - int i; + int i = 0; constexpr Iter() = default; constexpr Iter(int ii) : i(ii) {} + constexpr int operator*() const { return i; } + constexpr Iter& operator++() { + ++i; + return *this; + } + constexpr Iter operator++(int) { + Iter tmp = *this; + ++*this; + return tmp; + } + friend constexpr bool operator==(const Iter& x, const Iter& y) { return x.i == y.i; } }; constexpr bool test() { @@ -26,34 +37,33 @@ constexpr bool test() { using SplitView = std::ranges::split_view, std::ranges::subrange>; using SplitIter = std::ranges::iterator_t; + SplitView sv{std::ranges::subrange{Iter{5}, Iter{8}}, + std::ranges::subrange{Iter{8}, Iter{9}}}; + // const & { - SplitView sv; - const SplitIter it{sv, Iter{5}, {}}; + const SplitIter it = sv.begin(); std::same_as decltype(auto) base = it.base(); assert(base.i == 5); } // & { - SplitView sv; - SplitIter it{sv, Iter{5}, {}}; + SplitIter it = sv.begin(); std::same_as decltype(auto) base = it.base(); assert(base.i == 5); } // && { - SplitView sv; - SplitIter it{sv, Iter{5}, {}}; + SplitIter it = sv.begin(); std::same_as decltype(auto) base = std::move(it).base(); assert(base.i == 5); } // const && { - SplitView sv; - const SplitIter it{sv, Iter{5}, {}}; + const SplitIter it = sv.begin(); std::same_as decltype(auto) base = std::move(it).base(); assert(base.i == 5); } diff --git a/libcxx/test/std/ranges/range.adaptors/range.split/iterator/ctor.base.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.split/iterator/ctor.base.pass.cpp index 20b3c19611bd0..823e22e117f77 100644 --- a/libcxx/test/std/ranges/range.adaptors/range.split/iterator/ctor.base.pass.cpp +++ b/libcxx/test/std/ranges/range.adaptors/range.split/iterator/ctor.base.pass.cpp @@ -8,7 +8,7 @@ // UNSUPPORTED: c++03, c++11, c++14, c++17 -// constexpr iterator(split_view& parent, iterator_t current, subrange> next); +// constexpr iterator begin(); #include #include @@ -35,7 +35,7 @@ constexpr bool test() { using SplitIter = std::ranges::iterator_t; SplitView sv{TracedMoveView{}, TracedMoveView{}}; - SplitIter iter = {sv, sv.base().begin(), std::ranges::subrange{sv.base().begin(), sv.base().end()}}; + SplitIter iter = sv.begin(); assert(iter.base().moved); auto subRange = *iter; diff --git a/libcxx/test/std/ranges/range.adaptors/range.split/iterator/deref.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.split/iterator/deref.pass.cpp index 721a1cc0da3d4..be7aca854f640 100644 --- a/libcxx/test/std/ranges/range.adaptors/range.split/iterator/deref.pass.cpp +++ b/libcxx/test/std/ranges/range.adaptors/range.split/iterator/deref.pass.cpp @@ -17,24 +17,32 @@ #include "../types.h" struct Iter : ForwardIterBase { - int i; + int i = 0; constexpr Iter() = default; constexpr Iter(int ii) : i(ii) {} + constexpr int operator*() const { return i; } + constexpr Iter& operator++() { + ++i; + return *this; + } + constexpr Iter operator++(int) { + Iter tmp = *this; + ++*this; + return tmp; + } + friend constexpr bool operator==(const Iter& x, const Iter& y) { return x.i == y.i; } }; constexpr bool test() { using SplitView = std::ranges::split_view, std::ranges::subrange>; using SplitIter = std::ranges::iterator_t; - { - SplitView sv; - Iter current{5}; - std::ranges::subrange next{Iter{6}, Iter{7}}; - const SplitIter it{sv, current, next}; - std::same_as> decltype(auto) value = *it; - assert(value.begin().i == 5); - assert(value.end().i == 6); - } + SplitView sv{std::ranges::subrange{Iter{5}, Iter{8}}, + std::ranges::subrange{Iter{7}, Iter{8}}}; + const SplitIter it = sv.begin(); + std::same_as> decltype(auto) value = *it; + assert(value.begin().i == 5); + assert(value.end().i == 7); return true; } diff --git a/libcxx/test/std/ranges/range.adaptors/range.split/sentinel/ctor.parent.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.split/sentinel/ctor.parent.pass.cpp index c89b1ee2bdfce..6e1ba912a201b 100644 --- a/libcxx/test/std/ranges/range.adaptors/range.split/sentinel/ctor.parent.pass.cpp +++ b/libcxx/test/std/ranges/range.adaptors/range.split/sentinel/ctor.parent.pass.cpp @@ -21,9 +21,6 @@ using Range = std::ranges::subrange>; using SplitView = std::ranges::split_view>; using SplitSent = std::ranges::sentinel_t; -static_assert(std::is_constructible_v); -static_assert(!std::is_convertible_v); - constexpr bool test() { { int buffer[] = {0, 1, 2}; @@ -31,7 +28,7 @@ constexpr bool test() { SplitView sv(input, -1); auto it = sv.begin(); - SplitSent sent(sv); + auto sent = sv.end(); assert(sent != it); ++it; From cf1dc7a44c2467e47cf4edf89e7337d99a4e03b8 Mon Sep 17 00:00:00 2001 From: Hristo Hristov Date: Mon, 6 Apr 2026 00:48:57 +0300 Subject: [PATCH 03/33] Tests: `take_view` --- .../range.take/range.take.sentinel/ctor.pass.cpp | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/libcxx/test/std/ranges/range.adaptors/range.take/range.take.sentinel/ctor.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.take/range.take.sentinel/ctor.pass.cpp index 61d33760c71d7..3710be563c15b 100644 --- a/libcxx/test/std/ranges/range.adaptors/range.take/range.take.sentinel/ctor.pass.cpp +++ b/libcxx/test/std/ranges/range.adaptors/range.take/range.take.sentinel/ctor.pass.cpp @@ -9,7 +9,6 @@ // UNSUPPORTED: c++03, c++11, c++14, c++17 // sentinel() = default; -// constexpr explicit sentinel(sentinel_t end); // constexpr sentinel(sentinel s) // requires Const && convertible_to, sentinel_t>; @@ -49,18 +48,6 @@ constexpr bool test() { assert(std::as_const(tv).begin() + 4 == cs); } - { - // Test the constructor from "base-sentinel" to "sentinel". - using TakeView = std::ranges::take_view; - using Sentinel = std::ranges::sentinel_t; - sentinel_wrapper sw1 = MoveOnlyView(buffer).end(); - static_assert(std::is_constructible_v>); - static_assert(!std::is_convertible_v, Sentinel>); - auto s = Sentinel(sw1); - std::same_as> auto sw2 = s.base(); - assert(base(sw2) == base(sw1)); - } - return true; } From fd1f6eecd0e533fe0bc4de406d7d96ba66b1069d Mon Sep 17 00:00:00 2001 From: Hristo Hristov Date: Thu, 9 Apr 2026 12:41:47 +0300 Subject: [PATCH 04/33] Tests: `take_while_view` --- .../sentinel/ctor.base.pass.cpp | 86 ------------------- .../sentinel/ctor.convert.pass.cpp | 43 +++++++--- 2 files changed, 31 insertions(+), 98 deletions(-) delete mode 100644 libcxx/test/std/ranges/range.adaptors/range.take.while/sentinel/ctor.base.pass.cpp diff --git a/libcxx/test/std/ranges/range.adaptors/range.take.while/sentinel/ctor.base.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.take.while/sentinel/ctor.base.pass.cpp deleted file mode 100644 index b952534d1c966..0000000000000 --- a/libcxx/test/std/ranges/range.adaptors/range.take.while/sentinel/ctor.base.pass.cpp +++ /dev/null @@ -1,86 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// 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 -// -//===----------------------------------------------------------------------===// - -// UNSUPPORTED: c++03, c++11, c++14, c++17 - -// constexpr explicit sentinel(sentinel_t end, const Pred* pred); - -#include -#include -#include - -#include "../types.h" - -struct Sent { - int i; - - friend constexpr bool operator==(int* iter, const Sent& s) { return s.i > *iter; } -}; - -struct Range : std::ranges::view_base { - int* begin() const; - Sent end(); -}; - -struct Pred { - bool operator()(int i) const; -}; - -// Test explicit -template -void conversion_test(T); - -template -concept ImplicitlyConstructible = requires(Args&&... args) { conversion_test({std::forward(args)...}); }; -static_assert(ImplicitlyConstructible); - -static_assert(std::is_constructible_v>, - std::ranges::sentinel_t, - const Pred*>); -static_assert(!ImplicitlyConstructible>, - std::ranges::sentinel_t, - const Pred*>); - -constexpr bool test() { - // base is init correctly - { - using R = std::ranges::take_while_view; - using Sentinel = std::ranges::sentinel_t; - - Sentinel s1(Sent{5}, nullptr); - assert(s1.base().i == 5); - } - - // pred is init correctly - { - bool called = false; - auto pred = [&](int) { - called = true; - return false; - }; - - using R = std::ranges::take_while_view; - using Sentinel = std::ranges::sentinel_t; - - int i = 10; - int* iter = &i; - Sentinel s(Sent{0}, &pred); - - bool b = iter == s; - assert(called); - assert(b); - } - return true; -} - -int main(int, char**) { - test(); - static_assert(test()); - - return 0; -} diff --git a/libcxx/test/std/ranges/range.adaptors/range.take.while/sentinel/ctor.convert.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.take.while/sentinel/ctor.convert.pass.cpp index 865a3d45710fb..0fffe9b508816 100644 --- a/libcxx/test/std/ranges/range.adaptors/range.take.while/sentinel/ctor.convert.pass.cpp +++ b/libcxx/test/std/ranges/range.adaptors/range.take.while/sentinel/ctor.convert.pass.cpp @@ -70,34 +70,48 @@ static_assert(!std::is_constructible_v< constexpr bool test() { // base is init correctly { - using R = std::ranges::take_while_view; + struct TestRng : std::ranges::view_base { + constexpr int* begin() const { return nullptr; } + constexpr Sent end() { return Sent{5}; } + constexpr ConstSent end() const { return ConstSent{5}; } + }; + + using R = std::ranges::take_while_view; using Sentinel = std::ranges::sentinel_t; using ConstSentinel = std::ranges::sentinel_t; static_assert(!std::same_as); - Sentinel s1(Sent{5}, nullptr); + R r{TestRng{}, nullptr}; + Sentinel s1 = r.end(); ConstSentinel s2 = s1; assert(s2.base().i == 5); } // pred is init correctly { + struct TestRng : std::ranges::view_base { + constexpr int* begin() const { return nullptr; } + constexpr Sent end() { return Sent{0}; } + constexpr ConstSent end() const { return ConstSent{0}; } + }; + bool called = false; auto pred = [&](int) { called = true; return false; }; - using R = std::ranges::take_while_view; + using R = std::ranges::take_while_view; using Sentinel = std::ranges::sentinel_t; using ConstSentinel = std::ranges::sentinel_t; static_assert(!std::same_as); - int i = 10; - int* iter = &i; - Sentinel s1(Sent{0}, &pred); + R r{TestRng{}, pred}; + Sentinel s1 = r.end(); ConstSentinel s2 = s1; + int i = 10; + int* iter = &i; [[maybe_unused]] bool b = iter == s2; assert(called); } @@ -111,20 +125,25 @@ constexpr bool test() { constexpr bool operator==(int* iter) const { return i > *iter; } }; + struct TestPred { + constexpr bool operator()(int) const { return false; } + }; + struct Rng : std::ranges::view_base { - int* begin() const; - Sent end(); - MoveOnlyConvert end() const; + constexpr int* begin() const { return nullptr; } + constexpr Sent end() { return Sent{0}; } + constexpr MoveOnlyConvert end() const { return MoveOnlyConvert(Sent{0}); } }; - using R = std::ranges::take_while_view; + using R = std::ranges::take_while_view; using Sentinel = std::ranges::sentinel_t; using ConstSentinel = std::ranges::sentinel_t; static_assert(!std::same_as); - Sentinel s1(Sent{5}, nullptr); + R r{Rng{}, TestPred{}}; + Sentinel s1 = r.end(); ConstSentinel s2 = s1; - assert(s2.base().i == 5); + assert(s2.base().i == 0); } return true; From 666c86a6f1434c01236881ad7323fc3ba58b4724 Mon Sep 17 00:00:00 2001 From: Hristo Hristov Date: Thu, 9 Apr 2026 12:58:00 +0300 Subject: [PATCH 05/33] Tests: `filter_view` --- .../range.filter/iterator/arrow.pass.cpp | 3 +- .../range.filter/iterator/base.pass.cpp | 4 +- .../iterator/ctor.parent_iter.pass.cpp | 51 ---------------- .../range.filter/iterator/deref.pass.cpp | 3 +- .../sentinel/ctor.parent.pass.cpp | 60 ------------------- 5 files changed, 6 insertions(+), 115 deletions(-) delete mode 100644 libcxx/test/std/ranges/range.adaptors/range.filter/iterator/ctor.parent_iter.pass.cpp delete mode 100644 libcxx/test/std/ranges/range.adaptors/range.filter/sentinel/ctor.parent.pass.cpp diff --git a/libcxx/test/std/ranges/range.adaptors/range.filter/iterator/arrow.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.filter/iterator/arrow.pass.cpp index 8a12b1694ca2f..46d59c3de1d7d 100644 --- a/libcxx/test/std/ranges/range.adaptors/range.filter/iterator/arrow.pass.cpp +++ b/libcxx/test/std/ranges/range.adaptors/range.filter/iterator/arrow.pass.cpp @@ -87,7 +87,8 @@ constexpr void test() { for (std::ptrdiff_t n = 0; n != 5; ++n) { FilterView view = make_filter_view(array.data(), array.data() + array.size(), AlwaysTrue{}); - FilterIterator const iter(view, Iter(array.data() + n)); + FilterIterator iter = view.begin(); + for (std::ptrdiff_t i = 0; i < n; ++i) ++iter; std::same_as decltype(auto) result = iter.operator->(); assert(base(result) == array.data() + n); assert(iter->x == n); diff --git a/libcxx/test/std/ranges/range.adaptors/range.filter/iterator/base.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.filter/iterator/base.pass.cpp index 813cd892c64e6..9f193ddbc1a2d 100644 --- a/libcxx/test/std/ranges/range.adaptors/range.filter/iterator/base.pass.cpp +++ b/libcxx/test/std/ranges/range.adaptors/range.filter/iterator/base.pass.cpp @@ -37,7 +37,7 @@ constexpr void test() { // Test the const& version { - FilterIterator const iter(view, Iter(array.data())); + FilterIterator const iter = view.begin(); Iter const& result = iter.base(); ASSERT_SAME_TYPE(Iter const&, decltype(iter.base())); ASSERT_NOEXCEPT(iter.base()); @@ -46,7 +46,7 @@ constexpr void test() { // Test the && version { - FilterIterator iter(view, Iter(array.data())); + FilterIterator iter = view.begin(); Iter result = std::move(iter).base(); ASSERT_SAME_TYPE(Iter, decltype(std::move(iter).base())); assert(base(result) == array.data()); diff --git a/libcxx/test/std/ranges/range.adaptors/range.filter/iterator/ctor.parent_iter.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.filter/iterator/ctor.parent_iter.pass.cpp deleted file mode 100644 index 761ef2d8ee493..0000000000000 --- a/libcxx/test/std/ranges/range.adaptors/range.filter/iterator/ctor.parent_iter.pass.cpp +++ /dev/null @@ -1,51 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// 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 -// -//===----------------------------------------------------------------------===// - -// UNSUPPORTED: c++03, c++11, c++14, c++17 - -// constexpr std::ranges::filter_view::(filter_view&, iterator_t); - -#include - -#include -#include -#include -#include "test_iterators.h" -#include "../types.h" - -template > -constexpr void test() { - using View = minimal_view; - using FilterView = std::ranges::filter_view; - using FilterIterator = std::ranges::iterator_t; - - std::array array{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; - View view(Iter(array.data()), Sent(Iter(array.data() + array.size()))); - Iter iter = view.begin(); - - FilterView filter_view(std::move(view), AlwaysTrue{}); - FilterIterator filter_iter(filter_view, std::move(iter)); - assert(base(filter_iter.base()) == array.data()); -} - -constexpr bool tests() { - test>(); - test>(); - test>(); - test>(); - test>(); - test>(); - test(); - return true; -} - -int main(int, char**) { - tests(); - static_assert(tests()); - return 0; -} diff --git a/libcxx/test/std/ranges/range.adaptors/range.filter/iterator/deref.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.filter/iterator/deref.pass.cpp index f4f4982bb9d5d..e794ff133dcb0 100644 --- a/libcxx/test/std/ranges/range.adaptors/range.filter/iterator/deref.pass.cpp +++ b/libcxx/test/std/ranges/range.adaptors/range.filter/iterator/deref.pass.cpp @@ -36,7 +36,8 @@ constexpr void test() { FilterView view = make_filter_view(array.data(), array.data() + array.size(), AlwaysTrue{}); for (std::size_t n = 0; n != array.size(); ++n) { - FilterIterator const iter(view, Iter(array.data() + n)); + FilterIterator iter = view.begin(); + for (std::size_t i = 0; i < n; ++i) ++iter; ValueType& result = *iter; ASSERT_SAME_TYPE(ValueType&, decltype(*iter)); assert(&result == array.data() + n); diff --git a/libcxx/test/std/ranges/range.adaptors/range.filter/sentinel/ctor.parent.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.filter/sentinel/ctor.parent.pass.cpp deleted file mode 100644 index 9896bf80c31e1..0000000000000 --- a/libcxx/test/std/ranges/range.adaptors/range.filter/sentinel/ctor.parent.pass.cpp +++ /dev/null @@ -1,60 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// 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 -// -//===----------------------------------------------------------------------===// - -// UNSUPPORTED: c++03, c++11, c++14, c++17 - -// constexpr explicit sentinel(filter_view&); - -#include - -#include -#include -#include -#include -#include "test_iterators.h" -#include "../types.h" - -template > -constexpr void test() { - using View = minimal_view; - using FilterView = std::ranges::filter_view; - using FilterSentinel = std::ranges::sentinel_t; - - auto make_filter_view = [](auto begin, auto end, auto pred) { - View view{Iter(begin), Sent(Iter(end))}; - return FilterView(std::move(view), pred); - }; - - std::array array{0, 1, 2, 3, 4}; - FilterView view = make_filter_view(array.data(), array.data() + array.size(), AlwaysTrue{}); - - FilterSentinel sent(view); - assert(base(base(sent.base())) == base(base(view.end().base()))); - - static_assert(!std::is_constructible_v); - static_assert(!std::is_constructible_v); - static_assert( std::is_constructible_v && - !std::is_convertible_v); -} - -constexpr bool tests() { - test>(); - test>(); - test>(); - test>(); - test>(); - test>(); - test(); - return true; -} - -int main(int, char**) { - tests(); - static_assert(tests()); - return 0; -} From cd91923f83df438089785c565a885ccceadcb009 Mon Sep 17 00:00:00 2001 From: Hristo Hristov Date: Thu, 9 Apr 2026 13:10:28 +0300 Subject: [PATCH 06/33] Tests: `lazy_split_view` --- .../ctor.outer_iterator.pass.cpp | 43 ------------------- .../ctor.parent.pass.cpp | 39 ----------------- .../ctor.parent_base.pass.cpp | 36 ---------------- 3 files changed, 118 deletions(-) delete mode 100644 libcxx/test/std/ranges/range.adaptors/range.lazy.split/range.lazy.split.inner/ctor.outer_iterator.pass.cpp delete mode 100644 libcxx/test/std/ranges/range.adaptors/range.lazy.split/range.lazy.split.outer/ctor.parent.pass.cpp delete mode 100644 libcxx/test/std/ranges/range.adaptors/range.lazy.split/range.lazy.split.outer/ctor.parent_base.pass.cpp diff --git a/libcxx/test/std/ranges/range.adaptors/range.lazy.split/range.lazy.split.inner/ctor.outer_iterator.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.lazy.split/range.lazy.split.inner/ctor.outer_iterator.pass.cpp deleted file mode 100644 index 4981510be52d6..0000000000000 --- a/libcxx/test/std/ranges/range.adaptors/range.lazy.split/range.lazy.split.inner/ctor.outer_iterator.pass.cpp +++ /dev/null @@ -1,43 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// 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 -// -//===----------------------------------------------------------------------===// - -// UNSUPPORTED: c++03, c++11, c++14, c++17 - -// constexpr explicit inner-iterator::inner-iterator(outer-iterator i); - -#include - -#include "../types.h" - -static_assert(!std::is_constructible_v); - -template -constexpr void test_impl() { - [[maybe_unused]] Inner i(Outer{}); - // Verify that the constructor is `explicit`. - static_assert(!std::is_convertible_v); -} - -constexpr bool test() { - test_impl(); - test_impl(); -// Is only constructible if both the outer and the inner iterators have the same constness. - test_impl(); -// Note: this works because of an implicit conversion (`OuterIterNonConst` is converted to `OuterIterConst`). - test_impl(); - test_impl(); - - return true; -} - -int main(int, char**) { - test(); - static_assert(test()); - - return 0; -} diff --git a/libcxx/test/std/ranges/range.adaptors/range.lazy.split/range.lazy.split.outer/ctor.parent.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.lazy.split/range.lazy.split.outer/ctor.parent.pass.cpp deleted file mode 100644 index aacf6eabc290a..0000000000000 --- a/libcxx/test/std/ranges/range.adaptors/range.lazy.split/range.lazy.split.outer/ctor.parent.pass.cpp +++ /dev/null @@ -1,39 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// 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 -// -//===----------------------------------------------------------------------===// - -// UNSUPPORTED: c++03, c++11, c++14, c++17 - -// explicit std::ranges::lazy_split_view::outer-iterator::outer-iterator(Parent& parent) -// requires (!forward_range) - -#include - -#include -#include -#include "../types.h" - -// Verify that the constructor is `explicit`. -static_assert(!std::is_convertible_v); - -static_assert( std::ranges::forward_range); -static_assert(!std::is_constructible_v); - -constexpr bool test() { - InputView input; - SplitViewInput v(input, ForwardTinyView()); - [[maybe_unused]] OuterIterInput i(v); - - return true; -} - -int main(int, char**) { - test(); - static_assert(test()); - - return 0; -} diff --git a/libcxx/test/std/ranges/range.adaptors/range.lazy.split/range.lazy.split.outer/ctor.parent_base.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.lazy.split/range.lazy.split.outer/ctor.parent_base.pass.cpp deleted file mode 100644 index 9fc0ce3748b1f..0000000000000 --- a/libcxx/test/std/ranges/range.adaptors/range.lazy.split/range.lazy.split.outer/ctor.parent_base.pass.cpp +++ /dev/null @@ -1,36 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// 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 -// -//===----------------------------------------------------------------------===// - -// UNSUPPORTED: c++03, c++11, c++14, c++17 - -// constexpr outer-iterator(Parent& parent, iterator_t current); -// requires forward_range - -#include - -#include -#include -#include "../types.h" - -static_assert(!std::ranges::forward_range); -static_assert(!std::is_constructible_v>); - -constexpr bool test() { - ForwardView input("abc"); - SplitViewForward v(std::move(input), " "); - [[maybe_unused]] OuterIterForward i(v, input.begin()); - - return true; -} - -int main(int, char**) { - test(); - static_assert(test()); - - return 0; -} From 4581bdcbc92289da03e06c9b610cf3d1dbf02a30 Mon Sep 17 00:00:00 2001 From: Hristo Hristov Date: Thu, 9 Apr 2026 13:15:21 +0300 Subject: [PATCH 07/33] Tests: `join_view` --- .../range.join.sentinel/ctor.parent.pass.cpp | 43 ------------------- 1 file changed, 43 deletions(-) delete mode 100644 libcxx/test/std/ranges/range.adaptors/range.join/range.join.sentinel/ctor.parent.pass.cpp diff --git a/libcxx/test/std/ranges/range.adaptors/range.join/range.join.sentinel/ctor.parent.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.join/range.join.sentinel/ctor.parent.pass.cpp deleted file mode 100644 index 1ac68277338fe..0000000000000 --- a/libcxx/test/std/ranges/range.adaptors/range.join/range.join.sentinel/ctor.parent.pass.cpp +++ /dev/null @@ -1,43 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// 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 -// -//===----------------------------------------------------------------------===// - -// UNSUPPORTED: c++03, c++11, c++14, c++17 - -// constexpr explicit sentinel(Parent& parent); - -#include -#include - -#include "test_macros.h" -#include "../types.h" - -constexpr bool test() { - int buffer[4][4] = {{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}, {13, 14, 15, 16}}; - - CopyableChild children[4] = {CopyableChild(buffer[0]), CopyableChild(buffer[1]), CopyableChild(buffer[2]), CopyableChild(buffer[3])}; - CopyableParent parent{children}; - std::ranges::join_view jv(parent); - std::ranges::sentinel_t sent(jv); - assert(sent == std::ranges::next(jv.begin(), 16)); - - return true; -} - -int main(int, char**) { - test(); - static_assert(test()); - - { - // Test explicitness. - using Parent = std::ranges::join_view>; - static_assert( std::is_constructible_v, Parent&>); - static_assert(!std::is_convertible_v, Parent&>); - } - - return 0; -} From f6daa20e4a60aa451efc3cd8e55a9a9d06e07e14 Mon Sep 17 00:00:00 2001 From: Hristo Hristov Date: Thu, 9 Apr 2026 13:47:11 +0300 Subject: [PATCH 08/33] Tests: `istream_view` --- .../range.istream.view/ctor.pass.cpp | 5 +- .../range.istream.view/iterator/ctor.pass.cpp | 58 ------------------- .../iterator/deref.pass.cpp | 10 ---- 3 files changed, 2 insertions(+), 71 deletions(-) delete mode 100644 libcxx/test/std/ranges/range.factories/range.istream.view/iterator/ctor.pass.cpp diff --git a/libcxx/test/std/ranges/range.factories/range.istream.view/ctor.pass.cpp b/libcxx/test/std/ranges/range.factories/range.istream.view/ctor.pass.cpp index ff60fbff1d73b..beeeea4c1bbe1 100644 --- a/libcxx/test/std/ranges/range.factories/range.istream.view/ctor.pass.cpp +++ b/libcxx/test/std/ranges/range.factories/range.istream.view/ctor.pass.cpp @@ -39,10 +39,9 @@ void test() { // LWG 3568. basic_istream_view needs to initialize value_ { - auto iss = make_string_stream("123"); + auto iss = make_string_stream(""); std::ranges::basic_istream_view isv{iss}; - using Iter = std::ranges::iterator_t; - Iter iter{isv}; + auto iter = isv.begin(); assert(*iter == 0); } } diff --git a/libcxx/test/std/ranges/range.factories/range.istream.view/iterator/ctor.pass.cpp b/libcxx/test/std/ranges/range.factories/range.istream.view/iterator/ctor.pass.cpp deleted file mode 100644 index e180d12924084..0000000000000 --- a/libcxx/test/std/ranges/range.factories/range.istream.view/iterator/ctor.pass.cpp +++ /dev/null @@ -1,58 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// 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 -// -//===----------------------------------------------------------------------===// - -// UNSUPPORTED: no-localization -// UNSUPPORTED: c++03, c++11, c++14, c++17 - -// constexpr explicit iterator(basic_istream_view& parent) noexcept; - -#include -#include -#include -#include - -#include "test_macros.h" -#include "../utils.h" - -// test that the constructor is explicit -template -using IstreamView = std::ranges::basic_istream_view; -template -using Iter = std::ranges::iterator_t>; - -static_assert(std::constructible_from, IstreamView&>); -static_assert(!std::convertible_to&, Iter>); - -#ifndef TEST_HAS_NO_WIDE_CHARACTERS -static_assert(std::constructible_from, IstreamView&>); -static_assert(!std::convertible_to&, Iter>); -#endif - -// test that the constructor is noexcept -static_assert(std::is_nothrow_constructible_v, IstreamView&>); -#ifndef TEST_HAS_NO_WIDE_CHARACTERS -static_assert(std::is_nothrow_constructible_v, IstreamView&>); -#endif - -template -void test() { - auto iss = make_string_stream("123"); - std::ranges::basic_istream_view isv{iss}; - Iter it{isv}; - ++it; - assert(*it == 123); -} - -int main(int, char**) { - test(); -#ifndef TEST_HAS_NO_WIDE_CHARACTERS - test(); -#endif - - return 0; -} diff --git a/libcxx/test/std/ranges/range.factories/range.istream.view/iterator/deref.pass.cpp b/libcxx/test/std/ranges/range.factories/range.istream.view/iterator/deref.pass.cpp index 1cf05f0ac4cbe..d010ee06dbf51 100644 --- a/libcxx/test/std/ranges/range.factories/range.istream.view/iterator/deref.pass.cpp +++ b/libcxx/test/std/ranges/range.factories/range.istream.view/iterator/deref.pass.cpp @@ -29,16 +29,6 @@ void test() { assert(v1 == 1); } - // operator* should return the same reference to the value stored in the view - { - auto iss = make_string_stream("1 2 345 "); - std::ranges::basic_istream_view isv{iss}; - using Iter = std::ranges::iterator_t; - - Iter it1{isv}; - Iter it2{isv}; - assert(&*it1 == &*it2); - } } int main(int, char**) { From 4186467d445d24aa850297f23455f8da2edd183d Mon Sep 17 00:00:00 2001 From: Hristo Hristov Date: Thu, 9 Apr 2026 14:00:32 +0300 Subject: [PATCH 09/33] Tests: `iota_view` --- .../iterator/ctor.value.pass.cpp | 45 ------------------ .../sentinel/ctor.value.pass.cpp | 47 ------------------- 2 files changed, 92 deletions(-) delete mode 100644 libcxx/test/std/ranges/range.factories/range.iota.view/iterator/ctor.value.pass.cpp delete mode 100644 libcxx/test/std/ranges/range.factories/range.iota.view/sentinel/ctor.value.pass.cpp diff --git a/libcxx/test/std/ranges/range.factories/range.iota.view/iterator/ctor.value.pass.cpp b/libcxx/test/std/ranges/range.factories/range.iota.view/iterator/ctor.value.pass.cpp deleted file mode 100644 index a84cb91f7e9b3..0000000000000 --- a/libcxx/test/std/ranges/range.factories/range.iota.view/iterator/ctor.value.pass.cpp +++ /dev/null @@ -1,45 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// 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 -// -//===----------------------------------------------------------------------===// - -// UNSUPPORTED: c++03, c++11, c++14, c++17 - -// constexpr explicit iterator(W value); - -#include -#include -#include - -#include "test_macros.h" -#include "../types.h" - -constexpr bool test() { - { - using Iter = std::ranges::iterator_t>; - auto iter = Iter(42); - assert(*iter == 42); - } - { - using Iter = std::ranges::iterator_t>; - auto iter = Iter(SomeInt(42)); - assert(*iter == SomeInt(42)); - } - { - using Iter = std::ranges::iterator_t>; - static_assert(!std::is_convertible_v); - static_assert( std::is_constructible_v); - } - - return true; -} - -int main(int, char**) { - test(); - static_assert(test()); - - return 0; -} diff --git a/libcxx/test/std/ranges/range.factories/range.iota.view/sentinel/ctor.value.pass.cpp b/libcxx/test/std/ranges/range.factories/range.iota.view/sentinel/ctor.value.pass.cpp deleted file mode 100644 index a56369b046dc1..0000000000000 --- a/libcxx/test/std/ranges/range.factories/range.iota.view/sentinel/ctor.value.pass.cpp +++ /dev/null @@ -1,47 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// 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 -// -//===----------------------------------------------------------------------===// - -// UNSUPPORTED: c++03, c++11, c++14, c++17 - -// constexpr explicit sentinel(Bound bound); - -#include -#include -#include - -#include "test_macros.h" -#include "../types.h" - -constexpr bool test() { - { - using Sent = std::ranges::sentinel_t>>; - using Iter = std::ranges::iterator_t>>; - auto sent = Sent(IntSentinelWith(42)); - assert(sent == Iter(42)); - } - { - using Sent = std::ranges::sentinel_t>>; - using Iter = std::ranges::iterator_t>>; - auto sent = Sent(IntSentinelWith(SomeInt(42))); - assert(sent == Iter(SomeInt(42))); - } - { - using Sent = std::ranges::sentinel_t>>; - static_assert(!std::is_convertible_v>); - static_assert( std::is_constructible_v>); - } - - return true; -} - -int main(int, char**) { - test(); - static_assert(test()); - - return 0; -} From 9ea8e2c13b655cfb75ffccdf9b21399f7a637ae8 Mon Sep 17 00:00:00 2001 From: Hristo Hristov Date: Sat, 11 Apr 2026 14:45:00 +0300 Subject: [PATCH 10/33] Tests: `elements_view` --- .../range.elements/iterator/base.pass.cpp | 12 +++-- .../iterator/ctor.base.pass.cpp | 54 ------------------- .../iterator/ctor.other.pass.cpp | 8 +-- .../range.elements/sentinel/base.pass.cpp | 7 +-- .../sentinel/ctor.base.pass.cpp | 52 ------------------ .../sentinel/ctor.convert.pass.cpp | 9 ++-- 6 files changed, 20 insertions(+), 122 deletions(-) delete mode 100644 libcxx/test/std/ranges/range.adaptors/range.elements/iterator/ctor.base.pass.cpp delete mode 100644 libcxx/test/std/ranges/range.adaptors/range.elements/sentinel/ctor.base.pass.cpp diff --git a/libcxx/test/std/ranges/range.adaptors/range.elements/iterator/base.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.elements/iterator/base.pass.cpp index a77e98f845a06..425c13fea707e 100644 --- a/libcxx/test/std/ranges/range.adaptors/range.elements/iterator/base.pass.cpp +++ b/libcxx/test/std/ranges/range.adaptors/range.elements/iterator/base.pass.cpp @@ -39,7 +39,7 @@ constexpr bool test() { // const & { - const ElementsIter it{&t}; + const ElementsIter it = std::ranges::elements_view{BaseView{&t, &t + 1}}.begin(); decltype(auto) base = it.base(); static_assert(std::is_same_v* const&>); assert(base == &t); @@ -47,7 +47,7 @@ constexpr bool test() { // & { - ElementsIter it{&t}; + ElementsIter it = std::ranges::elements_view{BaseView{&t, &t + 1}}.begin(); decltype(auto) base = it.base(); static_assert(std::is_same_v* const&>); assert(base == &t); @@ -55,7 +55,7 @@ constexpr bool test() { // && { - ElementsIter it{&t}; + ElementsIter it = std::ranges::elements_view{BaseView{&t, &t + 1}}.begin(); decltype(auto) base = std::move(it).base(); static_assert(std::is_same_v*>); assert(base == &t); @@ -63,7 +63,7 @@ constexpr bool test() { // const && { - const ElementsIter it{&t}; + const ElementsIter it = std::ranges::elements_view{BaseView{&t, &t + 1}}.begin(); decltype(auto) base = std::move(it).base(); static_assert(std::is_same_v* const&>); assert(base == &t); @@ -81,7 +81,9 @@ constexpr bool test() { using MoveOnlyElemIter = std::ranges::iterator_t, 0>>; - MoveOnlyElemIter it{MoveOnlyIter{{}, MoveOnly{5}}}; + auto it = std::ranges::elements_view, 0>{ + std::ranges::subrange{MoveOnlyIter{{}, MoveOnly{5}}, Sent{}}} + .begin(); decltype(auto) base = std::move(it).base(); static_assert(std::is_same_v); assert(base.mo.get() == 5); diff --git a/libcxx/test/std/ranges/range.adaptors/range.elements/iterator/ctor.base.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.elements/iterator/ctor.base.pass.cpp deleted file mode 100644 index 5a280d294aecc..0000000000000 --- a/libcxx/test/std/ranges/range.adaptors/range.elements/iterator/ctor.base.pass.cpp +++ /dev/null @@ -1,54 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// 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 -// -//===----------------------------------------------------------------------===// - -// UNSUPPORTED: c++03, c++11, c++14, c++17 - -// constexpr explicit iterator(iterator_t current); - -#include -#include -#include - -#include "../types.h" - -// Test explicit -using BaseIter = std::tuple*; -using ElementsIter = std::ranges::iterator_t, 0>>; - -static_assert(std::is_constructible_v); -static_assert(!std::is_convertible_v); - -struct TracedMoveIter : IterBase{ - bool moved = false; - - constexpr TracedMoveIter() = default; - constexpr TracedMoveIter(const TracedMoveIter&) = default; - constexpr TracedMoveIter(TracedMoveIter&&) : moved{true} {} - constexpr TracedMoveIter& operator=(TracedMoveIter&&) = default; - constexpr TracedMoveIter& operator=(const TracedMoveIter&) = default; -}; - -struct TracedMoveView : std::ranges::view_base { - TracedMoveIter begin() const; - TracedMoveIter end() const; -}; - -constexpr bool test() { - using Iter = std::ranges::iterator_t>; - Iter iter{TracedMoveIter{}}; - assert(iter.base().moved); - - return true; -} - -int main(int, char**) { - test(); - static_assert(test()); - - return 0; -} diff --git a/libcxx/test/std/ranges/range.adaptors/range.elements/iterator/ctor.other.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.elements/iterator/ctor.other.pass.cpp index 4c94cd5edf62e..d1b8ea73d635d 100644 --- a/libcxx/test/std/ranges/range.adaptors/range.elements/iterator/ctor.other.pass.cpp +++ b/libcxx/test/std/ranges/range.adaptors/range.elements/iterator/ctor.other.pass.cpp @@ -57,10 +57,10 @@ static_assert(!std::is_constructible_v, ElemIt static_assert(!std::is_constructible_v, ConstElemIter>); constexpr bool test() { - ElemIter iter{ConvertibleIter{5}}; - ConstElemIter constIter = iter; // implicit - assert(constIter.base().movedFromOtherConst); - assert(constIter.base().i == 5); + // auto iter = std::ranges::elements_view{}.begin(); + // ConstElemIter constIter = iter; // implicit + // assert(constIter.base().movedFromOtherConst); + // assert(constIter.base().i == 5); return true; } diff --git a/libcxx/test/std/ranges/range.adaptors/range.elements/sentinel/base.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.elements/sentinel/base.pass.cpp index d4d0156fdb5be..a11d16817f030 100644 --- a/libcxx/test/std/ranges/range.adaptors/range.elements/sentinel/base.pass.cpp +++ b/libcxx/test/std/ranges/range.adaptors/range.elements/sentinel/base.pass.cpp @@ -17,7 +17,7 @@ #include struct Sent { - int i; + int i = 5; friend constexpr bool operator==(std::tuple*, const Sent&) { return true; } }; @@ -27,7 +27,8 @@ constexpr bool test() { using EleRange = std::ranges::elements_view; using EleSent = std::ranges::sentinel_t; - const EleSent st{Sent{5}}; + const EleRange ev; + const EleSent st = ev.end(); std::same_as decltype(auto) base = st.base(); assert(base.i == 5); @@ -36,6 +37,6 @@ constexpr bool test() { int main(int, char**) { test(); - static_assert(test()); + // static_assert(test()); return 0; } diff --git a/libcxx/test/std/ranges/range.adaptors/range.elements/sentinel/ctor.base.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.elements/sentinel/ctor.base.pass.cpp deleted file mode 100644 index 13fef1d53f121..0000000000000 --- a/libcxx/test/std/ranges/range.adaptors/range.elements/sentinel/ctor.base.pass.cpp +++ /dev/null @@ -1,52 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// 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 -// -//===----------------------------------------------------------------------===// - -// UNSUPPORTED: c++03, c++11, c++14, c++17 - -// constexpr explicit sentinel(sentinel_t end); - -#include -#include -#include -#include - -struct Sent { - int i; - - friend constexpr bool operator==(std::tuple*, const Sent&) { return true; } -}; - -struct Range : std::ranges::view_base { - std::tuple* begin() const; - Sent end(); -}; - -// Test explicit - -static_assert(std::is_constructible_v>, Sent>); -static_assert(!std::is_convertible_v>>); - -constexpr bool test() { - // base is init correctly - { - using R = std::ranges::elements_view; - using Sentinel = std::ranges::sentinel_t; - - Sentinel s1(Sent{5}); - assert(s1.base().i == 5); - } - - return true; -} - -int main(int, char**) { - test(); - static_assert(test()); - - return 0; -} diff --git a/libcxx/test/std/ranges/range.adaptors/range.elements/sentinel/ctor.convert.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.elements/sentinel/ctor.convert.pass.cpp index a8bc817ced291..ce81d1c00d376 100644 --- a/libcxx/test/std/ranges/range.adaptors/range.elements/sentinel/ctor.convert.pass.cpp +++ b/libcxx/test/std/ranges/range.adaptors/range.elements/sentinel/ctor.convert.pass.cpp @@ -72,9 +72,10 @@ constexpr bool test() { using ConstSentinel = std::ranges::sentinel_t; static_assert(!std::same_as); - Sentinel s1(Sent{5}); - ConstSentinel s2 = s1; - assert(s2.base().i == 5); + // auto s1 = R{}.end(); + // (void) s1; + // ConstSentinel s2 = s1; + // assert(s2.base().i == 5); } return true; @@ -82,7 +83,7 @@ constexpr bool test() { int main(int, char**) { test(); - static_assert(test()); + // static_assert(test()); return 0; } From c54da865e30c41abd243a9981c47de912ca2d5e4 Mon Sep 17 00:00:00 2001 From: Hristo Hristov Date: Fri, 24 Apr 2026 07:04:24 +0300 Subject: [PATCH 11/33] Format --- libcxx/docs/Status/Cxx26Papers.csv | 2 +- .../range.elements/iterator/base.pass.cpp | 15 ++++++++------- .../range.elements/sentinel/base.pass.cpp | 2 +- .../range.split/iterator/base.pass.cpp | 10 +++++----- .../range.split/iterator/deref.pass.cpp | 7 +++---- .../sentinel/ctor.convert.pass.cpp | 4 ++-- 6 files changed, 20 insertions(+), 20 deletions(-) diff --git a/libcxx/docs/Status/Cxx26Papers.csv b/libcxx/docs/Status/Cxx26Papers.csv index 855ac2533a282..37d1ccac120b5 100644 --- a/libcxx/docs/Status/Cxx26Papers.csv +++ b/libcxx/docs/Status/Cxx26Papers.csv @@ -188,7 +188,7 @@ "`P4140R0 `__","Proposed resolution for US70-126: allow incomplete types in type_order","2026-03 (Croydon)","","","`#189595 `__","" "`P3373R4 `__","Of Operation States and Their Lifetimes","2026-03 (Croydon)","","","`#189597 `__","" "`P3986R1 `__","A Wording Strategy for Inlinable Receivers","2026-03 (Croydon)","","","`#189598 `__","" -"`P3059R2 `__","Making user-defined constructors of view iterators/sentinels private","2026-03 (Croydon)","","","`#189599 `__","" +"`P3059R2 `__","Making user-defined constructors of view iterators/sentinels private","2026-03 (Croydon)","|Complete|","23","`#189599 `__","" "`P3725R3 `__","Filter View Extensions for Safer Use, Rev 3","2026-03 (Croydon)","","","`#189601 `__","" "`P3828R1 `__","Rename the to_input view to as_input","2026-03 (Croydon)","","","`#189602 `__","" "`P3795R2 `__","Miscellaneous Reflection Cleanup","2026-03 (Croydon)","","","`#189603 `__","" diff --git a/libcxx/test/std/ranges/range.adaptors/range.elements/iterator/base.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.elements/iterator/base.pass.cpp index 425c13fea707e..316e3523edc73 100644 --- a/libcxx/test/std/ranges/range.adaptors/range.elements/iterator/base.pass.cpp +++ b/libcxx/test/std/ranges/range.adaptors/range.elements/iterator/base.pass.cpp @@ -40,14 +40,14 @@ constexpr bool test() { // const & { const ElementsIter it = std::ranges::elements_view{BaseView{&t, &t + 1}}.begin(); - decltype(auto) base = it.base(); + decltype(auto) base = it.base(); static_assert(std::is_same_v* const&>); assert(base == &t); } // & { - ElementsIter it = std::ranges::elements_view{BaseView{&t, &t + 1}}.begin(); + ElementsIter it = std::ranges::elements_view{BaseView{&t, &t + 1}}.begin(); decltype(auto) base = it.base(); static_assert(std::is_same_v* const&>); assert(base == &t); @@ -55,7 +55,7 @@ constexpr bool test() { // && { - ElementsIter it = std::ranges::elements_view{BaseView{&t, &t + 1}}.begin(); + ElementsIter it = std::ranges::elements_view{BaseView{&t, &t + 1}}.begin(); decltype(auto) base = std::move(it).base(); static_assert(std::is_same_v*>); assert(base == &t); @@ -64,7 +64,7 @@ constexpr bool test() { // const && { const ElementsIter it = std::ranges::elements_view{BaseView{&t, &t + 1}}.begin(); - decltype(auto) base = std::move(it).base(); + decltype(auto) base = std::move(it).base(); static_assert(std::is_same_v* const&>); assert(base == &t); } @@ -81,9 +81,10 @@ constexpr bool test() { using MoveOnlyElemIter = std::ranges::iterator_t, 0>>; - auto it = std::ranges::elements_view, 0>{ - std::ranges::subrange{MoveOnlyIter{{}, MoveOnly{5}}, Sent{}}} - .begin(); + auto it = + std::ranges::elements_view, 0>{ + std::ranges::subrange{MoveOnlyIter{{}, MoveOnly{5}}, Sent{}}} + .begin(); decltype(auto) base = std::move(it).base(); static_assert(std::is_same_v); assert(base.mo.get() == 5); diff --git a/libcxx/test/std/ranges/range.adaptors/range.elements/sentinel/base.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.elements/sentinel/base.pass.cpp index a11d16817f030..885582a5c94a8 100644 --- a/libcxx/test/std/ranges/range.adaptors/range.elements/sentinel/base.pass.cpp +++ b/libcxx/test/std/ranges/range.adaptors/range.elements/sentinel/base.pass.cpp @@ -28,7 +28,7 @@ constexpr bool test() { using EleSent = std::ranges::sentinel_t; const EleRange ev; - const EleSent st = ev.end(); + const EleSent st = ev.end(); std::same_as decltype(auto) base = st.base(); assert(base.i == 5); diff --git a/libcxx/test/std/ranges/range.adaptors/range.split/iterator/base.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.split/iterator/base.pass.cpp index 66c2914ba1919..fe9be0e97104c 100644 --- a/libcxx/test/std/ranges/range.adaptors/range.split/iterator/base.pass.cpp +++ b/libcxx/test/std/ranges/range.adaptors/range.split/iterator/base.pass.cpp @@ -16,7 +16,7 @@ #include "../types.h" struct Iter : ForwardIterBase { - int i = 0; + int i = 0; constexpr Iter() = default; constexpr Iter(int ii) : i(ii) {} constexpr int operator*() const { return i; } @@ -42,28 +42,28 @@ constexpr bool test() { // const & { - const SplitIter it = sv.begin(); + const SplitIter it = sv.begin(); std::same_as decltype(auto) base = it.base(); assert(base.i == 5); } // & { - SplitIter it = sv.begin(); + SplitIter it = sv.begin(); std::same_as decltype(auto) base = it.base(); assert(base.i == 5); } // && { - SplitIter it = sv.begin(); + SplitIter it = sv.begin(); std::same_as decltype(auto) base = std::move(it).base(); assert(base.i == 5); } // const && { - const SplitIter it = sv.begin(); + const SplitIter it = sv.begin(); std::same_as decltype(auto) base = std::move(it).base(); assert(base.i == 5); } diff --git a/libcxx/test/std/ranges/range.adaptors/range.split/iterator/deref.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.split/iterator/deref.pass.cpp index be7aca854f640..0e9812020fb38 100644 --- a/libcxx/test/std/ranges/range.adaptors/range.split/iterator/deref.pass.cpp +++ b/libcxx/test/std/ranges/range.adaptors/range.split/iterator/deref.pass.cpp @@ -17,7 +17,7 @@ #include "../types.h" struct Iter : ForwardIterBase { - int i = 0; + int i = 0; constexpr Iter() = default; constexpr Iter(int ii) : i(ii) {} constexpr int operator*() const { return i; } @@ -37,9 +37,8 @@ constexpr bool test() { using SplitView = std::ranges::split_view, std::ranges::subrange>; using SplitIter = std::ranges::iterator_t; - SplitView sv{std::ranges::subrange{Iter{5}, Iter{8}}, - std::ranges::subrange{Iter{7}, Iter{8}}}; - const SplitIter it = sv.begin(); + SplitView sv{std::ranges::subrange{Iter{5}, Iter{8}}, std::ranges::subrange{Iter{7}, Iter{8}}}; + const SplitIter it = sv.begin(); std::same_as> decltype(auto) value = *it; assert(value.begin().i == 5); assert(value.end().i == 7); diff --git a/libcxx/test/std/ranges/range.adaptors/range.take.while/sentinel/ctor.convert.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.take.while/sentinel/ctor.convert.pass.cpp index 0fffe9b508816..8a9ee79660a1d 100644 --- a/libcxx/test/std/ranges/range.adaptors/range.take.while/sentinel/ctor.convert.pass.cpp +++ b/libcxx/test/std/ranges/range.adaptors/range.take.while/sentinel/ctor.convert.pass.cpp @@ -107,7 +107,7 @@ constexpr bool test() { static_assert(!std::same_as); R r{TestRng{}, pred}; - Sentinel s1 = r.end(); + Sentinel s1 = r.end(); ConstSentinel s2 = s1; int i = 10; @@ -141,7 +141,7 @@ constexpr bool test() { static_assert(!std::same_as); R r{Rng{}, TestPred{}}; - Sentinel s1 = r.end(); + Sentinel s1 = r.end(); ConstSentinel s2 = s1; assert(s2.base().i == 0); } From 428278a83bfea43d58cfd3972755e6172e3d05cb Mon Sep 17 00:00:00 2001 From: Hristo Hristov Date: Fri, 17 Jul 2026 21:28:20 +0300 Subject: [PATCH 12/33] Release notes --- libcxx/docs/ReleaseNotes/24.rst | 1 + libcxx/docs/Status/Cxx26Papers.csv | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/libcxx/docs/ReleaseNotes/24.rst b/libcxx/docs/ReleaseNotes/24.rst index d71a24c66b0c4..6c0b837074ea2 100644 --- a/libcxx/docs/ReleaseNotes/24.rst +++ b/libcxx/docs/ReleaseNotes/24.rst @@ -39,6 +39,7 @@ Implemented Papers ------------------ - P0493R5: Atomic minimum/maximum (`Github `__) +- P3059R2: Making user-defined constructors of view iterators/sentinels private (`Github `__) - P0792R14: ``function_ref`` : a type-erased callable reference (`Github `__) - P3948R1: ``constant_wrapper`` is the only tool needed for passing constant expressions via function arguments (`Github `__) - P3961R1: Less double indirection in ``function_ref`` (RU-220) (`Github `__) diff --git a/libcxx/docs/Status/Cxx26Papers.csv b/libcxx/docs/Status/Cxx26Papers.csv index 37d1ccac120b5..1832ec915a06a 100644 --- a/libcxx/docs/Status/Cxx26Papers.csv +++ b/libcxx/docs/Status/Cxx26Papers.csv @@ -188,7 +188,7 @@ "`P4140R0 `__","Proposed resolution for US70-126: allow incomplete types in type_order","2026-03 (Croydon)","","","`#189595 `__","" "`P3373R4 `__","Of Operation States and Their Lifetimes","2026-03 (Croydon)","","","`#189597 `__","" "`P3986R1 `__","A Wording Strategy for Inlinable Receivers","2026-03 (Croydon)","","","`#189598 `__","" -"`P3059R2 `__","Making user-defined constructors of view iterators/sentinels private","2026-03 (Croydon)","|Complete|","23","`#189599 `__","" +"`P3059R2 `__","Making user-defined constructors of view iterators/sentinels private","2026-03 (Croydon)","|Complete|","24","`#189599 `__","" "`P3725R3 `__","Filter View Extensions for Safer Use, Rev 3","2026-03 (Croydon)","","","`#189601 `__","" "`P3828R1 `__","Rename the to_input view to as_input","2026-03 (Croydon)","","","`#189602 `__","" "`P3795R2 `__","Miscellaneous Reflection Cleanup","2026-03 (Croydon)","","","`#189603 `__","" From f80bcca134ed7799658a0fbe3660be9a449d8b12 Mon Sep 17 00:00:00 2001 From: Hristo Hristov Date: Fri, 17 Jul 2026 21:42:44 +0300 Subject: [PATCH 13/33] Format --- .../range.adaptors/range.filter/iterator/arrow.pass.cpp | 3 ++- .../range.adaptors/range.filter/iterator/deref.pass.cpp | 3 ++- .../range.adaptors/range.split/iterator/base.pass.cpp | 3 +-- .../range.take.while/sentinel/ctor.convert.pass.cpp | 6 +++--- .../range.istream.view/iterator/deref.pass.cpp | 1 - 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/libcxx/test/std/ranges/range.adaptors/range.filter/iterator/arrow.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.filter/iterator/arrow.pass.cpp index 46d59c3de1d7d..284a22d218bf0 100644 --- a/libcxx/test/std/ranges/range.adaptors/range.filter/iterator/arrow.pass.cpp +++ b/libcxx/test/std/ranges/range.adaptors/range.filter/iterator/arrow.pass.cpp @@ -88,7 +88,8 @@ constexpr void test() { for (std::ptrdiff_t n = 0; n != 5; ++n) { FilterView view = make_filter_view(array.data(), array.data() + array.size(), AlwaysTrue{}); FilterIterator iter = view.begin(); - for (std::ptrdiff_t i = 0; i < n; ++i) ++iter; + for (std::ptrdiff_t i = 0; i < n; ++i) + ++iter; std::same_as decltype(auto) result = iter.operator->(); assert(base(result) == array.data() + n); assert(iter->x == n); diff --git a/libcxx/test/std/ranges/range.adaptors/range.filter/iterator/deref.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.filter/iterator/deref.pass.cpp index e794ff133dcb0..42b0f1816d8a1 100644 --- a/libcxx/test/std/ranges/range.adaptors/range.filter/iterator/deref.pass.cpp +++ b/libcxx/test/std/ranges/range.adaptors/range.filter/iterator/deref.pass.cpp @@ -37,7 +37,8 @@ constexpr void test() { for (std::size_t n = 0; n != array.size(); ++n) { FilterIterator iter = view.begin(); - for (std::size_t i = 0; i < n; ++i) ++iter; + for (std::size_t i = 0; i < n; ++i) + ++iter; ValueType& result = *iter; ASSERT_SAME_TYPE(ValueType&, decltype(*iter)); assert(&result == array.data() + n); diff --git a/libcxx/test/std/ranges/range.adaptors/range.split/iterator/base.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.split/iterator/base.pass.cpp index fe9be0e97104c..8e8eff8a12b97 100644 --- a/libcxx/test/std/ranges/range.adaptors/range.split/iterator/base.pass.cpp +++ b/libcxx/test/std/ranges/range.adaptors/range.split/iterator/base.pass.cpp @@ -37,8 +37,7 @@ constexpr bool test() { using SplitView = std::ranges::split_view, std::ranges::subrange>; using SplitIter = std::ranges::iterator_t; - SplitView sv{std::ranges::subrange{Iter{5}, Iter{8}}, - std::ranges::subrange{Iter{8}, Iter{9}}}; + SplitView sv{std::ranges::subrange{Iter{5}, Iter{8}}, std::ranges::subrange{Iter{8}, Iter{9}}}; // const & { diff --git a/libcxx/test/std/ranges/range.adaptors/range.take.while/sentinel/ctor.convert.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.take.while/sentinel/ctor.convert.pass.cpp index 8a9ee79660a1d..1808545422498 100644 --- a/libcxx/test/std/ranges/range.adaptors/range.take.while/sentinel/ctor.convert.pass.cpp +++ b/libcxx/test/std/ranges/range.adaptors/range.take.while/sentinel/ctor.convert.pass.cpp @@ -82,7 +82,7 @@ constexpr bool test() { static_assert(!std::same_as); R r{TestRng{}, nullptr}; - Sentinel s1 = r.end(); + Sentinel s1 = r.end(); ConstSentinel s2 = s1; assert(s2.base().i == 5); } @@ -110,8 +110,8 @@ constexpr bool test() { Sentinel s1 = r.end(); ConstSentinel s2 = s1; - int i = 10; - int* iter = &i; + int i = 10; + int* iter = &i; [[maybe_unused]] bool b = iter == s2; assert(called); } diff --git a/libcxx/test/std/ranges/range.factories/range.istream.view/iterator/deref.pass.cpp b/libcxx/test/std/ranges/range.factories/range.istream.view/iterator/deref.pass.cpp index d010ee06dbf51..9f9f13399392c 100644 --- a/libcxx/test/std/ranges/range.factories/range.istream.view/iterator/deref.pass.cpp +++ b/libcxx/test/std/ranges/range.factories/range.istream.view/iterator/deref.pass.cpp @@ -28,7 +28,6 @@ void test() { std::same_as decltype(auto) v1 = *it; assert(v1 == 1); } - } int main(int, char**) { From 6da2fb0b7280f746a762bbace63d5657f5db5063 Mon Sep 17 00:00:00 2001 From: Hristo Hristov Date: Mon, 20 Jul 2026 14:02:29 +0300 Subject: [PATCH 14/33] Tests: `elements_view` updates --- .../iterator/ctor.other.pass.cpp | 16 ++++++++++++---- .../sentinel/ctor.convert.pass.cpp | 18 ++++++++++++------ 2 files changed, 24 insertions(+), 10 deletions(-) diff --git a/libcxx/test/std/ranges/range.adaptors/range.elements/iterator/ctor.other.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.elements/iterator/ctor.other.pass.cpp index d1b8ea73d635d..9255fb47013b6 100644 --- a/libcxx/test/std/ranges/range.adaptors/range.elements/iterator/ctor.other.pass.cpp +++ b/libcxx/test/std/ranges/range.adaptors/range.elements/iterator/ctor.other.pass.cpp @@ -57,10 +57,18 @@ static_assert(!std::is_constructible_v, ElemIt static_assert(!std::is_constructible_v, ConstElemIter>); constexpr bool test() { - // auto iter = std::ranges::elements_view{}.begin(); - // ConstElemIter constIter = iter; // implicit - // assert(constIter.base().movedFromOtherConst); - // assert(constIter.base().i == 5); + struct TestRange : std::ranges::view_base { + constexpr ConvertibleIter begin() { return ConvertibleIter{5}; } + constexpr ConvertibleIter end() { return ConvertibleIter{5}; } + constexpr ConvertibleIter begin() const { return ConvertibleIter{5}; } + constexpr ConvertibleIter end() const { return ConvertibleIter{5}; } + }; + + std::ranges::elements_view ev{TestRange{}}; + ElemIter iter = ev.begin(); + ConstElemIter constIter = iter; // implicit + assert(constIter.base().movedFromOtherConst); + assert(constIter.base().i == 5); return true; } diff --git a/libcxx/test/std/ranges/range.adaptors/range.elements/sentinel/ctor.convert.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.elements/sentinel/ctor.convert.pass.cpp index ce81d1c00d376..25d1413b2fa16 100644 --- a/libcxx/test/std/ranges/range.adaptors/range.elements/sentinel/ctor.convert.pass.cpp +++ b/libcxx/test/std/ranges/range.adaptors/range.elements/sentinel/ctor.convert.pass.cpp @@ -67,15 +67,21 @@ static_assert( constexpr bool test() { // base is init correctly { - using R = std::ranges::elements_view; + struct TestRange : std::ranges::view_base { + constexpr std::tuple* begin() const { return nullptr; } + constexpr Sent end() { return Sent{5}; } + constexpr ConstSent end() const { return ConstSent{5}; } + }; + + using R = std::ranges::elements_view; using Sentinel = std::ranges::sentinel_t; using ConstSentinel = std::ranges::sentinel_t; static_assert(!std::same_as); - // auto s1 = R{}.end(); - // (void) s1; - // ConstSentinel s2 = s1; - // assert(s2.base().i == 5); + R r{TestRange{}}; + Sentinel s1 = r.end(); + ConstSentinel s2 = s1; + assert(s2.base().i == 5); } return true; @@ -83,7 +89,7 @@ constexpr bool test() { int main(int, char**) { test(); - // static_assert(test()); + static_assert(test()); return 0; } From 2522cc12d3eeca523787c71f8ccc95037f12e298 Mon Sep 17 00:00:00 2001 From: Hristo Hristov Date: Mon, 20 Jul 2026 14:03:34 +0300 Subject: [PATCH 15/33] Revert formatting --- .../range.adaptors/range.elements/iterator/base.pass.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libcxx/test/std/ranges/range.adaptors/range.elements/iterator/base.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.elements/iterator/base.pass.cpp index 316e3523edc73..27801eadac30f 100644 --- a/libcxx/test/std/ranges/range.adaptors/range.elements/iterator/base.pass.cpp +++ b/libcxx/test/std/ranges/range.adaptors/range.elements/iterator/base.pass.cpp @@ -22,7 +22,8 @@ // Test Noexcept template -concept IsBaseNoexcept = requires { +concept IsBaseNoexcept = + requires { { std::declval().base() } noexcept; }; From 94e99c057095d591bb4a6c60dfc7cde0957ca9bf Mon Sep 17 00:00:00 2001 From: Hristo Hristov Date: Mon, 20 Jul 2026 15:24:00 +0300 Subject: [PATCH 16/33] Apply suggestion from @frederick-vs-ja Co-authored-by: A. Jiang --- .../range.adaptors/range.elements/iterator/base.pass.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/libcxx/test/std/ranges/range.adaptors/range.elements/iterator/base.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.elements/iterator/base.pass.cpp index 27801eadac30f..e28c36b1254af 100644 --- a/libcxx/test/std/ranges/range.adaptors/range.elements/iterator/base.pass.cpp +++ b/libcxx/test/std/ranges/range.adaptors/range.elements/iterator/base.pass.cpp @@ -79,9 +79,6 @@ constexpr bool test() { constexpr bool operator==(const MoveOnlyIter&) const { return true; } }; - using MoveOnlyElemIter = - std::ranges::iterator_t, 0>>; - auto it = std::ranges::elements_view, 0>{ std::ranges::subrange{MoveOnlyIter{{}, MoveOnly{5}}, Sent{}}} From b0958e777847f7933b0a06b1b54ad118e2b240d2 Mon Sep 17 00:00:00 2001 From: Hristo Hristov Date: Tue, 21 Jul 2026 00:05:55 +0300 Subject: [PATCH 17/33] Fixed formatting --- .../range.adaptors/range.elements/iterator/base.pass.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/libcxx/test/std/ranges/range.adaptors/range.elements/iterator/base.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.elements/iterator/base.pass.cpp index e28c36b1254af..bcce8e1f48f7b 100644 --- a/libcxx/test/std/ranges/range.adaptors/range.elements/iterator/base.pass.cpp +++ b/libcxx/test/std/ranges/range.adaptors/range.elements/iterator/base.pass.cpp @@ -22,8 +22,7 @@ // Test Noexcept template -concept IsBaseNoexcept = - requires { +concept IsBaseNoexcept = requires { { std::declval().base() } noexcept; }; From 656265dd5e184b971ae7dd28dba070f534bd50e0 Mon Sep 17 00:00:00 2001 From: Hristo Hristov Date: Tue, 21 Jul 2026 00:18:55 +0300 Subject: [PATCH 18/33] Enable test --- .../ranges/range.adaptors/range.elements/sentinel/base.pass.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libcxx/test/std/ranges/range.adaptors/range.elements/sentinel/base.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.elements/sentinel/base.pass.cpp index 885582a5c94a8..114b7fc1f1b71 100644 --- a/libcxx/test/std/ranges/range.adaptors/range.elements/sentinel/base.pass.cpp +++ b/libcxx/test/std/ranges/range.adaptors/range.elements/sentinel/base.pass.cpp @@ -37,6 +37,6 @@ constexpr bool test() { int main(int, char**) { test(); - // static_assert(test()); + static_assert(test()); return 0; } From 792757cd769e39b149be5bb42ac4568b578794c0 Mon Sep 17 00:00:00 2001 From: Hristo Hristov Date: Tue, 21 Jul 2026 07:53:40 +0300 Subject: [PATCH 19/33] Added `std::is_constructible/convertible` tests --- .../iterator/ctor.base.compile.pass.cpp | 23 ++++++++++++ .../sentinel/ctor.base.compile.pass.cpp | 30 ++++++++++++++++ .../ctor.parent.iter.compile.pass.cpp | 25 +++++++++++++ .../sentinel/ctor.parent.compile.pass.cpp | 25 +++++++++++++ .../ctor.outer_iterator.compile.pass.cpp | 23 ++++++++++++ .../ctor.parent.base.compile.pass.cpp | 22 ++++++++++++ .../ctor.parent.compile.pass.cpp | 23 ++++++++++++ .../sentinel/ctor.base.pred.compile.pass.cpp | 35 +++++++++++++++++++ .../iterator/ctor.value.compile.pass.cpp | 26 ++++++++++++++ .../sentinel/ctor.value.compile.pass.cpp | 24 +++++++++++++ .../iterator/ctor.parent.compile.pass.cpp | 33 +++++++++++++++++ 11 files changed, 289 insertions(+) create mode 100644 libcxx/test/std/ranges/range.adaptors/range.elements/iterator/ctor.base.compile.pass.cpp create mode 100644 libcxx/test/std/ranges/range.adaptors/range.elements/sentinel/ctor.base.compile.pass.cpp create mode 100644 libcxx/test/std/ranges/range.adaptors/range.filter/iterator/ctor.parent.iter.compile.pass.cpp create mode 100644 libcxx/test/std/ranges/range.adaptors/range.filter/sentinel/ctor.parent.compile.pass.cpp create mode 100644 libcxx/test/std/ranges/range.adaptors/range.lazy.split/range.lazy.split.inner/ctor.outer_iterator.compile.pass.cpp create mode 100644 libcxx/test/std/ranges/range.adaptors/range.lazy.split/range.lazy.split.outer/ctor.parent.base.compile.pass.cpp create mode 100644 libcxx/test/std/ranges/range.adaptors/range.lazy.split/range.lazy.split.outer/ctor.parent.compile.pass.cpp create mode 100644 libcxx/test/std/ranges/range.adaptors/range.take.while/sentinel/ctor.base.pred.compile.pass.cpp create mode 100644 libcxx/test/std/ranges/range.factories/range.iota.view/iterator/ctor.value.compile.pass.cpp create mode 100644 libcxx/test/std/ranges/range.factories/range.iota.view/sentinel/ctor.value.compile.pass.cpp create mode 100644 libcxx/test/std/ranges/range.factories/range.istream.view/iterator/ctor.parent.compile.pass.cpp diff --git a/libcxx/test/std/ranges/range.adaptors/range.elements/iterator/ctor.base.compile.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.elements/iterator/ctor.base.compile.pass.cpp new file mode 100644 index 0000000000000..b43a60276e280 --- /dev/null +++ b/libcxx/test/std/ranges/range.adaptors/range.elements/iterator/ctor.base.compile.pass.cpp @@ -0,0 +1,23 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// REQUIRES: std-at-least-c++20 + +// constexpr explicit iterator(iterator_t current); + +// The constructor is now `private` (exposition-only) per P3059R2. + +#include +#include +#include + +using BaseIter = std::tuple*; +using ElementsIter = std::ranges::iterator_t, 0>>; + +static_assert(!std::is_constructible_v); +static_assert(!std::is_convertible_v); diff --git a/libcxx/test/std/ranges/range.adaptors/range.elements/sentinel/ctor.base.compile.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.elements/sentinel/ctor.base.compile.pass.cpp new file mode 100644 index 0000000000000..ee4a297c1f4a9 --- /dev/null +++ b/libcxx/test/std/ranges/range.adaptors/range.elements/sentinel/ctor.base.compile.pass.cpp @@ -0,0 +1,30 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// REQUIRES: std-at-least-c++20 + +// constexpr explicit sentinel(sentinel_t end); + +// The constructor is now `private` (exposition-only) per P3059R2. + +#include +#include + +struct Sent { + int i; + + friend constexpr bool operator==(std::tuple*, const Sent&) { return true; } +}; + +struct Range : std::ranges::view_base { + std::tuple* begin() const; + Sent end(); +}; + +static_assert(!std::is_constructible_v>, Sent>); +static_assert(!std::is_convertible_v>>); diff --git a/libcxx/test/std/ranges/range.adaptors/range.filter/iterator/ctor.parent.iter.compile.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.filter/iterator/ctor.parent.iter.compile.pass.cpp new file mode 100644 index 0000000000000..4a013d0072222 --- /dev/null +++ b/libcxx/test/std/ranges/range.adaptors/range.filter/iterator/ctor.parent.iter.compile.pass.cpp @@ -0,0 +1,25 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// REQUIRES: std-at-least-c++20 + +// constexpr std::ranges::filter_view::(filter_view&, iterator_t); + +// The constructor is now `private` (exposition-only) per P3059R2. + +#include + +#include "test_iterators.h" +#include "../types.h" + +using View = minimal_view>; +using FilterView = std::ranges::filter_view; +using FilterIterator = std::ranges::iterator_t; + +static_assert(!std::constructible_from); +static_assert(!std::convertible_to); diff --git a/libcxx/test/std/ranges/range.adaptors/range.filter/sentinel/ctor.parent.compile.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.filter/sentinel/ctor.parent.compile.pass.cpp new file mode 100644 index 0000000000000..06e06aeb6db6e --- /dev/null +++ b/libcxx/test/std/ranges/range.adaptors/range.filter/sentinel/ctor.parent.compile.pass.cpp @@ -0,0 +1,25 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// REQUIRES: std-at-least-c++20 + +// constexpr explicit sentinel(filter_view&); + +// The constructor is now `private` (exposition-only) per P3059R2. + +#include + +#include "test_iterators.h" +#include "../types.h" + +using View = minimal_view>; +using FilterView = std::ranges::filter_view; +using FilterSentinel = std::ranges::sentinel_t; + +static_assert(!std::constructible_from); +static_assert(!std::convertible_to); diff --git a/libcxx/test/std/ranges/range.adaptors/range.lazy.split/range.lazy.split.inner/ctor.outer_iterator.compile.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.lazy.split/range.lazy.split.inner/ctor.outer_iterator.compile.pass.cpp new file mode 100644 index 0000000000000..37fe2fadfd41a --- /dev/null +++ b/libcxx/test/std/ranges/range.adaptors/range.lazy.split/range.lazy.split.inner/ctor.outer_iterator.compile.pass.cpp @@ -0,0 +1,23 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// REQUIRES: std-at-least-c++20 + +// constexpr explicit inner-iterator::inner-iterator(outer-iterator i); + +// The constructor is now `private` (exposition-only) per P3059R2. + +#include + +#include "../types.h" + +static_assert(!std::is_constructible_v); +static_assert(!std::is_convertible_v); + +static_assert(!std::is_constructible_v); +static_assert(!std::is_convertible_v); diff --git a/libcxx/test/std/ranges/range.adaptors/range.lazy.split/range.lazy.split.outer/ctor.parent.base.compile.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.lazy.split/range.lazy.split.outer/ctor.parent.base.compile.pass.cpp new file mode 100644 index 0000000000000..70e97ea04f5c0 --- /dev/null +++ b/libcxx/test/std/ranges/range.adaptors/range.lazy.split/range.lazy.split.outer/ctor.parent.base.compile.pass.cpp @@ -0,0 +1,22 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// REQUIRES: std-at-least-c++20 + +// constexpr outer-iterator(Parent& parent, iterator_t current); +// requires forward_range + +// The constructor is now `private` (exposition-only) per P3059R2. + +#include +#include + +#include "../types.h" + +static_assert(std::ranges::forward_range); +static_assert(!std::is_constructible_v>); diff --git a/libcxx/test/std/ranges/range.adaptors/range.lazy.split/range.lazy.split.outer/ctor.parent.compile.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.lazy.split/range.lazy.split.outer/ctor.parent.compile.pass.cpp new file mode 100644 index 0000000000000..b838970718c8a --- /dev/null +++ b/libcxx/test/std/ranges/range.adaptors/range.lazy.split/range.lazy.split.outer/ctor.parent.compile.pass.cpp @@ -0,0 +1,23 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// REQUIRES: std-at-least-c++20 + +// explicit std::ranges::lazy_split_view::outer-iterator::outer-iterator(Parent& parent) +// requires (!forward_range) + +// The constructor is now `private` (exposition-only) per P3059R2. + +#include +#include + +#include "../types.h" + +static_assert(!std::ranges::forward_range); +static_assert(!std::is_constructible_v); +static_assert(!std::is_convertible_v); diff --git a/libcxx/test/std/ranges/range.adaptors/range.take.while/sentinel/ctor.base.pred.compile.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.take.while/sentinel/ctor.base.pred.compile.pass.cpp new file mode 100644 index 0000000000000..a66e3d1e84c6e --- /dev/null +++ b/libcxx/test/std/ranges/range.adaptors/range.take.while/sentinel/ctor.base.pred.compile.pass.cpp @@ -0,0 +1,35 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// REQUIRES: std-at-least-c++20 + +// constexpr explicit sentinel(sentinel_t end, const Pred* pred); + +// The constructor is now `private` (exposition-only) per P3059R2. + +#include +#include + +struct Sent { + int i; + + friend constexpr bool operator==(int* iter, const Sent& s) { return s.i > *iter; } +}; + +struct Range : std::ranges::view_base { + int* begin() const; + Sent end(); +}; + +struct Pred { + bool operator()(int i) const; +}; + +using Sentinel = std::ranges::sentinel_t>; + +static_assert(!std::is_constructible_v, const Pred*>); diff --git a/libcxx/test/std/ranges/range.factories/range.iota.view/iterator/ctor.value.compile.pass.cpp b/libcxx/test/std/ranges/range.factories/range.iota.view/iterator/ctor.value.compile.pass.cpp new file mode 100644 index 0000000000000..e95042e26e146 --- /dev/null +++ b/libcxx/test/std/ranges/range.factories/range.iota.view/iterator/ctor.value.compile.pass.cpp @@ -0,0 +1,26 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// REQUIRES: std-at-least-c++20 + +// constexpr explicit iterator(W value); + +// The constructor is now `private` (exposition-only) per P3059R2. + +#include +#include + +#include "test_macros.h" + +#include "../types.h" + +static_assert(!std::is_constructible_v>, int>); + +using Iter = std::ranges::iterator_t>; +static_assert(!std::is_constructible_v); +static_assert(!std::is_convertible_v); diff --git a/libcxx/test/std/ranges/range.factories/range.iota.view/sentinel/ctor.value.compile.pass.cpp b/libcxx/test/std/ranges/range.factories/range.iota.view/sentinel/ctor.value.compile.pass.cpp new file mode 100644 index 0000000000000..a39efb4318794 --- /dev/null +++ b/libcxx/test/std/ranges/range.factories/range.iota.view/sentinel/ctor.value.compile.pass.cpp @@ -0,0 +1,24 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// REQUIRES: std-at-least-c++20 + +// constexpr explicit sentinel(Bound bound); + +// The constructor is now `private` (exposition-only) per P3059R2. + +#include +#include + +#include "test_macros.h" + +#include "../types.h" + +using Sent = std::ranges::sentinel_t>>; +static_assert(!std::is_constructible_v>); +static_assert(!std::is_convertible_v, Sent>); diff --git a/libcxx/test/std/ranges/range.factories/range.istream.view/iterator/ctor.parent.compile.pass.cpp b/libcxx/test/std/ranges/range.factories/range.istream.view/iterator/ctor.parent.compile.pass.cpp new file mode 100644 index 0000000000000..171e2dce1e5f0 --- /dev/null +++ b/libcxx/test/std/ranges/range.factories/range.istream.view/iterator/ctor.parent.compile.pass.cpp @@ -0,0 +1,33 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// REQUIRES: std-at-least-c++20 + +// constexpr explicit iterator(basic_istream_view& parent) noexcept; + +// The constructor is now `private` (exposition-only) per P3059R2. + +#include +#include +#include + +#include "test_macros.h" + +// test that the constructor is explicit +template +using IstreamView = std::ranges::basic_istream_view; +template +using Iter = std::ranges::iterator_t>; + +static_assert(!std::constructible_from, IstreamView&>); +static_assert(!std::convertible_to&, Iter>); + +#ifndef TEST_HAS_NO_WIDE_CHARACTERS +static_assert(!std::constructible_from, IstreamView&>); +static_assert(!std::convertible_to&, Iter>); +#endif From 21cafc7d5982e774ce751e244ccfb8c85c259fca Mon Sep 17 00:00:00 2001 From: Hristo Hristov Date: Wed, 22 Jul 2026 09:20:54 +0300 Subject: [PATCH 20/33] Cleanup --- .../range.iota.view/iterator/ctor.value.compile.pass.cpp | 2 -- .../range.iota.view/sentinel/ctor.value.compile.pass.cpp | 2 -- 2 files changed, 4 deletions(-) diff --git a/libcxx/test/std/ranges/range.factories/range.iota.view/iterator/ctor.value.compile.pass.cpp b/libcxx/test/std/ranges/range.factories/range.iota.view/iterator/ctor.value.compile.pass.cpp index e95042e26e146..fc3384e191d1d 100644 --- a/libcxx/test/std/ranges/range.factories/range.iota.view/iterator/ctor.value.compile.pass.cpp +++ b/libcxx/test/std/ranges/range.factories/range.iota.view/iterator/ctor.value.compile.pass.cpp @@ -15,8 +15,6 @@ #include #include -#include "test_macros.h" - #include "../types.h" static_assert(!std::is_constructible_v>, int>); diff --git a/libcxx/test/std/ranges/range.factories/range.iota.view/sentinel/ctor.value.compile.pass.cpp b/libcxx/test/std/ranges/range.factories/range.iota.view/sentinel/ctor.value.compile.pass.cpp index a39efb4318794..b0bcdb6c60ce7 100644 --- a/libcxx/test/std/ranges/range.factories/range.iota.view/sentinel/ctor.value.compile.pass.cpp +++ b/libcxx/test/std/ranges/range.factories/range.iota.view/sentinel/ctor.value.compile.pass.cpp @@ -15,8 +15,6 @@ #include #include -#include "test_macros.h" - #include "../types.h" using Sent = std::ranges::sentinel_t>>; From fb026c38b4b6c2b149f03074de2639bc952a6adc Mon Sep 17 00:00:00 2001 From: Hristo Hristov Date: Wed, 22 Jul 2026 10:42:42 +0300 Subject: [PATCH 21/33] Fixed CI --- .../range.istream.view/iterator/ctor.parent.compile.pass.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libcxx/test/std/ranges/range.factories/range.istream.view/iterator/ctor.parent.compile.pass.cpp b/libcxx/test/std/ranges/range.factories/range.istream.view/iterator/ctor.parent.compile.pass.cpp index 171e2dce1e5f0..04ff9ac24d731 100644 --- a/libcxx/test/std/ranges/range.factories/range.istream.view/iterator/ctor.parent.compile.pass.cpp +++ b/libcxx/test/std/ranges/range.factories/range.istream.view/iterator/ctor.parent.compile.pass.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// // REQUIRES: std-at-least-c++20 +// UNSUPPORTED: no-localization // constexpr explicit iterator(basic_istream_view& parent) noexcept; From 40e4eb936cd4c513c3792b57853bf3649ee73971 Mon Sep 17 00:00:00 2001 From: Hristo Hristov Date: Wed, 22 Jul 2026 10:57:29 +0300 Subject: [PATCH 22/33] Restored a test case! --- .../range.istream.view/iterator/deref.pass.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/libcxx/test/std/ranges/range.factories/range.istream.view/iterator/deref.pass.cpp b/libcxx/test/std/ranges/range.factories/range.istream.view/iterator/deref.pass.cpp index 9f9f13399392c..5df730410a4ad 100644 --- a/libcxx/test/std/ranges/range.factories/range.istream.view/iterator/deref.pass.cpp +++ b/libcxx/test/std/ranges/range.factories/range.istream.view/iterator/deref.pass.cpp @@ -28,6 +28,17 @@ void test() { std::same_as decltype(auto) v1 = *it; assert(v1 == 1); } + + // operator* should return the same reference to the value stored in the view + { + auto iss = make_string_stream("1 2 345 "); + std::ranges::basic_istream_view isv{iss}; + using Iter = std::ranges::iterator_t; + + Iter it1 = isv.begin(); + Iter it2 = isv.begin(); + assert(&*it1 == &*it2); + } } int main(int, char**) { From 09acb0d695deffea07116738be9e14c51c0fc0fe Mon Sep 17 00:00:00 2001 From: Hristo Hristov Date: Wed, 22 Jul 2026 11:16:34 +0300 Subject: [PATCH 23/33] Added a missing `take_view` test --- .../ctor.base.compile.pass.cpp | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 libcxx/test/std/ranges/range.adaptors/range.take/range.take.sentinel/ctor.base.compile.pass.cpp diff --git a/libcxx/test/std/ranges/range.adaptors/range.take/range.take.sentinel/ctor.base.compile.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.take/range.take.sentinel/ctor.base.compile.pass.cpp new file mode 100644 index 0000000000000..9383508165609 --- /dev/null +++ b/libcxx/test/std/ranges/range.adaptors/range.take/range.take.sentinel/ctor.base.compile.pass.cpp @@ -0,0 +1,25 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// REQUIRES: std-at-least-c++20 + +// constexpr explicit sentinel(sentinel_t end); + +// The constructor is now `private` (exposition-only) per P3059R2. + +#include +#include + +#include "test_iterators.h" +#include "../types.h" + +using TakeView = std::ranges::take_view; +using Sentinel = std::ranges::sentinel_t; + +static_assert(!std::is_constructible_v>); +static_assert(!std::is_convertible_v, Sentinel>); From ba73c41e69e0adca001ef6825b49ccabe8aaad84 Mon Sep 17 00:00:00 2001 From: Hristo Hristov Date: Wed, 22 Jul 2026 11:34:21 +0300 Subject: [PATCH 24/33] Added missing test `join_view` --- .../ctor.parent.compile.pass.cpp | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 libcxx/test/std/ranges/range.adaptors/range.join/range.join.sentinel/ctor.parent.compile.pass.cpp diff --git a/libcxx/test/std/ranges/range.adaptors/range.join/range.join.sentinel/ctor.parent.compile.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.join/range.join.sentinel/ctor.parent.compile.pass.cpp new file mode 100644 index 0000000000000..504c945e3d918 --- /dev/null +++ b/libcxx/test/std/ranges/range.adaptors/range.join/range.join.sentinel/ctor.parent.compile.pass.cpp @@ -0,0 +1,21 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// REQUIRES: std-at-least-c++20 + +// constexpr explicit sentinel(Parent& parent); + +// The constructor is now `private` (exposition-only) per P3059R2. + +#include + +#include "../types.h" + +using Parent = std::ranges::join_view>; +static_assert(!std::is_constructible_v, Parent&>); +static_assert(!std::is_convertible_v, Parent&>); From 2f4a7d4a8d731d64fedca47cb3e80bd72b87d1a7 Mon Sep 17 00:00:00 2001 From: Hristo Hristov Date: Wed, 22 Jul 2026 11:54:39 +0300 Subject: [PATCH 25/33] Update tests `split_view` --- ...tor.parent.iter.subrange.compile.pass.cpp} | 31 +++++------------ ....pass.cpp => ctor.parent.compile.pass.cpp} | 34 ++++--------------- 2 files changed, 14 insertions(+), 51 deletions(-) rename libcxx/test/std/ranges/range.adaptors/range.split/iterator/{ctor.base.pass.cpp => ctor.parent.iter.subrange.compile.pass.cpp} (64%) rename libcxx/test/std/ranges/range.adaptors/range.split/sentinel/{ctor.parent.pass.cpp => ctor.parent.compile.pass.cpp} (57%) diff --git a/libcxx/test/std/ranges/range.adaptors/range.split/iterator/ctor.base.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.split/iterator/ctor.parent.iter.subrange.compile.pass.cpp similarity index 64% rename from libcxx/test/std/ranges/range.adaptors/range.split/iterator/ctor.base.pass.cpp rename to libcxx/test/std/ranges/range.adaptors/range.split/iterator/ctor.parent.iter.subrange.compile.pass.cpp index 823e22e117f77..9f4e9a13e0447 100644 --- a/libcxx/test/std/ranges/range.adaptors/range.split/iterator/ctor.base.pass.cpp +++ b/libcxx/test/std/ranges/range.adaptors/range.split/iterator/ctor.parent.iter.subrange.compile.pass.cpp @@ -6,12 +6,14 @@ // //===----------------------------------------------------------------------===// -// UNSUPPORTED: c++03, c++11, c++14, c++17 +// REQUIRES: std-at-least-c++20 -// constexpr iterator begin(); +// constexpr iterator(split_view& parent, iterator_t current, subrange> next); + +// The constructor is now `private` (exposition-only) per P3059R2. -#include #include +#include #include "../types.h" @@ -30,24 +32,7 @@ struct TracedMoveView : std::ranges::view_base { constexpr TracedMoveIter end() const { return {}; } }; -constexpr bool test() { - using SplitView = std::ranges::split_view; - using SplitIter = std::ranges::iterator_t; - - SplitView sv{TracedMoveView{}, TracedMoveView{}}; - SplitIter iter = sv.begin(); - assert(iter.base().moved); - - auto subRange = *iter; - assert(subRange.begin().moved); - assert(subRange.end().moved); - - return true; -} - -int main(int, char**) { - test(); - static_assert(test()); +using SplitView = std::ranges::split_view; +using SplitIter = std::ranges::iterator_t; - return 0; -} +static_assert(!std::is_constructible_v>); diff --git a/libcxx/test/std/ranges/range.adaptors/range.split/sentinel/ctor.parent.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.split/sentinel/ctor.parent.compile.pass.cpp similarity index 57% rename from libcxx/test/std/ranges/range.adaptors/range.split/sentinel/ctor.parent.pass.cpp rename to libcxx/test/std/ranges/range.adaptors/range.split/sentinel/ctor.parent.compile.pass.cpp index 6e1ba912a201b..85d7e908a057c 100644 --- a/libcxx/test/std/ranges/range.adaptors/range.split/sentinel/ctor.parent.pass.cpp +++ b/libcxx/test/std/ranges/range.adaptors/range.split/sentinel/ctor.parent.compile.pass.cpp @@ -6,41 +6,19 @@ // //===----------------------------------------------------------------------===// -// UNSUPPORTED: c++03, c++11, c++14, c++17 +// REQUIRES: std-at-least-c++20 // constexpr explicit sentinel(split_view& parent); -#include +// The constructor is now `private` (exposition-only) per P3059R2. + #include -#include -#include "test_iterators.h" +#include "../types.h" -// test explicit using Range = std::ranges::subrange>; using SplitView = std::ranges::split_view>; using SplitSent = std::ranges::sentinel_t; -constexpr bool test() { - { - int buffer[] = {0, 1, 2}; - Range input{buffer, sentinel_wrapper(buffer + 3)}; - SplitView sv(input, -1); - auto it = sv.begin(); - - auto sent = sv.end(); - assert(sent != it); - - ++it; - assert(sent == it); - } - - return true; -} - -int main(int, char**) { - test(); - static_assert(test()); - - return 0; -} +static_assert(std::is_constructible_v); +static_assert(!std::is_convertible_v); From 4b7ed091fdad7c14f1774723d47eead9b6025984 Mon Sep 17 00:00:00 2001 From: Hristo Hristov Date: Wed, 22 Jul 2026 11:57:06 +0300 Subject: [PATCH 26/33] Fixed test --- .../range.split/sentinel/ctor.parent.compile.pass.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libcxx/test/std/ranges/range.adaptors/range.split/sentinel/ctor.parent.compile.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.split/sentinel/ctor.parent.compile.pass.cpp index 85d7e908a057c..e0e8029c4c538 100644 --- a/libcxx/test/std/ranges/range.adaptors/range.split/sentinel/ctor.parent.compile.pass.cpp +++ b/libcxx/test/std/ranges/range.adaptors/range.split/sentinel/ctor.parent.compile.pass.cpp @@ -20,5 +20,5 @@ using Range = std::ranges::subrange>; using SplitView = std::ranges::split_view>; using SplitSent = std::ranges::sentinel_t; -static_assert(std::is_constructible_v); +static_assert(!std::is_constructible_v); static_assert(!std::is_convertible_v); From 2e222712c8f7d62a2063ad917184d2cbc4fb6ebd Mon Sep 17 00:00:00 2001 From: Hristo Hristov Date: Wed, 22 Jul 2026 12:49:06 +0300 Subject: [PATCH 27/33] Added missing `transform_view` tests --- .../ctor.parent.iter.compile.pass.cpp | 23 ++++++++++++++++++ .../sentinel/ctor.base.compile.pass.cpp | 24 +++++++++++++++++++ 2 files changed, 47 insertions(+) create mode 100644 libcxx/test/std/ranges/range.adaptors/range.transform/iterator/ctor.parent.iter.compile.pass.cpp create mode 100644 libcxx/test/std/ranges/range.adaptors/range.transform/sentinel/ctor.base.compile.pass.cpp diff --git a/libcxx/test/std/ranges/range.adaptors/range.transform/iterator/ctor.parent.iter.compile.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.transform/iterator/ctor.parent.iter.compile.pass.cpp new file mode 100644 index 0000000000000..e7841dede5bc2 --- /dev/null +++ b/libcxx/test/std/ranges/range.adaptors/range.transform/iterator/ctor.parent.iter.compile.pass.cpp @@ -0,0 +1,23 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// REQUIRES: std-at-least-c++20 + +// constexpr iterator(Parent& parent, iterator_t current); + +// The constructor is now `private` (exposition-only) per P3059R2. + +#include + +#include "../types.h" + +using TransformView = std::ranges::transform_view; +using TransformViewBaseIter = std::ranges::iterator_t; +using TransformIter = std::ranges::iterator_t; + +static_assert(!std::is_constructible_v); diff --git a/libcxx/test/std/ranges/range.adaptors/range.transform/sentinel/ctor.base.compile.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.transform/sentinel/ctor.base.compile.pass.cpp new file mode 100644 index 0000000000000..08be4bbd16667 --- /dev/null +++ b/libcxx/test/std/ranges/range.adaptors/range.transform/sentinel/ctor.base.compile.pass.cpp @@ -0,0 +1,24 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// REQUIRES: std-at-least-c++20 + +// constexpr explicit sentinel(sentinel_t end); + +// The constructor is now `private` (exposition-only) per P3059R2. + +#include + +#include "../types.h" + +using Range = std::ranges::subrange>; +using SplitView = std::ranges::split_view>; +using SplitSent = std::ranges::sentinel_t; + +static_assert(!std::is_constructible_v); +static_assert(!std::is_convertible_v); From 67392d1cc29b61463984aafd64731af37d7315e2 Mon Sep 17 00:00:00 2001 From: Hristo Hristov Date: Wed, 22 Jul 2026 13:32:08 +0300 Subject: [PATCH 28/33] Try to fix the tests --- .../iterator/ctor.parent.iter.compile.pass.cpp | 3 ++- .../range.transform/sentinel/ctor.base.compile.pass.cpp | 9 +++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/libcxx/test/std/ranges/range.adaptors/range.filter/iterator/ctor.parent.iter.compile.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.filter/iterator/ctor.parent.iter.compile.pass.cpp index 4a013d0072222..bca1b3bda4b24 100644 --- a/libcxx/test/std/ranges/range.adaptors/range.filter/iterator/ctor.parent.iter.compile.pass.cpp +++ b/libcxx/test/std/ranges/range.adaptors/range.filter/iterator/ctor.parent.iter.compile.pass.cpp @@ -18,8 +18,9 @@ #include "../types.h" using View = minimal_view>; +using ViewIter = std::ranges::iterator_t; using FilterView = std::ranges::filter_view; using FilterIterator = std::ranges::iterator_t; -static_assert(!std::constructible_from); +static_assert(!std::constructible_from); static_assert(!std::convertible_to); diff --git a/libcxx/test/std/ranges/range.adaptors/range.transform/sentinel/ctor.base.compile.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.transform/sentinel/ctor.base.compile.pass.cpp index 08be4bbd16667..25a73252bcd2e 100644 --- a/libcxx/test/std/ranges/range.adaptors/range.transform/sentinel/ctor.base.compile.pass.cpp +++ b/libcxx/test/std/ranges/range.adaptors/range.transform/sentinel/ctor.base.compile.pass.cpp @@ -14,11 +14,12 @@ #include -#include "../types.h" - +#include "test_iterators.h" + using Range = std::ranges::subrange>; +using RangeSent = std::ranges::sentinel_t; using SplitView = std::ranges::split_view>; using SplitSent = std::ranges::sentinel_t; -static_assert(!std::is_constructible_v); -static_assert(!std::is_convertible_v); +static_assert(!std::is_constructible_v); +static_assert(!std::is_convertible_v); From e692e9b052765eb5c13399e719546b1071675663 Mon Sep 17 00:00:00 2001 From: Hristo Hristov Date: Wed, 22 Jul 2026 13:34:09 +0300 Subject: [PATCH 29/33] Formatting --- .../iterator/ctor.parent.iter.compile.pass.cpp | 6 +++--- .../range.transform/sentinel/ctor.base.compile.pass.cpp | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/libcxx/test/std/ranges/range.adaptors/range.transform/iterator/ctor.parent.iter.compile.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.transform/iterator/ctor.parent.iter.compile.pass.cpp index e7841dede5bc2..4bafbfea3e284 100644 --- a/libcxx/test/std/ranges/range.adaptors/range.transform/iterator/ctor.parent.iter.compile.pass.cpp +++ b/libcxx/test/std/ranges/range.adaptors/range.transform/iterator/ctor.parent.iter.compile.pass.cpp @@ -16,8 +16,8 @@ #include "../types.h" -using TransformView = std::ranges::transform_view; -using TransformViewBaseIter = std::ranges::iterator_t; -using TransformIter = std::ranges::iterator_t; +using TransformView = std::ranges::transform_view; +using TransformViewBaseIter = std::ranges::iterator_t; +using TransformIter = std::ranges::iterator_t; static_assert(!std::is_constructible_v); diff --git a/libcxx/test/std/ranges/range.adaptors/range.transform/sentinel/ctor.base.compile.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.transform/sentinel/ctor.base.compile.pass.cpp index 25a73252bcd2e..bfbe0a5820b9e 100644 --- a/libcxx/test/std/ranges/range.adaptors/range.transform/sentinel/ctor.base.compile.pass.cpp +++ b/libcxx/test/std/ranges/range.adaptors/range.transform/sentinel/ctor.base.compile.pass.cpp @@ -15,7 +15,7 @@ #include #include "test_iterators.h" - + using Range = std::ranges::subrange>; using RangeSent = std::ranges::sentinel_t; using SplitView = std::ranges::split_view>; From ddb5c85f5d4aa7ddf3cb2f4e17e20f0356194a95 Mon Sep 17 00:00:00 2001 From: Hristo Hristov Date: Wed, 22 Jul 2026 13:48:32 +0300 Subject: [PATCH 30/33] More fixes --- .../iterator/ctor.parent.iter.compile.pass.cpp | 3 +-- .../iterator/ctor.parent.iter.compile.pass.cpp | 2 +- .../sentinel/ctor.base.compile.pass.cpp | 13 +++++++------ 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/libcxx/test/std/ranges/range.adaptors/range.filter/iterator/ctor.parent.iter.compile.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.filter/iterator/ctor.parent.iter.compile.pass.cpp index bca1b3bda4b24..47deabb7136c6 100644 --- a/libcxx/test/std/ranges/range.adaptors/range.filter/iterator/ctor.parent.iter.compile.pass.cpp +++ b/libcxx/test/std/ranges/range.adaptors/range.filter/iterator/ctor.parent.iter.compile.pass.cpp @@ -22,5 +22,4 @@ using ViewIter = std::ranges::iterator_t; using FilterView = std::ranges::filter_view; using FilterIterator = std::ranges::iterator_t; -static_assert(!std::constructible_from); -static_assert(!std::convertible_to); +static_assert(!std::constructible_from); diff --git a/libcxx/test/std/ranges/range.adaptors/range.transform/iterator/ctor.parent.iter.compile.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.transform/iterator/ctor.parent.iter.compile.pass.cpp index 4bafbfea3e284..37b6016e439fb 100644 --- a/libcxx/test/std/ranges/range.adaptors/range.transform/iterator/ctor.parent.iter.compile.pass.cpp +++ b/libcxx/test/std/ranges/range.adaptors/range.transform/iterator/ctor.parent.iter.compile.pass.cpp @@ -20,4 +20,4 @@ using TransformView = std::ranges::transform_view using TransformViewBaseIter = std::ranges::iterator_t; using TransformIter = std::ranges::iterator_t; -static_assert(!std::is_constructible_v); +static_assert(!std::is_constructible_v); diff --git a/libcxx/test/std/ranges/range.adaptors/range.transform/sentinel/ctor.base.compile.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.transform/sentinel/ctor.base.compile.pass.cpp index bfbe0a5820b9e..608db6eafe127 100644 --- a/libcxx/test/std/ranges/range.adaptors/range.transform/sentinel/ctor.base.compile.pass.cpp +++ b/libcxx/test/std/ranges/range.adaptors/range.transform/sentinel/ctor.base.compile.pass.cpp @@ -15,11 +15,12 @@ #include #include "test_iterators.h" +#include "../types.h" -using Range = std::ranges::subrange>; -using RangeSent = std::ranges::sentinel_t; -using SplitView = std::ranges::split_view>; -using SplitSent = std::ranges::sentinel_t; +using Range = std::ranges::subrange>; +using BaseSent = std::ranges::sentinel_t; +using TransformView = std::ranges::transform_view; +using TransformSent = std::ranges::sentinel_t; -static_assert(!std::is_constructible_v); -static_assert(!std::is_convertible_v); +static_assert(!std::is_constructible_v); +static_assert(!std::is_convertible_v); From 2e1494c52f79d4c6c00ca13a1cb484ac609c1f31 Mon Sep 17 00:00:00 2001 From: Hristo Hristov Date: Wed, 22 Jul 2026 14:20:32 +0300 Subject: [PATCH 31/33] More fixes --- .../range.transform/sentinel/ctor.base.compile.pass.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/libcxx/test/std/ranges/range.adaptors/range.transform/sentinel/ctor.base.compile.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.transform/sentinel/ctor.base.compile.pass.cpp index 608db6eafe127..b5f134528fef0 100644 --- a/libcxx/test/std/ranges/range.adaptors/range.transform/sentinel/ctor.base.compile.pass.cpp +++ b/libcxx/test/std/ranges/range.adaptors/range.transform/sentinel/ctor.base.compile.pass.cpp @@ -17,9 +17,8 @@ #include "test_iterators.h" #include "../types.h" -using Range = std::ranges::subrange>; -using BaseSent = std::ranges::sentinel_t; -using TransformView = std::ranges::transform_view; +using BaseSent = std::ranges::sentinel_t; +using TransformView = std::ranges::transform_view; using TransformSent = std::ranges::sentinel_t; static_assert(!std::is_constructible_v); From 71723ab5616e273decb732c934859e95fd586b23 Mon Sep 17 00:00:00 2001 From: Hristo Hristov Date: Thu, 23 Jul 2026 08:55:43 +0300 Subject: [PATCH 32/33] Clean-up tests --- .../range.elements/iterator/base.pass.cpp | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/libcxx/test/std/ranges/range.adaptors/range.elements/iterator/base.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.elements/iterator/base.pass.cpp index bcce8e1f48f7b..83a2faa635188 100644 --- a/libcxx/test/std/ranges/range.adaptors/range.elements/iterator/base.pass.cpp +++ b/libcxx/test/std/ranges/range.adaptors/range.elements/iterator/base.pass.cpp @@ -37,9 +37,11 @@ LIBCPP_STATIC_ASSERT(!IsBaseNoexcept); constexpr bool test() { std::tuple t{5}; + std::ranges::elements_view ev{BaseView{&t, &t + 1}}; + // const & { - const ElementsIter it = std::ranges::elements_view{BaseView{&t, &t + 1}}.begin(); + const ElementsIter it = ev.begin(); decltype(auto) base = it.base(); static_assert(std::is_same_v* const&>); assert(base == &t); @@ -47,7 +49,7 @@ constexpr bool test() { // & { - ElementsIter it = std::ranges::elements_view{BaseView{&t, &t + 1}}.begin(); + ElementsIter it = ev.begin(); decltype(auto) base = it.base(); static_assert(std::is_same_v* const&>); assert(base == &t); @@ -55,7 +57,7 @@ constexpr bool test() { // && { - ElementsIter it = std::ranges::elements_view{BaseView{&t, &t + 1}}.begin(); + ElementsIter it = ev.begin(); decltype(auto) base = std::move(it).base(); static_assert(std::is_same_v*>); assert(base == &t); @@ -63,7 +65,7 @@ constexpr bool test() { // const && { - const ElementsIter it = std::ranges::elements_view{BaseView{&t, &t + 1}}.begin(); + const ElementsIter it = ev.begin(); decltype(auto) base = std::move(it).base(); static_assert(std::is_same_v* const&>); assert(base == &t); @@ -78,10 +80,10 @@ constexpr bool test() { constexpr bool operator==(const MoveOnlyIter&) const { return true; } }; - auto it = - std::ranges::elements_view, 0>{ - std::ranges::subrange{MoveOnlyIter{{}, MoveOnly{5}}, Sent{}}} - .begin(); + std::ranges::elements_view, 0>{ + std::ranges::subrange mev{MoveOnlyIter{{}, MoveOnly{5}}, Sent{}}}; + auto it = mev.begin(); + decltype(auto) base = std::move(it).base(); static_assert(std::is_same_v); assert(base.mo.get() == 5); From f5c82b23b5a1b54135905829b90effffe17ea70b Mon Sep 17 00:00:00 2001 From: Hristo Hristov Date: Thu, 23 Jul 2026 09:22:54 +0300 Subject: [PATCH 33/33] Clean-up `elements_view` --- .../range.adaptors/range.elements/iterator/base.pass.cpp | 4 ++-- .../range.elements/iterator/ctor.other.pass.cpp | 8 ++++---- .../range.elements/sentinel/ctor.base.compile.pass.cpp | 6 ++++-- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/libcxx/test/std/ranges/range.adaptors/range.elements/iterator/base.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.elements/iterator/base.pass.cpp index 83a2faa635188..f6514d6fe696b 100644 --- a/libcxx/test/std/ranges/range.adaptors/range.elements/iterator/base.pass.cpp +++ b/libcxx/test/std/ranges/range.adaptors/range.elements/iterator/base.pass.cpp @@ -80,8 +80,8 @@ constexpr bool test() { constexpr bool operator==(const MoveOnlyIter&) const { return true; } }; - std::ranges::elements_view, 0>{ - std::ranges::subrange mev{MoveOnlyIter{{}, MoveOnly{5}}, Sent{}}}; + std::ranges::elements_view, 0> mev{ + std::ranges::subrange{MoveOnlyIter{{}, MoveOnly{5}}, Sent{}}}; auto it = mev.begin(); decltype(auto) base = std::move(it).base(); diff --git a/libcxx/test/std/ranges/range.adaptors/range.elements/iterator/ctor.other.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.elements/iterator/ctor.other.pass.cpp index 9255fb47013b6..df0d63ed38c96 100644 --- a/libcxx/test/std/ranges/range.adaptors/range.elements/iterator/ctor.other.pass.cpp +++ b/libcxx/test/std/ranges/range.adaptors/range.elements/iterator/ctor.other.pass.cpp @@ -58,10 +58,10 @@ static_assert(!std::is_constructible_v, ConstElemIt constexpr bool test() { struct TestRange : std::ranges::view_base { - constexpr ConvertibleIter begin() { return ConvertibleIter{5}; } - constexpr ConvertibleIter end() { return ConvertibleIter{5}; } - constexpr ConvertibleIter begin() const { return ConvertibleIter{5}; } - constexpr ConvertibleIter end() const { return ConvertibleIter{5}; } + constexpr auto begin() { return ConvertibleIter{5}; } + constexpr auto end() { return ConvertibleIter{5}; } + constexpr auto begin() const { return ConvertibleIter{5}; } + constexpr auto end() const { return ConvertibleIter{5}; } }; std::ranges::elements_view ev{TestRange{}}; diff --git a/libcxx/test/std/ranges/range.adaptors/range.elements/sentinel/ctor.base.compile.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.elements/sentinel/ctor.base.compile.pass.cpp index ee4a297c1f4a9..bbdc797b03e9c 100644 --- a/libcxx/test/std/ranges/range.adaptors/range.elements/sentinel/ctor.base.compile.pass.cpp +++ b/libcxx/test/std/ranges/range.adaptors/range.elements/sentinel/ctor.base.compile.pass.cpp @@ -26,5 +26,7 @@ struct Range : std::ranges::view_base { Sent end(); }; -static_assert(!std::is_constructible_v>, Sent>); -static_assert(!std::is_convertible_v>>); +using ElementsView = std::ranges::elements_view; + +static_assert(!std::is_constructible_v, Sent>); +static_assert(!std::is_convertible_v>);