https://github.com/JMazurkiewicz updated https://github.com/llvm/llvm-project/pull/66033
>From 600a282d49011782fde23c4388ba1346284153a1 Mon Sep 17 00:00:00 2001 From: Jakub Mazurkiewicz <mazku...@gmail.com> Date: Fri, 8 Sep 2023 18:20:59 +0200 Subject: [PATCH 01/11] [libc++] P2770R0: "Stashing stashing iterators for proper flattening" * Parially implements P2770R0: "Stashing stashing iterators for proper flattening" * `join_with_view` hasn't been done yet since this type isn't implemented yet * Rename `test/libcxx/ranges/range.adaptors/range.adaptor.tuple` directory to `test/libcxx/ranges/range.adaptors/range.adaptor.helpers` to match the standard: http://eel.is/c++draft/range.adaptor.helpers (this change happened in P2770R0, see point 3 of wording). * Rename `libcxx\test\std\ranges\range.adaptors\range.join.view` to `libcxx\test\std\ranges\range.adaptors\range.join` to match the standard --- libcxx/docs/Status/Cxx23.rst | 1 + libcxx/docs/Status/Cxx23Papers.csv | 2 +- libcxx/docs/UsingLibcxx.rst | 1 - libcxx/include/CMakeLists.txt | 1 + libcxx/include/__ranges/join_view.h | 132 +++++++++++------- libcxx/include/__utility/as_lvalue.h | 39 ++++++ libcxx/include/module.modulemap.in | 1 + libcxx/include/regex | 8 ++ libcxx/include/utility | 1 + libcxx/modules/std/ranges.inc | 2 - .../as-lvalue.verify.cpp | 48 +++++++ .../tuple-for-each.pass.cpp | 0 .../segmented_iterator.compile.pass.cpp | 1 - .../alg.copy/ranges.copy.segmented.pass.cpp | 2 - .../alg.copy/ranges.copy_backward.pass.cpp | 2 - .../iterator/ctor.parent.outer.pass.cpp | 57 -------- .../adaptor.pass.cpp | 1 - .../base.pass.cpp | 1 - .../begin.pass.cpp | 31 +++- .../ctad.compile.pass.cpp | 1 - .../ctad.verify.cpp | 1 - .../ctor.default.pass.cpp | 1 - .../ctor.view.pass.cpp | 1 - .../end.pass.cpp | 22 +-- .../general.pass.cpp | 1 - .../range.join.iterator}/arrow.pass.cpp | 1 - .../ctor.default.pass.cpp | 16 +-- .../range.join.iterator}/ctor.other.pass.cpp | 3 +- .../range.join.iterator}/decrement.pass.cpp | 13 +- .../range.join.iterator}/eq.pass.cpp | 7 +- .../range.join.iterator}/increment.pass.cpp | 18 ++- .../range.join.iterator}/iter.move.pass.cpp | 1 - .../range.join.iterator}/iter.swap.pass.cpp | 1 - .../member_types.compile.pass.cpp | 1 - .../range.join.iterator}/star.pass.cpp | 1 - .../ctor.default.pass.cpp | 1 - .../range.join.sentinel}/ctor.other.pass.cpp | 1 - .../range.join.sentinel}/ctor.parent.pass.cpp | 1 - .../range.join.sentinel}/eq.pass.cpp | 19 ++- .../{range.join.view => range.join}/types.h | 66 ++++++++- ...rator_concept_conformance.compile.pass.cpp | 4 +- .../std/re/re.iter/re.regiter/types.pass.cpp | 4 + ...rator_concept_conformance.compile.pass.cpp | 4 +- .../std/re/re.iter/re.tokiter/types.pass.cpp | 4 + libcxx/utils/data/ignore_format.txt | 45 +++--- 45 files changed, 364 insertions(+), 205 deletions(-) create mode 100644 libcxx/include/__utility/as_lvalue.h create mode 100644 libcxx/test/libcxx/ranges/range.adaptors/range.adaptor.helpers/as-lvalue.verify.cpp rename libcxx/test/libcxx/ranges/range.adaptors/{range.adaptor.tuple => range.adaptor.helpers}/tuple-for-each.pass.cpp (100%) delete mode 100644 libcxx/test/std/ranges/range.adaptors/range.join.view/iterator/ctor.parent.outer.pass.cpp rename libcxx/test/std/ranges/range.adaptors/{range.join.view => range.join}/adaptor.pass.cpp (99%) rename libcxx/test/std/ranges/range.adaptors/{range.join.view => range.join}/base.pass.cpp (98%) rename libcxx/test/std/ranges/range.adaptors/{range.join.view => range.join}/begin.pass.cpp (83%) rename libcxx/test/std/ranges/range.adaptors/{range.join.view => range.join}/ctad.compile.pass.cpp (98%) rename libcxx/test/std/ranges/range.adaptors/{range.join.view => range.join}/ctad.verify.cpp (97%) rename libcxx/test/std/ranges/range.adaptors/{range.join.view => range.join}/ctor.default.pass.cpp (97%) rename libcxx/test/std/ranges/range.adaptors/{range.join.view => range.join}/ctor.view.pass.cpp (97%) rename libcxx/test/std/ranges/range.adaptors/{range.join.view => range.join}/end.pass.cpp (95%) rename libcxx/test/std/ranges/range.adaptors/{range.join.view => range.join}/general.pass.cpp (98%) rename libcxx/test/std/ranges/range.adaptors/{range.join.view/iterator => range.join/range.join.iterator}/arrow.pass.cpp (99%) rename libcxx/test/std/ranges/range.adaptors/{range.join.view/iterator => range.join/range.join.iterator}/ctor.default.pass.cpp (70%) rename libcxx/test/std/ranges/range.adaptors/{range.join.view/iterator => range.join/range.join.iterator}/ctor.other.pass.cpp (97%) rename libcxx/test/std/ranges/range.adaptors/{range.join.view/iterator => range.join/range.join.iterator}/decrement.pass.cpp (90%) rename libcxx/test/std/ranges/range.adaptors/{range.join.view/iterator => range.join/range.join.iterator}/eq.pass.cpp (89%) rename libcxx/test/std/ranges/range.adaptors/{range.join.view/iterator => range.join/range.join.iterator}/increment.pass.cpp (94%) rename libcxx/test/std/ranges/range.adaptors/{range.join.view/iterator => range.join/range.join.iterator}/iter.move.pass.cpp (98%) rename libcxx/test/std/ranges/range.adaptors/{range.join.view/iterator => range.join/range.join.iterator}/iter.swap.pass.cpp (98%) rename libcxx/test/std/ranges/range.adaptors/{range.join.view/iterator => range.join/range.join.iterator}/member_types.compile.pass.cpp (99%) rename libcxx/test/std/ranges/range.adaptors/{range.join.view/iterator => range.join/range.join.iterator}/star.pass.cpp (97%) rename libcxx/test/std/ranges/range.adaptors/{range.join.view/sentinel => range.join/range.join.sentinel}/ctor.default.pass.cpp (95%) rename libcxx/test/std/ranges/range.adaptors/{range.join.view/sentinel => range.join/range.join.sentinel}/ctor.other.pass.cpp (99%) rename libcxx/test/std/ranges/range.adaptors/{range.join.view/sentinel => range.join/range.join.sentinel}/ctor.parent.pass.cpp (97%) rename libcxx/test/std/ranges/range.adaptors/{range.join.view/sentinel => range.join/range.join.sentinel}/eq.pass.cpp (81%) rename libcxx/test/std/ranges/range.adaptors/{range.join.view => range.join}/types.h (88%) diff --git a/libcxx/docs/Status/Cxx23.rst b/libcxx/docs/Status/Cxx23.rst index 839640a7c7e881b..3e6e33f08c7ccfa 100644 --- a/libcxx/docs/Status/Cxx23.rst +++ b/libcxx/docs/Status/Cxx23.rst @@ -45,6 +45,7 @@ Paper Status clang doesn't issue a diagnostic for deprecated using template declarations. .. [#note-P2520R0] P2520R0: Libc++ implemented this paper as a DR in C++20 as well. .. [#note-P2711R1] P2711R1: ``join_with_view`` hasn't been done yet since this type isn't implemented yet. + .. [#note-P2770R0] P2770R0: ``join_with_view`` hasn't been done yet since this type isn't implemented yet. .. [#note-P2693R1] P2693R1: The formatter for ``std::thread::id`` is implemented. The formatter for ``stacktrace`` is not implemented, since ``stacktrace`` is not implemented yet. diff --git a/libcxx/docs/Status/Cxx23Papers.csv b/libcxx/docs/Status/Cxx23Papers.csv index 19b1dd8eb5a446f..38b77d42ec5b977 100644 --- a/libcxx/docs/Status/Cxx23Papers.csv +++ b/libcxx/docs/Status/Cxx23Papers.csv @@ -104,7 +104,7 @@ "`P2708R1 <https://wg21.link/P2708R1>`__","LWG", "No Further Fundamentals TSes", "November 2022","|Nothing to do|","","" "","","","","","","" "`P0290R4 <https://wg21.link/P0290R4>`__","LWG", "``apply()`` for ``synchronized_value<T>``","February 2023","","","|concurrency TS|" -"`P2770R0 <https://wg21.link/P2770R0>`__","LWG", "Stashing stashing ``iterators`` for proper flattening","February 2023","|In Progress|","","|ranges|" +"`P2770R0 <https://wg21.link/P2770R0>`__","LWG", "Stashing stashing ``iterators`` for proper flattening","February 2023","|Partial| [#note-P2770R0]_","","|ranges|" "`P2164R9 <https://wg21.link/P2164R9>`__","LWG", "``views::enumerate``","February 2023","","","|ranges|" "`P2711R1 <https://wg21.link/P2711R1>`__","LWG", "Making multi-param constructors of ``views`` ``explicit``","February 2023","|In Progress| [#note-P2711R1]_","","|ranges|" "`P2609R3 <https://wg21.link/P2609R3>`__","LWG", "Relaxing Ranges Just A Smidge","February 2023","","","|ranges|" diff --git a/libcxx/docs/UsingLibcxx.rst b/libcxx/docs/UsingLibcxx.rst index 24d6a7b95f5b2e4..2d52a7c9ef2b8a4 100644 --- a/libcxx/docs/UsingLibcxx.rst +++ b/libcxx/docs/UsingLibcxx.rst @@ -50,7 +50,6 @@ when ``-fexperimental-library`` is passed: * ``std::stop_token``, ``std::stop_source`` and ``std::stop_callback`` * ``std::jthread`` * ``std::chrono::tzdb`` and related time zone functionality -* ``std::ranges::join_view`` .. warning:: Experimental libraries are experimental. diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt index 889d7fedbf2965f..7aad3a4c624345a 100644 --- a/libcxx/include/CMakeLists.txt +++ b/libcxx/include/CMakeLists.txt @@ -837,6 +837,7 @@ set(files __type_traits/void_t.h __undef_macros __utility/as_const.h + __utility/as_lvalue.h __utility/auto_cast.h __utility/cmp.h __utility/convert_to_integral.h diff --git a/libcxx/include/__ranges/join_view.h b/libcxx/include/__ranges/join_view.h index e6240dfd2580dc7..812a6f9379a8579 100644 --- a/libcxx/include/__ranges/join_view.h +++ b/libcxx/include/__ranges/join_view.h @@ -32,6 +32,8 @@ #include <__ranges/view_interface.h> #include <__type_traits/common_type.h> #include <__type_traits/maybe_const.h> +#include <__utility/as_lvalue.h> +#include <__utility/empty.h> #include <__utility/forward.h> #include <optional> @@ -41,10 +43,7 @@ _LIBCPP_BEGIN_NAMESPACE_STD -// Note: `join_view` is still marked experimental because there is an ABI-breaking change that affects `join_view` in -// the pipeline (https://isocpp.org/files/papers/D2770R0.html). -// TODO: make `join_view` non-experimental once D2770 is implemented. -#if _LIBCPP_STD_VER >= 20 && defined(_LIBCPP_ENABLE_EXPERIMENTAL) +#if _LIBCPP_STD_VER >= 20 namespace ranges { template<class> @@ -84,11 +83,16 @@ namespace ranges { template <class> friend struct std::__segmented_iterator_traits; - static constexpr bool _UseCache = !is_reference_v<_InnerRange>; - using _Cache = _If<_UseCache, __non_propagating_cache<remove_cvref_t<_InnerRange>>, __empty_cache>; - _LIBCPP_NO_UNIQUE_ADDRESS _Cache __cache_; _LIBCPP_NO_UNIQUE_ADDRESS _View __base_ = _View(); + static constexpr bool _UseOuterCache = !forward_range<_View>; + using _OuterCache = _If<_UseOuterCache, __non_propagating_cache<iterator_t<_View>>, __empty_cache>; + _LIBCPP_NO_UNIQUE_ADDRESS _OuterCache __outer_; + + static constexpr bool _UseInnerCache = !is_reference_v<_InnerRange>; + using _InnerCache = _If<_UseInnerCache, __non_propagating_cache<remove_cvref_t<_InnerRange>>, __empty_cache>; + _LIBCPP_NO_UNIQUE_ADDRESS _InnerCache __inner_; + public: _LIBCPP_HIDE_FROM_ABI join_view() requires default_initializable<_View> = default; @@ -105,16 +109,22 @@ namespace ranges { _LIBCPP_HIDE_FROM_ABI constexpr auto begin() { - constexpr bool __use_const = __simple_view<_View> && - is_reference_v<range_reference_t<_View>>; - return __iterator<__use_const>{*this, ranges::begin(__base_)}; + if constexpr (forward_range<_View>) { + constexpr bool __use_const = __simple_view<_View> && + is_reference_v<range_reference_t<_View>>; + return __iterator<__use_const>{*this, ranges::begin(__base_)}; + } else { + __outer_.__emplace(ranges::begin(__base_)); + return __iterator<false>{*this}; + } } template<class _V2 = _View> _LIBCPP_HIDE_FROM_ABI constexpr auto begin() const - requires input_range<const _V2> && - is_reference_v<range_reference_t<const _V2>> + requires forward_range<const _V2> && + is_reference_v<range_reference_t<const _V2>> && + input_range<range_reference_t<const _V2>> { return __iterator<true>{*this, ranges::begin(__base_)}; } @@ -134,13 +144,12 @@ namespace ranges { template<class _V2 = _View> _LIBCPP_HIDE_FROM_ABI constexpr auto end() const - requires input_range<const _V2> && - is_reference_v<range_reference_t<const _V2>> + requires forward_range<const _V2> && + is_reference_v<range_reference_t<const _V2>> && + input_range<range_reference_t<const _V2>> { using _ConstInnerRange = range_reference_t<const _View>; - if constexpr (forward_range<const _View> && - is_reference_v<_ConstInnerRange> && - forward_range<_ConstInnerRange> && + if constexpr (forward_range<_ConstInnerRange> && common_range<const _View> && common_range<_ConstInnerRange>) { return __iterator<true>{*this, ranges::end(__base_)}; @@ -154,11 +163,10 @@ namespace ranges { requires view<_View> && input_range<range_reference_t<_View>> template<bool _Const> struct join_view<_View>::__sentinel { - template<bool> - friend struct __sentinel; - private: - using _Parent = __maybe_const<_Const, join_view<_View>>; + friend join_view; + + using _Parent = __maybe_const<_Const, join_view>; using _Base = __maybe_const<_Const, _View>; sentinel_t<_Base> __end_ = sentinel_t<_Base>(); @@ -179,7 +187,7 @@ namespace ranges { requires sentinel_for<sentinel_t<_Base>, iterator_t<__maybe_const<_OtherConst, _View>>> _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const __iterator<_OtherConst>& __x, const __sentinel& __y) { - return __x.__outer_ == __y.__end_; + return __x.__get_outer() == __y.__end_; } }; @@ -191,9 +199,7 @@ namespace ranges { template<bool _Const> struct join_view<_View>::__iterator final : public __join_view_iterator_category<__maybe_const<_Const, _View>> { - - template<bool> - friend struct __iterator; + friend join_view; template <class> friend struct std::__segmented_iterator_traits; @@ -209,8 +215,11 @@ namespace ranges { static constexpr bool __ref_is_glvalue = is_reference_v<range_reference_t<_Base>>; + static constexpr bool _OuterPresent = forward_range<_Base>; + using _OuterType = _If<_OuterPresent, _Outer, std::__empty>; + public: - _Outer __outer_ = _Outer(); + _LIBCPP_NO_UNIQUE_ADDRESS _OuterType __outer_ = _OuterType(); private: optional<_Inner> __inner_; @@ -218,12 +227,12 @@ namespace ranges { _LIBCPP_HIDE_FROM_ABI constexpr void __satisfy() { - for (; __outer_ != ranges::end(__parent_->__base_); ++__outer_) { - auto&& __inner = [&]() -> auto&& { + for (; __get_outer() != ranges::end(__parent_->__base_); ++__get_outer()) { + auto&& __inner = [this]() -> auto&& { if constexpr (__ref_is_glvalue) - return *__outer_; + return *__get_outer(); else - return __parent_->__cache_.__emplace_from([&]() -> decltype(auto) { return *__outer_; }); + return __parent_->__inner_.__emplace_from([&]() -> decltype(auto) { return *__get_outer(); }); }(); __inner_ = ranges::begin(__inner); if (*__inner_ != ranges::end(__inner)) @@ -234,8 +243,37 @@ namespace ranges { __inner_.reset(); } + _LIBCPP_HIDE_FROM_ABI constexpr _Outer& __get_outer() { + if constexpr (forward_range<_Base>) { + return __outer_; + } else { + return *__parent_->__outer_; + } + } + + _LIBCPP_HIDE_FROM_ABI constexpr const _Outer& __get_outer() const { + if constexpr (forward_range<_Base>) { + return __outer_; + } else { + return *__parent_->__outer_; + } + } + + _LIBCPP_HIDE_FROM_ABI constexpr __iterator(_Parent& __parent, _Outer __outer) + requires forward_range<_Base> + : __outer_(std::move(__outer)), __parent_(std::addressof(__parent)) { + __satisfy(); + } + + _LIBCPP_HIDE_FROM_ABI constexpr __iterator(_Parent& __parent) + requires(!forward_range<_Base>) + : __parent_(std::addressof(__parent)) { + __satisfy(); + } + _LIBCPP_HIDE_FROM_ABI constexpr __iterator(_Parent* __parent, _Outer __outer, _Inner __inner) - : __outer_(std::move(__outer)), __inner_(std::move(__inner)), __parent_(__parent) {} + requires forward_range<_Base> + : __outer_(std::move(__outer)), __inner_(std::move(__inner)), __parent_(__parent) {} public: using iterator_concept = _If< @@ -254,15 +292,7 @@ namespace ranges { using difference_type = common_type_t< range_difference_t<_Base>, range_difference_t<range_reference_t<_Base>>>; - _LIBCPP_HIDE_FROM_ABI - __iterator() requires default_initializable<_Outer> = default; - - _LIBCPP_HIDE_FROM_ABI - constexpr __iterator(_Parent& __parent, _Outer __outer) - : __outer_(std::move(__outer)) - , __parent_(std::addressof(__parent)) { - __satisfy(); - } + _LIBCPP_HIDE_FROM_ABI __iterator() = default; _LIBCPP_HIDE_FROM_ABI constexpr __iterator(__iterator<!_Const> __i) @@ -287,14 +317,14 @@ namespace ranges { _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator++() { - auto&& __inner = [&]() -> auto&& { + auto __get_inner_range = [&]() -> decltype(auto) { if constexpr (__ref_is_glvalue) - return *__outer_; + return *__get_outer(); else - return *__parent_->__cache_; - }(); - if (++*__inner_ == ranges::end(__inner)) { - ++__outer_; + return *__parent_->__inner_; + }; + if (++*__inner_ == ranges::end(ranges::__as_lvalue(__get_inner_range()))) { + ++__get_outer(); __satisfy(); } return *this; @@ -324,11 +354,11 @@ namespace ranges { common_range<range_reference_t<_Base>> { if (__outer_ == ranges::end(__parent_->__base_)) - __inner_ = ranges::end(*--__outer_); + __inner_ = ranges::end(ranges::__as_lvalue(*--__outer_)); // Skip empty inner ranges when going backwards. - while (*__inner_ == ranges::begin(*__outer_)) { - __inner_ = ranges::end(*--__outer_); + while (*__inner_ == ranges::begin(ranges::__as_lvalue(*__outer_))) { + __inner_ = ranges::end(ranges::__as_lvalue(*--__outer_)); } --*__inner_; @@ -350,7 +380,7 @@ namespace ranges { _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const __iterator& __x, const __iterator& __y) requires __ref_is_glvalue && - equality_comparable<iterator_t<_Base>> && + forward_range<_Base> && equality_comparable<iterator_t<range_reference_t<_Base>>> { return __x.__outer_ == __y.__outer_ && __x.__inner_ == __y.__inner_; @@ -436,7 +466,7 @@ struct __segmented_iterator_traits<_JoinViewIterator> { } }; -#endif // #if _LIBCPP_STD_VER >= 20 && defined(_LIBCPP_ENABLE_EXPERIMENTAL) +#endif // #if _LIBCPP_STD_VER >= 20 _LIBCPP_END_NAMESPACE_STD diff --git a/libcxx/include/__utility/as_lvalue.h b/libcxx/include/__utility/as_lvalue.h new file mode 100644 index 000000000000000..b4df650edbf65ef --- /dev/null +++ b/libcxx/include/__utility/as_lvalue.h @@ -0,0 +1,39 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___UTILITY_AS_LVALUE_H +#define _LIBCPP___UTILITY_AS_LVALUE_H + +#include <__config> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 20 + +namespace ranges { +template <class _Tp> +_LIBCPP_HIDE_FROM_ABI constexpr _Tp& __as_lvalue(_LIBCPP_LIFETIMEBOUND _Tp&& __t) { + return static_cast<_Tp&>(__t); +} +} // namespace ranges + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___UTILITY_AS_LVALUE_H diff --git a/libcxx/include/module.modulemap.in b/libcxx/include/module.modulemap.in index 17ebe48f329963d..8364dde16ccf9f9 100644 --- a/libcxx/include/module.modulemap.in +++ b/libcxx/include/module.modulemap.in @@ -2041,6 +2041,7 @@ module std_private_type_traits_unwrap_ref [system module std_private_type_traits_void_t [system] { header "__type_traits/void_t.h" } module std_private_utility_as_const [system] { header "__utility/as_const.h" } +module std_private_utility_as_lvalue [system] { header "__utility/as_lvalue.h" } module std_private_utility_auto_cast [system] { header "__utility/auto_cast.h" export std_private_type_traits_decay diff --git a/libcxx/include/regex b/libcxx/include/regex index e8865ac1089d6f4..59d3af2a4bcb32a 100644 --- a/libcxx/include/regex +++ b/libcxx/include/regex @@ -697,6 +697,7 @@ public: typedef const value_type* pointer; typedef const value_type& reference; typedef forward_iterator_tag iterator_category; + typedef input_iterator_tag iterator_concept; // since C++20 regex_iterator(); regex_iterator(BidirectionalIterator a, BidirectionalIterator b, @@ -737,6 +738,7 @@ public: typedef const value_type* pointer; typedef const value_type& reference; typedef forward_iterator_tag iterator_category; + typedef input_iterator_tag iterator_concept; // since C++20 regex_token_iterator(); regex_token_iterator(BidirectionalIterator a, BidirectionalIterator b, @@ -6407,6 +6409,9 @@ public: typedef const value_type* pointer; typedef const value_type& reference; typedef forward_iterator_tag iterator_category; +#if _LIBCPP_STD_VER >= 20 + typedef input_iterator_tag iterator_concept; +#endif private: _BidirectionalIterator __begin_; @@ -6542,6 +6547,9 @@ public: typedef const value_type* pointer; typedef const value_type& reference; typedef forward_iterator_tag iterator_category; +#if _LIBCPP_STD_VER >= 20 + typedef input_iterator_tag iterator_concept; +#endif private: typedef regex_iterator<_BidirectionalIterator, _CharT, _Traits> _Position; diff --git a/libcxx/include/utility b/libcxx/include/utility index c5581d55e79bbb3..1deef3db204107f 100644 --- a/libcxx/include/utility +++ b/libcxx/include/utility @@ -249,6 +249,7 @@ template <class T> #include <__assert> // all public C++ headers provide the assertion handler #include <__config> #include <__utility/as_const.h> +#include <__utility/as_lvalue.h> #include <__utility/auto_cast.h> #include <__utility/cmp.h> #include <__utility/declval.h> diff --git a/libcxx/modules/std/ranges.inc b/libcxx/modules/std/ranges.inc index a883103d812588b..82c7d99f8979a82 100644 --- a/libcxx/modules/std/ranges.inc +++ b/libcxx/modules/std/ranges.inc @@ -204,13 +204,11 @@ export namespace std { using std::ranges::views::drop_while; } // namespace views -#ifdef _LIBCPP_ENABLE_EXPERIMENTAL using std::ranges::join_view; namespace views { using std::ranges::views::join; } // namespace views -#endif // _LIBCPP_ENABLE_EXPERIMENTAL #if 0 using std::ranges::join_with_view; diff --git a/libcxx/test/libcxx/ranges/range.adaptors/range.adaptor.helpers/as-lvalue.verify.cpp b/libcxx/test/libcxx/ranges/range.adaptors/range.adaptor.helpers/as-lvalue.verify.cpp new file mode 100644 index 000000000000000..878ef91b13839d2 --- /dev/null +++ b/libcxx/test/libcxx/ranges/range.adaptors/range.adaptor.helpers/as-lvalue.verify.cpp @@ -0,0 +1,48 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// <ranges> + +// template<class T> +// constexpr T& as-lvalue(T&& t) { // exposition only + +#include <ranges> + +#include <concepts> +#include <utility> + +constexpr bool test() { + // Check glvalue + { + int lvalue{}; + [[maybe_unused]] std::same_as<int&> decltype(auto) check = std::ranges::__as_lvalue(lvalue); + } + + // Check prvalue + { + [[maybe_unused]] std::same_as<int&> decltype(auto) check = std::ranges::__as_lvalue( + 0); // expected-warning {{temporary bound to local reference 'check' will be destroyed at the end of the full-expression}} + } + + // Check xvalue + { + int xvalue{}; + [[maybe_unused]] std::same_as<int&> decltype(auto) check = std::ranges::__as_lvalue(std::move(xvalue)); + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/libcxx/ranges/range.adaptors/range.adaptor.tuple/tuple-for-each.pass.cpp b/libcxx/test/libcxx/ranges/range.adaptors/range.adaptor.helpers/tuple-for-each.pass.cpp similarity index 100% rename from libcxx/test/libcxx/ranges/range.adaptors/range.adaptor.tuple/tuple-for-each.pass.cpp rename to libcxx/test/libcxx/ranges/range.adaptors/range.adaptor.helpers/tuple-for-each.pass.cpp diff --git a/libcxx/test/libcxx/ranges/range.adaptors/range.join/segmented_iterator.compile.pass.cpp b/libcxx/test/libcxx/ranges/range.adaptors/range.join/segmented_iterator.compile.pass.cpp index 82e8cab503a2750..6cd17c2b3f3533b 100644 --- a/libcxx/test/libcxx/ranges/range.adaptors/range.join/segmented_iterator.compile.pass.cpp +++ b/libcxx/test/libcxx/ranges/range.adaptors/range.join/segmented_iterator.compile.pass.cpp @@ -7,7 +7,6 @@ //===----------------------------------------------------------------------===// // UNSUPPORTED: c++03, c++11, c++14, c++17 -// UNSUPPORTED: !c++experimental #include <ranges> #include <utility> diff --git a/libcxx/test/std/algorithms/alg.modifying.operations/alg.copy/ranges.copy.segmented.pass.cpp b/libcxx/test/std/algorithms/alg.modifying.operations/alg.copy/ranges.copy.segmented.pass.cpp index 50fb479afcd0640..ec60ab8db1609b2 100644 --- a/libcxx/test/std/algorithms/alg.modifying.operations/alg.copy/ranges.copy.segmented.pass.cpp +++ b/libcxx/test/std/algorithms/alg.modifying.operations/alg.copy/ranges.copy.segmented.pass.cpp @@ -7,8 +7,6 @@ //===----------------------------------------------------------------------===// // UNSUPPORTED: c++03, c++11, c++14, c++17 -// TODO: make `join_view` non-experimental once D2770 is implemented. -// UNSUPPORTED: !c++experimental #include <algorithm> #include <array> diff --git a/libcxx/test/std/algorithms/alg.modifying.operations/alg.copy/ranges.copy_backward.pass.cpp b/libcxx/test/std/algorithms/alg.modifying.operations/alg.copy/ranges.copy_backward.pass.cpp index 184008c3e2fd0ff..301fbcbc533c260 100644 --- a/libcxx/test/std/algorithms/alg.modifying.operations/alg.copy/ranges.copy_backward.pass.cpp +++ b/libcxx/test/std/algorithms/alg.modifying.operations/alg.copy/ranges.copy_backward.pass.cpp @@ -9,8 +9,6 @@ // <algorithm> // UNSUPPORTED: c++03, c++11, c++14, c++17 -// TODO: make `join_view` non-experimental once D2770 is implemented. -// UNSUPPORTED: !c++experimental // UNSUPPORTED: GCC-ALWAYS_INLINE-FIXME // template<bidirectional_iterator I1, sentinel_for<I1> S1, bidirectional_iterator I2> diff --git a/libcxx/test/std/ranges/range.adaptors/range.join.view/iterator/ctor.parent.outer.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.join.view/iterator/ctor.parent.outer.pass.cpp deleted file mode 100644 index 215318f15cad0db..000000000000000 --- a/libcxx/test/std/ranges/range.adaptors/range.join.view/iterator/ctor.parent.outer.pass.cpp +++ /dev/null @@ -1,57 +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 -// UNSUPPORTED: !c++experimental - -// constexpr iterator(Parent& parent, OuterIter outer); - -#include <cassert> -#include <ranges> - -#include "../types.h" - -using NonDefaultCtrIter = cpp20_input_iterator<int*>; -static_assert(!std::default_initializable<NonDefaultCtrIter>); - -using NonDefaultCtrIterView = BufferView<NonDefaultCtrIter, sentinel_wrapper<NonDefaultCtrIter>>; -static_assert(std::ranges::input_range<NonDefaultCtrIterView>); - -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::iterator_t<decltype(jv)> iter(jv, std::ranges::begin(parent)); - assert(*iter == 1); - } - - { - // LWG3569 Inner iterator not default_initializable - // With the current spec, the constructor under test invokes Inner iterator's default constructor - // even if it is not default constructible - // This test is checking that this constructor can be invoked with an inner range with non default - // constructible iterator - NonDefaultCtrIterView inners[] = {buffer[0], buffer[1]}; - auto outer = std::views::all(inners); - std::ranges::join_view jv(outer); - std::ranges::iterator_t<decltype(jv)> iter(jv, std::ranges::begin(outer)); - assert(*iter == 1); - } - - return true; -} - -int main(int, char**) { - test(); - static_assert(test()); - - return 0; -} diff --git a/libcxx/test/std/ranges/range.adaptors/range.join.view/adaptor.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.join/adaptor.pass.cpp similarity index 99% rename from libcxx/test/std/ranges/range.adaptors/range.join.view/adaptor.pass.cpp rename to libcxx/test/std/ranges/range.adaptors/range.join/adaptor.pass.cpp index afaf32272109963..9beb3d282a27cc9 100644 --- a/libcxx/test/std/ranges/range.adaptors/range.join.view/adaptor.pass.cpp +++ b/libcxx/test/std/ranges/range.adaptors/range.join/adaptor.pass.cpp @@ -7,7 +7,6 @@ //===----------------------------------------------------------------------===// // UNSUPPORTED: c++03, c++11, c++14, c++17 -// UNSUPPORTED: !c++experimental // std::views::join diff --git a/libcxx/test/std/ranges/range.adaptors/range.join.view/base.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.join/base.pass.cpp similarity index 98% rename from libcxx/test/std/ranges/range.adaptors/range.join.view/base.pass.cpp rename to libcxx/test/std/ranges/range.adaptors/range.join/base.pass.cpp index 13883e894ac7bf9..caf018b582263a5 100644 --- a/libcxx/test/std/ranges/range.adaptors/range.join.view/base.pass.cpp +++ b/libcxx/test/std/ranges/range.adaptors/range.join/base.pass.cpp @@ -7,7 +7,6 @@ //===----------------------------------------------------------------------===// // UNSUPPORTED: c++03, c++11, c++14, c++17 -// UNSUPPORTED: !c++experimental // constexpr V base() const& requires copy_constructible<V>; // constexpr V base() &&; diff --git a/libcxx/test/std/ranges/range.adaptors/range.join.view/begin.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.join/begin.pass.cpp similarity index 83% rename from libcxx/test/std/ranges/range.adaptors/range.join.view/begin.pass.cpp rename to libcxx/test/std/ranges/range.adaptors/range.join/begin.pass.cpp index 9e4fa5f8c59a44a..005d0d1d2d5cb75 100644 --- a/libcxx/test/std/ranges/range.adaptors/range.join.view/begin.pass.cpp +++ b/libcxx/test/std/ranges/range.adaptors/range.join/begin.pass.cpp @@ -7,15 +7,17 @@ //===----------------------------------------------------------------------===// // UNSUPPORTED: c++03, c++11, c++14, c++17 -// UNSUPPORTED: !c++experimental // constexpr auto begin(); // constexpr auto begin() const -// requires input_range<const V> && -// is_reference_v<range_reference_t<const V>>; +// requires forward_range<const V> && +// is_reference_v<range_reference_t<const V>> && +// input_range<range_reference_t<const V>>; +#include <algorithm> #include <cassert> #include <ranges> +#include <string_view> #include "types.h" @@ -120,7 +122,7 @@ constexpr bool test() { static_assert(HasConstBegin<decltype(jv)>); } - // !input_range<const V> + // !forward_range<const V> { std::ranges::join_view jv{ConstNotRange{}}; static_assert(!HasConstBegin<decltype(jv)>); @@ -146,6 +148,27 @@ constexpr bool test() { static_assert(std::same_as<decltype(jv.begin()), decltype(std::as_const(jv).begin())>); } + // Check stashing iterators (LWG3698: regex_iterator and join_view don't work together very well) + { + std::ranges::join_view<StashingRange> jv; + assert(std::ranges::equal(std::views::counted(jv.begin(), 10), std::string_view{"aababcabcd"})); + } + + // LWG3700: The `const begin` of the `join_view` family does not require `InnerRng` to be a range + { + std::ranges::join_view<ConstNonJoinableRange> jv; + static_assert(!HasConstBegin<decltype(jv)>); + } + + // Check example from LWG3700 + { + auto r = std::views::iota(0, 5) | std::views::split(1); + auto s = std::views::single(r); + auto j = s | std::views::join; + auto f = j.front(); + assert(std::ranges::equal(f, std::views::single(0))); + } + return true; } diff --git a/libcxx/test/std/ranges/range.adaptors/range.join.view/ctad.compile.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.join/ctad.compile.pass.cpp similarity index 98% rename from libcxx/test/std/ranges/range.adaptors/range.join.view/ctad.compile.pass.cpp rename to libcxx/test/std/ranges/range.adaptors/range.join/ctad.compile.pass.cpp index 2c470991be0b6bc..a8eafc5a9c02111 100644 --- a/libcxx/test/std/ranges/range.adaptors/range.join.view/ctad.compile.pass.cpp +++ b/libcxx/test/std/ranges/range.adaptors/range.join/ctad.compile.pass.cpp @@ -7,7 +7,6 @@ //===----------------------------------------------------------------------===// // UNSUPPORTED: c++03, c++11, c++14, c++17 -// UNSUPPORTED: !c++experimental // template<class R> // explicit join_view(R&&) -> join_view<views::all_t<R>>; diff --git a/libcxx/test/std/ranges/range.adaptors/range.join.view/ctad.verify.cpp b/libcxx/test/std/ranges/range.adaptors/range.join/ctad.verify.cpp similarity index 97% rename from libcxx/test/std/ranges/range.adaptors/range.join.view/ctad.verify.cpp rename to libcxx/test/std/ranges/range.adaptors/range.join/ctad.verify.cpp index eddc950747ba768..2c6eea500580d6b 100644 --- a/libcxx/test/std/ranges/range.adaptors/range.join.view/ctad.verify.cpp +++ b/libcxx/test/std/ranges/range.adaptors/range.join/ctad.verify.cpp @@ -7,7 +7,6 @@ //===----------------------------------------------------------------------===// // UNSUPPORTED: c++03, c++11, c++14, c++17 -// UNSUPPORTED: !c++experimental // template<class R> // explicit join_view(R&&) -> join_view<views::all_t<R>>; diff --git a/libcxx/test/std/ranges/range.adaptors/range.join.view/ctor.default.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.join/ctor.default.pass.cpp similarity index 97% rename from libcxx/test/std/ranges/range.adaptors/range.join.view/ctor.default.pass.cpp rename to libcxx/test/std/ranges/range.adaptors/range.join/ctor.default.pass.cpp index 26206e32c358cec..0daff7d3b3c98ab 100644 --- a/libcxx/test/std/ranges/range.adaptors/range.join.view/ctor.default.pass.cpp +++ b/libcxx/test/std/ranges/range.adaptors/range.join/ctor.default.pass.cpp @@ -7,7 +7,6 @@ //===----------------------------------------------------------------------===// // UNSUPPORTED: c++03, c++11, c++14, c++17 -// UNSUPPORTED: !c++experimental // join_view() requires default_initializable<V> = default; diff --git a/libcxx/test/std/ranges/range.adaptors/range.join.view/ctor.view.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.join/ctor.view.pass.cpp similarity index 97% rename from libcxx/test/std/ranges/range.adaptors/range.join.view/ctor.view.pass.cpp rename to libcxx/test/std/ranges/range.adaptors/range.join/ctor.view.pass.cpp index ce5393062d77814..75d4c7e5916b0a5 100644 --- a/libcxx/test/std/ranges/range.adaptors/range.join.view/ctor.view.pass.cpp +++ b/libcxx/test/std/ranges/range.adaptors/range.join/ctor.view.pass.cpp @@ -7,7 +7,6 @@ //===----------------------------------------------------------------------===// // UNSUPPORTED: c++03, c++11, c++14, c++17 -// UNSUPPORTED: !c++experimental // constexpr explicit join_view(V base); diff --git a/libcxx/test/std/ranges/range.adaptors/range.join.view/end.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.join/end.pass.cpp similarity index 95% rename from libcxx/test/std/ranges/range.adaptors/range.join.view/end.pass.cpp rename to libcxx/test/std/ranges/range.adaptors/range.join/end.pass.cpp index 7e225202cc23127..516ba25a0e8596d 100644 --- a/libcxx/test/std/ranges/range.adaptors/range.join.view/end.pass.cpp +++ b/libcxx/test/std/ranges/range.adaptors/range.join/end.pass.cpp @@ -7,10 +7,12 @@ //===----------------------------------------------------------------------===// // UNSUPPORTED: c++03, c++11, c++14, c++17 -// UNSUPPORTED: !c++experimental // constexpr auto end(); // constexpr auto end() const; +// requires forward_range<const V> && +// is_reference_v<range_reference_t<const V>> && +// input_range<range_reference_t<const V>> #include <cassert> #include <ranges> @@ -33,13 +35,13 @@ concept HasConstEnd = requires (const T& t){ // | 3 | Y | Y | Y | Y | N | Y |sentinel<true> |sentinel<true>| // | 4 | Y | Y | Y | N | Y | Y |sentinel<true> | - | // | 5 | Y | Y | N | Y | Y | Y |sentinel<true> |sentinel<true>| -// | 6 | Y | N | Y | Y | Y | Y |sentinel<true> |sentinel<true>| +// | 6 | Y | N | Y | Y | Y | Y |sentinel<true> | - | // | 7 | N | Y | Y | Y | Y | Y |iterator<false>|iterator<true>| // | 8 | N | Y | Y | Y | Y | N |sentinel<false>|sentinel<true>| // | 9 | N | Y | Y | Y | N | Y |sentinel<false>|sentinel<true>| // | 10 | N | Y | Y | N | Y | Y |sentinel<false>| - | // | 11 | N | Y | N | Y | Y | Y |sentinel<false>|sentinel<true>| -// | 12 | N | N | Y | Y | Y | Y |sentinel<false>|sentinel<true>| +// | 12 | N | N | Y | Y | Y | Y |sentinel<false>| - | // // @@ -131,10 +133,8 @@ constexpr bool test() { std::ranges::join_view jv(outer); assert(jv.end() == std::ranges::next(jv.begin(), 16)); - assert(std::as_const(jv).end() == std::ranges::next(std::as_const(jv).begin(), 16)); - static_assert(HasConstEnd<decltype(jv)>); - static_assert(std::same_as<decltype(jv.end()), decltype(std::as_const(jv).end())>); + static_assert(!HasConstEnd<decltype(jv)>); static_assert(!std::ranges::common_range<decltype(jv)>); static_assert(!std::ranges::common_range<const decltype(jv)>); } @@ -219,10 +219,8 @@ constexpr bool test() { std::ranges::join_view jv(outer); assert(jv.end() == std::ranges::next(jv.begin(), 16)); - assert(std::as_const(jv).end() == std::ranges::next(std::as_const(jv).begin(), 16)); - static_assert(HasConstEnd<decltype(jv)>); - static_assert(!std::same_as<decltype(jv.end()), decltype(std::as_const(jv).end())>); + static_assert(!HasConstEnd<decltype(jv)>); static_assert(!std::ranges::common_range<decltype(jv)>); static_assert(!std::ranges::common_range<const decltype(jv)>); } @@ -288,6 +286,12 @@ constexpr bool test() { assert(jv.end() == std::ranges::next(jv.begin(), 12)); } + // LWG3700: The `const begin` of the `join_view` family does not require `InnerRng` to be a range + { + std::ranges::join_view<ConstNonJoinableRange> jv; + static_assert(!HasConstEnd<decltype(jv)>); + } + return true; } diff --git a/libcxx/test/std/ranges/range.adaptors/range.join.view/general.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.join/general.pass.cpp similarity index 98% rename from libcxx/test/std/ranges/range.adaptors/range.join.view/general.pass.cpp rename to libcxx/test/std/ranges/range.adaptors/range.join/general.pass.cpp index e9eab585260cdc9..f92eb418fac77c8 100644 --- a/libcxx/test/std/ranges/range.adaptors/range.join.view/general.pass.cpp +++ b/libcxx/test/std/ranges/range.adaptors/range.join/general.pass.cpp @@ -7,7 +7,6 @@ //===----------------------------------------------------------------------===// // UNSUPPORTED: c++03, c++11, c++14, c++17 -// UNSUPPORTED: !c++experimental // General tests for join_view. This file does not test anything specifically. diff --git a/libcxx/test/std/ranges/range.adaptors/range.join.view/iterator/arrow.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.join/range.join.iterator/arrow.pass.cpp similarity index 99% rename from libcxx/test/std/ranges/range.adaptors/range.join.view/iterator/arrow.pass.cpp rename to libcxx/test/std/ranges/range.adaptors/range.join/range.join.iterator/arrow.pass.cpp index e610cde2c3b5bec..ddcf66bfe775e7d 100644 --- a/libcxx/test/std/ranges/range.adaptors/range.join.view/iterator/arrow.pass.cpp +++ b/libcxx/test/std/ranges/range.adaptors/range.join/range.join.iterator/arrow.pass.cpp @@ -7,7 +7,6 @@ //===----------------------------------------------------------------------===// // UNSUPPORTED: c++03, c++11, c++14, c++17 -// UNSUPPORTED: !c++experimental // constexpr InnerIter operator->() const // requires has-arrow<InnerIter> && copyable<InnerIter>; diff --git a/libcxx/test/std/ranges/range.adaptors/range.join.view/iterator/ctor.default.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.join/range.join.iterator/ctor.default.pass.cpp similarity index 70% rename from libcxx/test/std/ranges/range.adaptors/range.join.view/iterator/ctor.default.pass.cpp rename to libcxx/test/std/ranges/range.adaptors/range.join/range.join.iterator/ctor.default.pass.cpp index e4f193e4e606421..82fe824fad1b2a4 100644 --- a/libcxx/test/std/ranges/range.adaptors/range.join.view/iterator/ctor.default.pass.cpp +++ b/libcxx/test/std/ranges/range.adaptors/range.join/range.join.iterator/ctor.default.pass.cpp @@ -7,9 +7,8 @@ //===----------------------------------------------------------------------===// // UNSUPPORTED: c++03, c++11, c++14, c++17 -// UNSUPPORTED: !c++experimental -// iterator() requires default_initializable<OuterIter> = default; +// iterator() = default; #include <ranges> @@ -29,19 +28,12 @@ constexpr void test_default_constructible() { using JoinView = std::ranges::join_view<view<It>>; using JoinIterator = std::ranges::iterator_t<JoinView>; static_assert(std::is_default_constructible_v<JoinIterator>); - JoinIterator it; (void)it; -} - -template <class It> -constexpr void test_non_default_constructible() { - using JoinView = std::ranges::join_view<view<It>>; - using JoinIterator = std::ranges::iterator_t<JoinView>; - static_assert(!std::is_default_constructible_v<JoinIterator>); + [[maybe_unused]] JoinIterator it; } constexpr bool test() { - test_non_default_constructible<cpp17_input_iterator<ChildView*>>(); - // NOTE: cpp20_input_iterator can't be used with join_view because it is not copyable. + test_default_constructible<cpp17_input_iterator<ChildView*>>(); + test_default_constructible<cpp20_input_iterator<ChildView*>>(); test_default_constructible<forward_iterator<ChildView*>>(); test_default_constructible<bidirectional_iterator<ChildView*>>(); test_default_constructible<random_access_iterator<ChildView*>>(); diff --git a/libcxx/test/std/ranges/range.adaptors/range.join.view/iterator/ctor.other.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.join/range.join.iterator/ctor.other.pass.cpp similarity index 97% rename from libcxx/test/std/ranges/range.adaptors/range.join.view/iterator/ctor.other.pass.cpp rename to libcxx/test/std/ranges/range.adaptors/range.join/range.join.iterator/ctor.other.pass.cpp index a0406f90c88c639..e220b2cfeac84aa 100644 --- a/libcxx/test/std/ranges/range.adaptors/range.join.view/iterator/ctor.other.pass.cpp +++ b/libcxx/test/std/ranges/range.adaptors/range.join/range.join.iterator/ctor.other.pass.cpp @@ -7,7 +7,6 @@ //===----------------------------------------------------------------------===// // UNSUPPORTED: c++03, c++11, c++14, c++17 -// UNSUPPORTED: !c++experimental // constexpr iterator(iterator<!Const> i) // requires Const && @@ -37,7 +36,7 @@ constexpr bool test() { { CopyableChild children[4] = {CopyableChild(buffer[0]), CopyableChild(buffer[1]), CopyableChild(buffer[2]), CopyableChild(buffer[3])}; - std::ranges::join_view jv(CopyableParent{children}); + std::ranges::join_view jv(ForwardCopyableParent{children}); auto iter1 = jv.begin(); using iterator = decltype(iter1); using const_iterator = decltype(std::as_const(jv).begin()); diff --git a/libcxx/test/std/ranges/range.adaptors/range.join.view/iterator/decrement.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.join/range.join.iterator/decrement.pass.cpp similarity index 90% rename from libcxx/test/std/ranges/range.adaptors/range.join.view/iterator/decrement.pass.cpp rename to libcxx/test/std/ranges/range.adaptors/range.join/range.join.iterator/decrement.pass.cpp index 4363fb0e330c3b9..29720d93bab66f1 100644 --- a/libcxx/test/std/ranges/range.adaptors/range.join.view/iterator/decrement.pass.cpp +++ b/libcxx/test/std/ranges/range.adaptors/range.join/range.join.iterator/decrement.pass.cpp @@ -7,7 +7,6 @@ //===----------------------------------------------------------------------===// // UNSUPPORTED: c++03, c++11, c++14, c++17 -// UNSUPPORTED: !c++experimental // constexpr iterator& operator--(); // requires ref-is-glvalue && bidirectional_range<Base> && @@ -18,9 +17,12 @@ // bidirectional_range<range_reference_t<Base>> && // common_range<range_reference_t<Base>>; +#include <algorithm> +#include <array> #include <cassert> #include <ranges> #include <type_traits> +#include <vector> #include "../types.h" @@ -150,6 +152,15 @@ constexpr bool test() { static_assert(!CanPostDecrement<decltype(iter)>); } + { + // LWG3791: `join_view::iterator::operator--` may be ill-formed + std::vector<std::vector<int>> vec = {{1, 2}, {3, 4}, {5, 6}}; + auto r = vec | std::views::transform([](auto& x) -> auto&& { return std::move(x); }) | std::views::join; + auto e = --r.end(); + assert(*e == 6); + assert(std::ranges::equal(std::views::reverse(r), std::array{6, 5, 4, 3, 2, 1})); + } + return true; } diff --git a/libcxx/test/std/ranges/range.adaptors/range.join.view/iterator/eq.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.join/range.join.iterator/eq.pass.cpp similarity index 89% rename from libcxx/test/std/ranges/range.adaptors/range.join.view/iterator/eq.pass.cpp rename to libcxx/test/std/ranges/range.adaptors/range.join/range.join.iterator/eq.pass.cpp index 327cc82b06b085b..8b7e694b080f47f 100644 --- a/libcxx/test/std/ranges/range.adaptors/range.join.view/iterator/eq.pass.cpp +++ b/libcxx/test/std/ranges/range.adaptors/range.join/range.join.iterator/eq.pass.cpp @@ -7,10 +7,9 @@ //===----------------------------------------------------------------------===// // UNSUPPORTED: c++03, c++11, c++14, c++17 -// UNSUPPORTED: !c++experimental // friend constexpr bool operator==(const iterator& x, const iterator& y); -// requires ref-is-glvalue && equality_comparable<iterator_t<Base>> && +// requires ref-is-glvalue && forward_range<Base> && // equality_comparable<iterator_t<range_reference_t<Base>>>; #include <cassert> @@ -43,7 +42,7 @@ constexpr bool test() { } { - // !equality_comparable<iterator_t<Base>> + // !forward_range<iterator_t<Base>> using Inner = BufferView<int*>; using Outer = BufferView<cpp20_input_iterator<Inner*>, sentinel_wrapper<cpp20_input_iterator<Inner*>>>; static_assert(!std::equality_comparable<std::ranges::iterator_t<Outer>>); @@ -51,8 +50,6 @@ constexpr bool test() { std::ranges::join_view jv(Outer{inners}); auto iter = jv.begin(); static_assert(!std::equality_comparable<decltype(iter)>); - auto const_iter = std::as_const(jv).begin(); - static_assert(!std::equality_comparable<decltype(const_iter)>); } { diff --git a/libcxx/test/std/ranges/range.adaptors/range.join.view/iterator/increment.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.join/range.join.iterator/increment.pass.cpp similarity index 94% rename from libcxx/test/std/ranges/range.adaptors/range.join.view/iterator/increment.pass.cpp rename to libcxx/test/std/ranges/range.adaptors/range.join/range.join.iterator/increment.pass.cpp index 4bcb4de7e9c8868..dada91462a73fff 100644 --- a/libcxx/test/std/ranges/range.adaptors/range.join.view/iterator/increment.pass.cpp +++ b/libcxx/test/std/ranges/range.adaptors/range.join/range.join.iterator/increment.pass.cpp @@ -7,7 +7,6 @@ //===----------------------------------------------------------------------===// // UNSUPPORTED: c++03, c++11, c++14, c++17 -// UNSUPPORTED: !c++experimental // constexpr iterator& operator++(); // constexpr void operator++(int); @@ -205,6 +204,23 @@ constexpr bool test() { static_assert(std::is_void_v<decltype(iter++)>); } + { + // Check stashing iterators (LWG3698: regex_iterator and join_view don't work together very well) + std::ranges::join_view<StashingRange> jv; + auto it = jv.begin(); + assert(*it == 'a'); + ++it; + assert(*it == 'a'); + ++it; + assert(*it == 'b'); + it++; + assert(*it == 'a'); + it++; + assert(*it == 'b'); + ++it; + assert(*it == 'c'); + } + return true; } diff --git a/libcxx/test/std/ranges/range.adaptors/range.join.view/iterator/iter.move.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.join/range.join.iterator/iter.move.pass.cpp similarity index 98% rename from libcxx/test/std/ranges/range.adaptors/range.join.view/iterator/iter.move.pass.cpp rename to libcxx/test/std/ranges/range.adaptors/range.join/range.join.iterator/iter.move.pass.cpp index 0bf6aa3d926146e..917e72dc858545c 100644 --- a/libcxx/test/std/ranges/range.adaptors/range.join.view/iterator/iter.move.pass.cpp +++ b/libcxx/test/std/ranges/range.adaptors/range.join/range.join.iterator/iter.move.pass.cpp @@ -7,7 +7,6 @@ //===----------------------------------------------------------------------===// // UNSUPPORTED: c++03, c++11, c++14, c++17 -// UNSUPPORTED: !c++experimental // friend constexpr decltype(auto) iter_move(const iterator& i); diff --git a/libcxx/test/std/ranges/range.adaptors/range.join.view/iterator/iter.swap.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.join/range.join.iterator/iter.swap.pass.cpp similarity index 98% rename from libcxx/test/std/ranges/range.adaptors/range.join.view/iterator/iter.swap.pass.cpp rename to libcxx/test/std/ranges/range.adaptors/range.join/range.join.iterator/iter.swap.pass.cpp index e9b73f1a415966a..28e1bf75726f639 100644 --- a/libcxx/test/std/ranges/range.adaptors/range.join.view/iterator/iter.swap.pass.cpp +++ b/libcxx/test/std/ranges/range.adaptors/range.join/range.join.iterator/iter.swap.pass.cpp @@ -7,7 +7,6 @@ //===----------------------------------------------------------------------===// // UNSUPPORTED: c++03, c++11, c++14, c++17 -// UNSUPPORTED: !c++experimental // friend constexpr void iter_swap(const iterator& x, const iterator& y); diff --git a/libcxx/test/std/ranges/range.adaptors/range.join.view/iterator/member_types.compile.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.join/range.join.iterator/member_types.compile.pass.cpp similarity index 99% rename from libcxx/test/std/ranges/range.adaptors/range.join.view/iterator/member_types.compile.pass.cpp rename to libcxx/test/std/ranges/range.adaptors/range.join/range.join.iterator/member_types.compile.pass.cpp index 17b98facd65081d..b9b9d73d77e2655 100644 --- a/libcxx/test/std/ranges/range.adaptors/range.join.view/iterator/member_types.compile.pass.cpp +++ b/libcxx/test/std/ranges/range.adaptors/range.join/range.join.iterator/member_types.compile.pass.cpp @@ -7,7 +7,6 @@ //===----------------------------------------------------------------------===// // UNSUPPORTED: c++03, c++11, c++14, c++17 -// UNSUPPORTED: !c++experimental // Iterator traits and member typedefs in join_view::<iterator>. diff --git a/libcxx/test/std/ranges/range.adaptors/range.join.view/iterator/star.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.join/range.join.iterator/star.pass.cpp similarity index 97% rename from libcxx/test/std/ranges/range.adaptors/range.join.view/iterator/star.pass.cpp rename to libcxx/test/std/ranges/range.adaptors/range.join/range.join.iterator/star.pass.cpp index fa6f7bb031207a3..73457b826df0b04 100644 --- a/libcxx/test/std/ranges/range.adaptors/range.join.view/iterator/star.pass.cpp +++ b/libcxx/test/std/ranges/range.adaptors/range.join/range.join.iterator/star.pass.cpp @@ -7,7 +7,6 @@ //===----------------------------------------------------------------------===// // UNSUPPORTED: c++03, c++11, c++14, c++17 -// UNSUPPORTED: !c++experimental // constexpr decltype(auto) operator*() const; diff --git a/libcxx/test/std/ranges/range.adaptors/range.join.view/sentinel/ctor.default.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.join/range.join.sentinel/ctor.default.pass.cpp similarity index 95% rename from libcxx/test/std/ranges/range.adaptors/range.join.view/sentinel/ctor.default.pass.cpp rename to libcxx/test/std/ranges/range.adaptors/range.join/range.join.sentinel/ctor.default.pass.cpp index 0eebe14af3fcba3..42fcc733e181f4f 100644 --- a/libcxx/test/std/ranges/range.adaptors/range.join.view/sentinel/ctor.default.pass.cpp +++ b/libcxx/test/std/ranges/range.adaptors/range.join/range.join.sentinel/ctor.default.pass.cpp @@ -7,7 +7,6 @@ //===----------------------------------------------------------------------===// // UNSUPPORTED: c++03, c++11, c++14, c++17 -// UNSUPPORTED: !c++experimental // sentinel() = default; diff --git a/libcxx/test/std/ranges/range.adaptors/range.join.view/sentinel/ctor.other.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.join/range.join.sentinel/ctor.other.pass.cpp similarity index 99% rename from libcxx/test/std/ranges/range.adaptors/range.join.view/sentinel/ctor.other.pass.cpp rename to libcxx/test/std/ranges/range.adaptors/range.join/range.join.sentinel/ctor.other.pass.cpp index c2d7058746d758b..4bd8025efb5c1b3 100644 --- a/libcxx/test/std/ranges/range.adaptors/range.join.view/sentinel/ctor.other.pass.cpp +++ b/libcxx/test/std/ranges/range.adaptors/range.join/range.join.sentinel/ctor.other.pass.cpp @@ -7,7 +7,6 @@ //===----------------------------------------------------------------------===// // UNSUPPORTED: c++03, c++11, c++14, c++17 -// UNSUPPORTED: !c++experimental // constexpr sentinel(sentinel<!Const> s); // requires Const && convertible_to<sentinel_t<V>, sentinel_t<Base>>; diff --git a/libcxx/test/std/ranges/range.adaptors/range.join.view/sentinel/ctor.parent.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.join/range.join.sentinel/ctor.parent.pass.cpp similarity index 97% rename from libcxx/test/std/ranges/range.adaptors/range.join.view/sentinel/ctor.parent.pass.cpp rename to libcxx/test/std/ranges/range.adaptors/range.join/range.join.sentinel/ctor.parent.pass.cpp index a9df7c3881ba8f9..1ac68277338fee2 100644 --- a/libcxx/test/std/ranges/range.adaptors/range.join.view/sentinel/ctor.parent.pass.cpp +++ b/libcxx/test/std/ranges/range.adaptors/range.join/range.join.sentinel/ctor.parent.pass.cpp @@ -7,7 +7,6 @@ //===----------------------------------------------------------------------===// // UNSUPPORTED: c++03, c++11, c++14, c++17 -// UNSUPPORTED: !c++experimental // constexpr explicit sentinel(Parent& parent); diff --git a/libcxx/test/std/ranges/range.adaptors/range.join.view/sentinel/eq.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.join/range.join.sentinel/eq.pass.cpp similarity index 81% rename from libcxx/test/std/ranges/range.adaptors/range.join.view/sentinel/eq.pass.cpp rename to libcxx/test/std/ranges/range.adaptors/range.join/range.join.sentinel/eq.pass.cpp index cbd03b84f208b9f..bc7d4bec94d3e63 100644 --- a/libcxx/test/std/ranges/range.adaptors/range.join.view/sentinel/eq.pass.cpp +++ b/libcxx/test/std/ranges/range.adaptors/range.join/range.join.sentinel/eq.pass.cpp @@ -7,7 +7,6 @@ //===----------------------------------------------------------------------===// // UNSUPPORTED: c++03, c++11, c++14, c++17 -// UNSUPPORTED: !c++experimental // template<bool OtherConst> // requires sentinel_for<sentinel_t<Base>, iterator_t<maybe-const<OtherConst, V>>> @@ -17,6 +16,7 @@ #include <concepts> #include <functional> #include <ranges> +#include <type_traits> #include "../types.h" @@ -61,18 +61,27 @@ static_assert(EqualityComparable<std::ranges::iterator_t<const ConstComparableVi constexpr bool test() { int buffer[4][4] = {{1111, 2222, 3333, 4444}, {555, 666, 777, 888}, {99, 1010, 1111, 1212}, {13, 14, 15, 16}}; + // test iterator<false> == sentinel<false> { ChildView children[4] = {ChildView(buffer[0]), ChildView(buffer[1]), ChildView(buffer[2]), ChildView(buffer[3])}; - auto jv = std::ranges::join_view(ParentView(children)); + auto jv = std::ranges::join_view(ParentView(children)); assert(jv.end() == std::ranges::next(jv.begin(), 16)); - static_assert(!EqualityComparable<decltype(std::as_const(jv).begin()), decltype(jv.end())>); - static_assert(!EqualityComparable<decltype(jv.begin()), decltype(std::as_const(jv).end())>); } + // test iterator<false> == sentinel<true> + { + ChildView children[4] = {ChildView(buffer[0]), ChildView(buffer[1]), ChildView(buffer[2]), ChildView(buffer[3])}; + using ParentT = std::remove_all_extents_t<decltype(children)>; + auto jv = std::ranges::join_view(ForwardParentView<ParentT>(children)); + assert(std::as_const(jv).end() == std::ranges::next(jv.begin(), 16)); + } + + // test iterator<true> == sentinel<true> { CopyableChild children[4] = {CopyableChild(buffer[0]), CopyableChild(buffer[1]), CopyableChild(buffer[2]), CopyableChild(buffer[3])}; - const auto jv = std::ranges::join_view(ParentView(children)); + using ParentT = std::remove_all_extents_t<decltype(children)>; + const auto jv = std::ranges::join_view(ForwardParentView<ParentT>(children)); assert(jv.end() == std::ranges::next(jv.begin(), 16)); } diff --git a/libcxx/test/std/ranges/range.adaptors/range.join.view/types.h b/libcxx/test/std/ranges/range.adaptors/range.join/types.h similarity index 88% rename from libcxx/test/std/ranges/range.adaptors/range.join.view/types.h rename to libcxx/test/std/ranges/range.adaptors/range.join/types.h index b2ef5f090b5731d..c1378dc1144b403 100644 --- a/libcxx/test/std/ranges/range.adaptors/range.join.view/types.h +++ b/libcxx/test/std/ranges/range.adaptors/range.join/types.h @@ -11,6 +11,7 @@ #include <concepts> #include <cstdint> +#include <string> #include <tuple> #include "test_macros.h" @@ -52,13 +53,13 @@ inline ChildView globalChildren[4] = { ChildView(globalBuffer[3]), }; -template <class T> +template <class T, template<class...> class Iter = cpp17_input_iterator> struct ParentView : std::ranges::view_base { T* ptr_; unsigned size_; - using iterator = cpp20_input_iterator<T*>; - using const_iterator = cpp20_input_iterator<const T*>; + using iterator = Iter<T*>; + using const_iterator = Iter<const T*>; using sentinel = sentinel_wrapper<iterator>; using const_sentinel = sentinel_wrapper<const_iterator>; @@ -80,6 +81,9 @@ struct ParentView : std::ranges::view_base { template <class T> ParentView(T*) -> ParentView<T>; +template<class T> +using ForwardParentView = ParentView<T, forward_iterator>; + struct CopyableChild : std::ranges::view_base { int* ptr_; unsigned size_; @@ -97,15 +101,16 @@ struct CopyableChild : std::ranges::view_base { constexpr const_sentinel end() const { return const_sentinel(const_iterator(ptr_ + size_)); } }; -struct CopyableParent : std::ranges::view_base { +template<template<class...> class Iter> +struct CopyableParentTemplate : std::ranges::view_base { CopyableChild* ptr_; - using iterator = cpp17_input_iterator<CopyableChild*>; - using const_iterator = cpp17_input_iterator<const CopyableChild*>; + using iterator = Iter<CopyableChild*>; + using const_iterator = Iter<const CopyableChild*>; using sentinel = sentinel_wrapper<iterator>; using const_sentinel = sentinel_wrapper<const_iterator>; - constexpr CopyableParent(CopyableChild* ptr) : ptr_(ptr) {} + constexpr CopyableParentTemplate(CopyableChild* ptr) : ptr_(ptr) {} constexpr iterator begin() { return iterator(ptr_); } constexpr const_iterator begin() const { return const_iterator(ptr_); } @@ -113,6 +118,9 @@ struct CopyableParent : std::ranges::view_base { constexpr const_sentinel end() const { return const_sentinel(const_iterator(ptr_ + 4)); } }; +using CopyableParent = CopyableParentTemplate<cpp17_input_iterator>; +using ForwardCopyableParent = CopyableParentTemplate<forward_iterator>; + struct Box { int x; }; @@ -392,4 +400,48 @@ struct IterMoveSwapAwareView : BufferView<int*> { }; static_assert(std::ranges::input_range<IterMoveSwapAwareView>); +class StashingIterator { +public: + using difference_type = std::ptrdiff_t; + using value_type = std::string; + + constexpr StashingIterator() : letter_('a') {} + + constexpr StashingIterator& operator++() { + str_ += letter_; + ++letter_; + return *this; + } + + constexpr void operator++(int) { ++*this; } + + constexpr value_type operator*() const { return str_; } + + constexpr bool operator==(std::default_sentinel_t) const { return letter_ > 'z'; } + +private: + char letter_; + value_type str_; +}; + +using StashingRange = std::ranges::subrange<StashingIterator, std::default_sentinel_t>; +static_assert(std::ranges::input_range<StashingRange>); +static_assert(!std::ranges::forward_range<StashingRange>); + +class ConstNonJoinableRange : public std::ranges::view_base { +public: + constexpr StashingIterator begin() { return {}; } + constexpr std::default_sentinel_t end() { return {}; } + + constexpr const int* begin() const { return &val_; } + constexpr const int* end() const { return &val_ + 1; } + +private: + int val_ = 1; +}; +static_assert(std::ranges::input_range<ConstNonJoinableRange>); +static_assert(std::ranges::input_range<const ConstNonJoinableRange>); +static_assert(std::ranges::input_range<std::ranges::range_reference_t<ConstNonJoinableRange>>); +static_assert(!std::ranges::input_range<std::ranges::range_reference_t<const ConstNonJoinableRange>>); + #endif // TEST_STD_RANGES_RANGE_ADAPTORS_RANGE_JOIN_TYPES_H diff --git a/libcxx/test/std/re/re.iter/re.regiter/iterator_concept_conformance.compile.pass.cpp b/libcxx/test/std/re/re.iter/re.regiter/iterator_concept_conformance.compile.pass.cpp index 6f2da091c3709b3..ad61baa76018da8 100644 --- a/libcxx/test/std/re/re.iter/re.regiter/iterator_concept_conformance.compile.pass.cpp +++ b/libcxx/test/std/re/re.iter/re.regiter/iterator_concept_conformance.compile.pass.cpp @@ -14,8 +14,8 @@ #include <iterator> -static_assert(std::forward_iterator<std::cregex_iterator>); -static_assert(!std::bidirectional_iterator<std::cregex_iterator>); +static_assert(std::input_iterator<std::cregex_iterator>); +static_assert(!std::forward_iterator<std::cregex_iterator>); static_assert(!std::indirectly_writable<std::cregex_iterator, char>); static_assert(std::sentinel_for<std::cregex_iterator, std::cregex_iterator>); static_assert(!std::sized_sentinel_for<std::cregex_iterator, std::cregex_iterator>); diff --git a/libcxx/test/std/re/re.iter/re.regiter/types.pass.cpp b/libcxx/test/std/re/re.iter/re.regiter/types.pass.cpp index 7d30b0adcc234c3..8ee2c5006d31c4a 100644 --- a/libcxx/test/std/re/re.iter/re.regiter/types.pass.cpp +++ b/libcxx/test/std/re/re.iter/re.regiter/types.pass.cpp @@ -20,6 +20,7 @@ // typedef const value_type* pointer; // typedef const value_type& reference; // typedef forward_iterator_tag iterator_category; +// typedef input_iterator_tag iterator_concept; // since C++20 #include <regex> #include <type_traits> @@ -36,6 +37,9 @@ test() static_assert((std::is_same<typename I::pointer, const std::match_results<const CharT*>*>::value), ""); static_assert((std::is_same<typename I::reference, const std::match_results<const CharT*>&>::value), ""); static_assert((std::is_same<typename I::iterator_category, std::forward_iterator_tag>::value), ""); +#if TEST_STD_VER >= 20 + static_assert(std::is_same_v<typename I::iterator_concept, std::input_iterator_tag>); +#endif } int main(int, char**) diff --git a/libcxx/test/std/re/re.iter/re.tokiter/iterator_concept_conformance.compile.pass.cpp b/libcxx/test/std/re/re.iter/re.tokiter/iterator_concept_conformance.compile.pass.cpp index 397226552edee07..23eea7f369c170d 100644 --- a/libcxx/test/std/re/re.iter/re.tokiter/iterator_concept_conformance.compile.pass.cpp +++ b/libcxx/test/std/re/re.iter/re.tokiter/iterator_concept_conformance.compile.pass.cpp @@ -14,8 +14,8 @@ #include <iterator> -static_assert(std::forward_iterator<std::cregex_token_iterator>); -static_assert(!std::bidirectional_iterator<std::cregex_token_iterator>); +static_assert(std::input_iterator<std::cregex_token_iterator>); +static_assert(!std::forward_iterator<std::cregex_token_iterator>); static_assert(!std::indirectly_writable<std::cregex_token_iterator, char>); static_assert(std::sentinel_for<std::cregex_token_iterator, std::cregex_token_iterator>); static_assert(!std::sized_sentinel_for<std::cregex_token_iterator, std::cregex_token_iterator>); diff --git a/libcxx/test/std/re/re.iter/re.tokiter/types.pass.cpp b/libcxx/test/std/re/re.iter/re.tokiter/types.pass.cpp index 73ad58f4eecfb6a..a9c18e8a1b77a16 100644 --- a/libcxx/test/std/re/re.iter/re.tokiter/types.pass.cpp +++ b/libcxx/test/std/re/re.iter/re.tokiter/types.pass.cpp @@ -20,6 +20,7 @@ // typedef const value_type* pointer; // typedef const value_type& reference; // typedef forward_iterator_tag iterator_category; +// typedef input_iterator_tag iterator_concept; // since C++20 #include <regex> #include <type_traits> @@ -36,6 +37,9 @@ test() static_assert((std::is_same<typename I::pointer, const std::sub_match<const CharT*>*>::value), ""); static_assert((std::is_same<typename I::reference, const std::sub_match<const CharT*>&>::value), ""); static_assert((std::is_same<typename I::iterator_category, std::forward_iterator_tag>::value), ""); +#if TEST_STD_VER >= 20 + static_assert(std::is_same_v<typename I::iterator_concept, std::input_iterator_tag>); +#endif } int main(int, char**) diff --git a/libcxx/utils/data/ignore_format.txt b/libcxx/utils/data/ignore_format.txt index 123d06d56e29a5b..c10745ce3edadf2 100644 --- a/libcxx/utils/data/ignore_format.txt +++ b/libcxx/utils/data/ignore_format.txt @@ -5209,29 +5209,28 @@ libcxx/test/std/ranges/range.adaptors/range.filter/sentinel/compare.pass.cpp libcxx/test/std/ranges/range.adaptors/range.filter/sentinel/ctor.default.pass.cpp libcxx/test/std/ranges/range.adaptors/range.filter/sentinel/ctor.parent.pass.cpp libcxx/test/std/ranges/range.adaptors/range.filter/types.h -libcxx/test/std/ranges/range.adaptors/range.join.view/adaptor.pass.cpp -libcxx/test/std/ranges/range.adaptors/range.join.view/base.pass.cpp -libcxx/test/std/ranges/range.adaptors/range.join.view/begin.pass.cpp -libcxx/test/std/ranges/range.adaptors/range.join.view/ctad.compile.pass.cpp -libcxx/test/std/ranges/range.adaptors/range.join.view/ctad.verify.cpp -libcxx/test/std/ranges/range.adaptors/range.join.view/ctor.default.pass.cpp -libcxx/test/std/ranges/range.adaptors/range.join.view/ctor.view.pass.cpp -libcxx/test/std/ranges/range.adaptors/range.join.view/end.pass.cpp -libcxx/test/std/ranges/range.adaptors/range.join.view/general.pass.cpp -libcxx/test/std/ranges/range.adaptors/range.join.view/iterator/arrow.pass.cpp -libcxx/test/std/ranges/range.adaptors/range.join.view/iterator/ctor.default.pass.cpp -libcxx/test/std/ranges/range.adaptors/range.join.view/iterator/ctor.other.pass.cpp -libcxx/test/std/ranges/range.adaptors/range.join.view/iterator/ctor.parent.outer.pass.cpp -libcxx/test/std/ranges/range.adaptors/range.join.view/iterator/decrement.pass.cpp -libcxx/test/std/ranges/range.adaptors/range.join.view/iterator/eq.pass.cpp -libcxx/test/std/ranges/range.adaptors/range.join.view/iterator/increment.pass.cpp -libcxx/test/std/ranges/range.adaptors/range.join.view/iterator/member_types.compile.pass.cpp -libcxx/test/std/ranges/range.adaptors/range.join.view/iterator/star.pass.cpp -libcxx/test/std/ranges/range.adaptors/range.join.view/sentinel/ctor.default.pass.cpp -libcxx/test/std/ranges/range.adaptors/range.join.view/sentinel/ctor.other.pass.cpp -libcxx/test/std/ranges/range.adaptors/range.join.view/sentinel/ctor.parent.pass.cpp -libcxx/test/std/ranges/range.adaptors/range.join.view/sentinel/eq.pass.cpp -libcxx/test/std/ranges/range.adaptors/range.join.view/types.h +libcxx/test/std/ranges/range.adaptors/range.join/adaptor.pass.cpp +libcxx/test/std/ranges/range.adaptors/range.join/base.pass.cpp +libcxx/test/std/ranges/range.adaptors/range.join/begin.pass.cpp +libcxx/test/std/ranges/range.adaptors/range.join/ctad.compile.pass.cpp +libcxx/test/std/ranges/range.adaptors/range.join/ctad.verify.cpp +libcxx/test/std/ranges/range.adaptors/range.join/ctor.default.pass.cpp +libcxx/test/std/ranges/range.adaptors/range.join/ctor.view.pass.cpp +libcxx/test/std/ranges/range.adaptors/range.join/end.pass.cpp +libcxx/test/std/ranges/range.adaptors/range.join/general.pass.cpp +libcxx/test/std/ranges/range.adaptors/range.join/range.join.iterator/arrow.pass.cpp +libcxx/test/std/ranges/range.adaptors/range.join/range.join.iterator/ctor.default.pass.cpp +libcxx/test/std/ranges/range.adaptors/range.join/range.join.iterator/ctor.other.pass.cpp +libcxx/test/std/ranges/range.adaptors/range.join/range.join.iterator/decrement.pass.cpp +libcxx/test/std/ranges/range.adaptors/range.join/range.join.iterator/eq.pass.cpp +libcxx/test/std/ranges/range.adaptors/range.join/range.join.iterator/increment.pass.cpp +libcxx/test/std/ranges/range.adaptors/range.join/range.join.iterator/member_types.compile.pass.cpp +libcxx/test/std/ranges/range.adaptors/range.join/range.join.iterator/star.pass.cpp +libcxx/test/std/ranges/range.adaptors/range.join/range.join.sentinel/ctor.default.pass.cpp +libcxx/test/std/ranges/range.adaptors/range.join/range.join.sentinel/ctor.other.pass.cpp +libcxx/test/std/ranges/range.adaptors/range.join/range.join.sentinel/ctor.parent.pass.cpp +libcxx/test/std/ranges/range.adaptors/range.join/range.join.sentinel/eq.pass.cpp +libcxx/test/std/ranges/range.adaptors/range.join/types.h libcxx/test/std/ranges/range.adaptors/range.lazy.split/adaptor.pass.cpp libcxx/test/std/ranges/range.adaptors/range.lazy.split/base.pass.cpp libcxx/test/std/ranges/range.adaptors/range.lazy.split/begin.pass.cpp >From f601c073fdfc6fce8ec6b54bee5f93b4d87a4e6f Mon Sep 17 00:00:00 2001 From: Jakub Mazurkiewicz <mazku...@gmail.com> Date: Mon, 27 Nov 2023 15:40:34 +0100 Subject: [PATCH 02/11] Enable `__as_lvalue` in >C++03 modes Comments: * https://github.com/llvm/llvm-project/pull/66033#discussion_r1396562251 * https://github.com/llvm/llvm-project/pull/66033#discussion_r1396564172 * https://github.com/llvm/llvm-project/pull/66033#discussion_r1396579715 --- libcxx/include/__ranges/join_view.h | 8 ++++---- libcxx/include/__utility/as_lvalue.h | 6 ++---- .../range.adaptor.helpers/as-lvalue.verify.cpp | 12 ++++-------- 3 files changed, 10 insertions(+), 16 deletions(-) diff --git a/libcxx/include/__ranges/join_view.h b/libcxx/include/__ranges/join_view.h index 812a6f9379a8579..fd68358837e0fa0 100644 --- a/libcxx/include/__ranges/join_view.h +++ b/libcxx/include/__ranges/join_view.h @@ -323,7 +323,7 @@ namespace ranges { else return *__parent_->__inner_; }; - if (++*__inner_ == ranges::end(ranges::__as_lvalue(__get_inner_range()))) { + if (++*__inner_ == ranges::end(std::__as_lvalue(__get_inner_range()))) { ++__get_outer(); __satisfy(); } @@ -354,11 +354,11 @@ namespace ranges { common_range<range_reference_t<_Base>> { if (__outer_ == ranges::end(__parent_->__base_)) - __inner_ = ranges::end(ranges::__as_lvalue(*--__outer_)); + __inner_ = ranges::end(std::__as_lvalue(*--__outer_)); // Skip empty inner ranges when going backwards. - while (*__inner_ == ranges::begin(ranges::__as_lvalue(*__outer_))) { - __inner_ = ranges::end(ranges::__as_lvalue(*--__outer_)); + while (*__inner_ == ranges::begin(std::__as_lvalue(*__outer_))) { + __inner_ = ranges::end(std::__as_lvalue(*--__outer_)); } --*__inner_; diff --git a/libcxx/include/__utility/as_lvalue.h b/libcxx/include/__utility/as_lvalue.h index b4df650edbf65ef..159f45dad4d41c0 100644 --- a/libcxx/include/__utility/as_lvalue.h +++ b/libcxx/include/__utility/as_lvalue.h @@ -21,16 +21,14 @@ _LIBCPP_PUSH_MACROS _LIBCPP_BEGIN_NAMESPACE_STD -#if _LIBCPP_STD_VER >= 20 +#ifndef _LIBCPP_CXX03_LANG -namespace ranges { template <class _Tp> _LIBCPP_HIDE_FROM_ABI constexpr _Tp& __as_lvalue(_LIBCPP_LIFETIMEBOUND _Tp&& __t) { return static_cast<_Tp&>(__t); } -} // namespace ranges -#endif // _LIBCPP_STD_VER >= 20 +#endif // !_LIBCPP_CXX03_LANG _LIBCPP_END_NAMESPACE_STD diff --git a/libcxx/test/libcxx/ranges/range.adaptors/range.adaptor.helpers/as-lvalue.verify.cpp b/libcxx/test/libcxx/ranges/range.adaptors/range.adaptor.helpers/as-lvalue.verify.cpp index 878ef91b13839d2..8efd7e5ccf983a4 100644 --- a/libcxx/test/libcxx/ranges/range.adaptors/range.adaptor.helpers/as-lvalue.verify.cpp +++ b/libcxx/test/libcxx/ranges/range.adaptors/range.adaptor.helpers/as-lvalue.verify.cpp @@ -6,15 +6,11 @@ // //===----------------------------------------------------------------------===// -// UNSUPPORTED: c++03, c++11, c++14, c++17 - -// <ranges> +// UNSUPPORTED: c++03 // template<class T> // constexpr T& as-lvalue(T&& t) { // exposition only -#include <ranges> - #include <concepts> #include <utility> @@ -22,19 +18,19 @@ constexpr bool test() { // Check glvalue { int lvalue{}; - [[maybe_unused]] std::same_as<int&> decltype(auto) check = std::ranges::__as_lvalue(lvalue); + [[maybe_unused]] std::same_as<int&> decltype(auto) check = std::__as_lvalue(lvalue); } // Check prvalue { - [[maybe_unused]] std::same_as<int&> decltype(auto) check = std::ranges::__as_lvalue( + [[maybe_unused]] std::same_as<int&> decltype(auto) check = std::__as_lvalue( 0); // expected-warning {{temporary bound to local reference 'check' will be destroyed at the end of the full-expression}} } // Check xvalue { int xvalue{}; - [[maybe_unused]] std::same_as<int&> decltype(auto) check = std::ranges::__as_lvalue(std::move(xvalue)); + [[maybe_unused]] std::same_as<int&> decltype(auto) check = std::__as_lvalue(std::move(xvalue)); } return true; >From be16b577a981cc96f2eaa00024ecb341c6219085 Mon Sep 17 00:00:00 2001 From: Jakub Mazurkiewicz <mazku...@gmail.com> Date: Mon, 27 Nov 2023 16:12:40 +0100 Subject: [PATCH 03/11] Split `as-lvalue.verify.cpp` Comments: * https://github.com/llvm/llvm-project/pull/66033#discussion_r1396565383 * https://github.com/llvm/llvm-project/pull/66033#discussion_r1396565996 --- .../as-lvalue.lifetimebound.verify.cpp | 22 +++++++++++++++++++ ...s-lvalue.verify.cpp => as-lvalue.pass.cpp} | 6 ----- 2 files changed, 22 insertions(+), 6 deletions(-) create mode 100644 libcxx/test/libcxx/ranges/range.adaptors/range.adaptor.helpers/as-lvalue.lifetimebound.verify.cpp rename libcxx/test/libcxx/ranges/range.adaptors/range.adaptor.helpers/{as-lvalue.verify.cpp => as-lvalue.pass.cpp} (79%) diff --git a/libcxx/test/libcxx/ranges/range.adaptors/range.adaptor.helpers/as-lvalue.lifetimebound.verify.cpp b/libcxx/test/libcxx/ranges/range.adaptors/range.adaptor.helpers/as-lvalue.lifetimebound.verify.cpp new file mode 100644 index 000000000000000..7046936b1b7a7f7 --- /dev/null +++ b/libcxx/test/libcxx/ranges/range.adaptors/range.adaptor.helpers/as-lvalue.lifetimebound.verify.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 +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03 + +// template<class T> +// constexpr T& as-lvalue(T&& t) { // exposition only + +#include <utility> + +void test() { + // Check prvalue + { + [[maybe_unused]] auto& check = std::__as_lvalue( + 0); // expected-warning {{temporary bound to local reference 'check' will be destroyed at the end of the full-expression}} + } +} diff --git a/libcxx/test/libcxx/ranges/range.adaptors/range.adaptor.helpers/as-lvalue.verify.cpp b/libcxx/test/libcxx/ranges/range.adaptors/range.adaptor.helpers/as-lvalue.pass.cpp similarity index 79% rename from libcxx/test/libcxx/ranges/range.adaptors/range.adaptor.helpers/as-lvalue.verify.cpp rename to libcxx/test/libcxx/ranges/range.adaptors/range.adaptor.helpers/as-lvalue.pass.cpp index 8efd7e5ccf983a4..14a3db6367ddc9a 100644 --- a/libcxx/test/libcxx/ranges/range.adaptors/range.adaptor.helpers/as-lvalue.verify.cpp +++ b/libcxx/test/libcxx/ranges/range.adaptors/range.adaptor.helpers/as-lvalue.pass.cpp @@ -21,12 +21,6 @@ constexpr bool test() { [[maybe_unused]] std::same_as<int&> decltype(auto) check = std::__as_lvalue(lvalue); } - // Check prvalue - { - [[maybe_unused]] std::same_as<int&> decltype(auto) check = std::__as_lvalue( - 0); // expected-warning {{temporary bound to local reference 'check' will be destroyed at the end of the full-expression}} - } - // Check xvalue { int xvalue{}; >From 181cd853f50801d7ea5ecf232ae3413ac10f4c83 Mon Sep 17 00:00:00 2001 From: Jakub Mazurkiewicz <mazku...@gmail.com> Date: Mon, 27 Nov 2023 16:20:24 +0100 Subject: [PATCH 04/11] Add missing `explicit` specifier in `__iterator(_Parent& __parent)` Comment: https://github.com/llvm/llvm-project/pull/66033#discussion_r1396574310 --- libcxx/include/__ranges/join_view.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libcxx/include/__ranges/join_view.h b/libcxx/include/__ranges/join_view.h index fd68358837e0fa0..909ca9a06d3ad12 100644 --- a/libcxx/include/__ranges/join_view.h +++ b/libcxx/include/__ranges/join_view.h @@ -265,7 +265,7 @@ namespace ranges { __satisfy(); } - _LIBCPP_HIDE_FROM_ABI constexpr __iterator(_Parent& __parent) + _LIBCPP_HIDE_FROM_ABI constexpr explicit __iterator(_Parent& __parent) requires(!forward_range<_Base>) : __parent_(std::addressof(__parent)) { __satisfy(); >From d11d81cebf4fd96aa3b31e0908930e1f693d5c4d Mon Sep 17 00:00:00 2001 From: Jakub Mazurkiewicz <mazku...@gmail.com> Date: Mon, 27 Nov 2023 17:22:35 +0100 Subject: [PATCH 05/11] Restore old `__sentinel<C>` friendship in `join_view::_sentinel` Comment: https://github.com/llvm/llvm-project/pull/66033#discussion_r1396587214 --- libcxx/include/__ranges/join_view.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/libcxx/include/__ranges/join_view.h b/libcxx/include/__ranges/join_view.h index 909ca9a06d3ad12..e1d54c4e4bbc5f9 100644 --- a/libcxx/include/__ranges/join_view.h +++ b/libcxx/include/__ranges/join_view.h @@ -164,10 +164,11 @@ namespace ranges { template<bool _Const> struct join_view<_View>::__sentinel { private: - friend join_view; + template <bool> + friend struct __sentinel; - using _Parent = __maybe_const<_Const, join_view>; - using _Base = __maybe_const<_Const, _View>; + using _Parent = __maybe_const<_Const, join_view>; + using _Base = __maybe_const<_Const, _View>; sentinel_t<_Base> __end_ = sentinel_t<_Base>(); public: >From 03454c21dade534913e91ef137d2a16f2031a618 Mon Sep 17 00:00:00 2001 From: Jakub Mazurkiewicz <mazku...@gmail.com> Date: Mon, 27 Nov 2023 18:16:30 +0100 Subject: [PATCH 06/11] Un-experimental more `join_view` related tests --- .../alg.copy/ranges.copy_backward.segmented.pass.cpp | 2 -- .../alg.copy/ranges.copy_n.segmented.pass.cpp | 2 -- .../alg.move/ranges.move.segmented.pass.cpp | 2 -- .../alg.move/ranges.move_backward.segmented.pass.cpp | 2 -- .../conventions/customization.point.object/cpo.compile.pass.cpp | 2 -- .../std/ranges/iterator_robust_against_adl.compile.pass.cpp | 1 - 6 files changed, 11 deletions(-) diff --git a/libcxx/test/std/algorithms/alg.modifying.operations/alg.copy/ranges.copy_backward.segmented.pass.cpp b/libcxx/test/std/algorithms/alg.modifying.operations/alg.copy/ranges.copy_backward.segmented.pass.cpp index c434cea1208cfe8..efeada57625581e 100644 --- a/libcxx/test/std/algorithms/alg.modifying.operations/alg.copy/ranges.copy_backward.segmented.pass.cpp +++ b/libcxx/test/std/algorithms/alg.modifying.operations/alg.copy/ranges.copy_backward.segmented.pass.cpp @@ -7,8 +7,6 @@ //===----------------------------------------------------------------------===// // UNSUPPORTED: c++03, c++11, c++14, c++17 -// TODO: make `join_view` non-experimental once D2770 is implemented. -// UNSUPPORTED: !c++experimental #include <algorithm> #include <array> diff --git a/libcxx/test/std/algorithms/alg.modifying.operations/alg.copy/ranges.copy_n.segmented.pass.cpp b/libcxx/test/std/algorithms/alg.modifying.operations/alg.copy/ranges.copy_n.segmented.pass.cpp index eae40cefa663f82..7da0f30775905fe 100644 --- a/libcxx/test/std/algorithms/alg.modifying.operations/alg.copy/ranges.copy_n.segmented.pass.cpp +++ b/libcxx/test/std/algorithms/alg.modifying.operations/alg.copy/ranges.copy_n.segmented.pass.cpp @@ -7,8 +7,6 @@ //===----------------------------------------------------------------------===// // UNSUPPORTED: c++03, c++11, c++14, c++17 -// TODO: make `join_view` non-experimental once D2770 is implemented. -// UNSUPPORTED: !c++experimental #include <algorithm> #include <array> diff --git a/libcxx/test/std/algorithms/alg.modifying.operations/alg.move/ranges.move.segmented.pass.cpp b/libcxx/test/std/algorithms/alg.modifying.operations/alg.move/ranges.move.segmented.pass.cpp index 2df6a10b18504ce..e29ba8af07d6f8d 100644 --- a/libcxx/test/std/algorithms/alg.modifying.operations/alg.move/ranges.move.segmented.pass.cpp +++ b/libcxx/test/std/algorithms/alg.modifying.operations/alg.move/ranges.move.segmented.pass.cpp @@ -7,8 +7,6 @@ //===----------------------------------------------------------------------===// // UNSUPPORTED: c++03, c++11, c++14, c++17 -// TODO: make `join_view` non-experimental once D2770 is implemented. -// UNSUPPORTED: !c++experimental #include <algorithm> #include <array> diff --git a/libcxx/test/std/algorithms/alg.modifying.operations/alg.move/ranges.move_backward.segmented.pass.cpp b/libcxx/test/std/algorithms/alg.modifying.operations/alg.move/ranges.move_backward.segmented.pass.cpp index 0f0a71439a10dd1..50f371a6d64d3ab 100644 --- a/libcxx/test/std/algorithms/alg.modifying.operations/alg.move/ranges.move_backward.segmented.pass.cpp +++ b/libcxx/test/std/algorithms/alg.modifying.operations/alg.move/ranges.move_backward.segmented.pass.cpp @@ -7,8 +7,6 @@ //===----------------------------------------------------------------------===// // UNSUPPORTED: c++03, c++11, c++14, c++17 -// TODO: make `join_view` non-experimental once D2770 is implemented. -// UNSUPPORTED: !c++experimental #include <algorithm> #include <array> diff --git a/libcxx/test/std/library/description/conventions/customization.point.object/cpo.compile.pass.cpp b/libcxx/test/std/library/description/conventions/customization.point.object/cpo.compile.pass.cpp index e6c0e09dfff5f87..060f179fe168326 100644 --- a/libcxx/test/std/library/description/conventions/customization.point.object/cpo.compile.pass.cpp +++ b/libcxx/test/std/library/description/conventions/customization.point.object/cpo.compile.pass.cpp @@ -7,8 +7,6 @@ //===----------------------------------------------------------------------===// // UNSUPPORTED: c++03, c++11, c++14, c++17 -// TODO: make `join_view` non-experimental once D2770 is implemented. -// UNSUPPORTED: !c++experimental // [customization.point.object] // [range.adaptor.object] "A range adaptor object is a customization point object..." diff --git a/libcxx/test/std/ranges/iterator_robust_against_adl.compile.pass.cpp b/libcxx/test/std/ranges/iterator_robust_against_adl.compile.pass.cpp index 09b77c0901a229c..5efd6c72a13dbf0 100644 --- a/libcxx/test/std/ranges/iterator_robust_against_adl.compile.pass.cpp +++ b/libcxx/test/std/ranges/iterator_robust_against_adl.compile.pass.cpp @@ -7,7 +7,6 @@ //===----------------------------------------------------------------------===// // UNSUPPORTED: c++03, c++11, c++14, c++17 -// UNSUPPORTED: !c++experimental // ADL call with nested iterators of views should not look up base's view's // namespace >From 7de9a775a69fdf5496e3d73be9592ae768e9ce40 Mon Sep 17 00:00:00 2001 From: Jakub Mazurkiewicz <mazku...@gmail.com> Date: Mon, 27 Nov 2023 21:21:06 +0100 Subject: [PATCH 07/11] Make `join_view::__iterator::__outer_` private Which is hopefully enough. Comment: https://github.com/llvm/llvm-project/pull/66033#discussion_r1396575242 --- libcxx/include/__ranges/join_view.h | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/libcxx/include/__ranges/join_view.h b/libcxx/include/__ranges/join_view.h index e1d54c4e4bbc5f9..e75e61270721c60 100644 --- a/libcxx/include/__ranges/join_view.h +++ b/libcxx/include/__ranges/join_view.h @@ -219,12 +219,9 @@ namespace ranges { static constexpr bool _OuterPresent = forward_range<_Base>; using _OuterType = _If<_OuterPresent, _Outer, std::__empty>; - public: _LIBCPP_NO_UNIQUE_ADDRESS _OuterType __outer_ = _OuterType(); - - private: optional<_Inner> __inner_; - _Parent *__parent_ = nullptr; + _Parent* __parent_ = nullptr; _LIBCPP_HIDE_FROM_ABI constexpr void __satisfy() { @@ -243,7 +240,7 @@ namespace ranges { if constexpr (__ref_is_glvalue) __inner_.reset(); } - + _LIBCPP_HIDE_FROM_ABI constexpr _Outer& __get_outer() { if constexpr (forward_range<_Base>) { return __outer_; >From f256e1f9e663ec64ade659520b1b9494d8f0fe9d Mon Sep 17 00:00:00 2001 From: Jakub Mazurkiewicz <mazku...@gmail.com> Date: Mon, 27 Nov 2023 21:45:52 +0100 Subject: [PATCH 08/11] Add test with code from LWG-3698 Comment: https://github.com/llvm/llvm-project/pull/66033#discussion_r1396600533 --- .../range.join/lwg3698.pass.cpp | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 libcxx/test/std/ranges/range.adaptors/range.join/lwg3698.pass.cpp diff --git a/libcxx/test/std/ranges/range.adaptors/range.join/lwg3698.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.join/lwg3698.pass.cpp new file mode 100644 index 000000000000000..c1e81aef5f8e5d0 --- /dev/null +++ b/libcxx/test/std/ranges/range.adaptors/range.join/lwg3698.pass.cpp @@ -0,0 +1,31 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// UNSUPPORTED: no-localization + +// Check LWG-3698: `regex_iterator` and `join_view` don't work together very well + +#include <algorithm> +#include <array> +#include <cassert> +#include <ranges> +#include <regex> +#include <string_view> + +int main(int, char**) { + char const text[] = "Hello"; + std::regex regex{"[a-z]"}; + + auto lower = + std::ranges::subrange( + std::cregex_iterator(std::ranges::begin(text), std::ranges::end(text), regex), std::cregex_iterator{}) | + std::views::join | std::views::transform([](auto const& sm) { return std::string_view(sm.first, sm.second); }); + + assert(std::ranges::equal(lower, std::to_array<std::string_view>({"e", "l", "l", "o"}))); +} >From 1f00358e80414f42ff2b42249c7ed9fe5399e881 Mon Sep 17 00:00:00 2001 From: Jakub Mazurkiewicz <mazku...@gmail.com> Date: Mon, 27 Nov 2023 21:58:02 +0100 Subject: [PATCH 09/11] Whitespace amendments --- libcxx/include/__ranges/join_view.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libcxx/include/__ranges/join_view.h b/libcxx/include/__ranges/join_view.h index e75e61270721c60..9b7399c24e3a5c7 100644 --- a/libcxx/include/__ranges/join_view.h +++ b/libcxx/include/__ranges/join_view.h @@ -218,8 +218,8 @@ namespace ranges { static constexpr bool _OuterPresent = forward_range<_Base>; using _OuterType = _If<_OuterPresent, _Outer, std::__empty>; - _LIBCPP_NO_UNIQUE_ADDRESS _OuterType __outer_ = _OuterType(); + optional<_Inner> __inner_; _Parent* __parent_ = nullptr; @@ -240,7 +240,7 @@ namespace ranges { if constexpr (__ref_is_glvalue) __inner_.reset(); } - + _LIBCPP_HIDE_FROM_ABI constexpr _Outer& __get_outer() { if constexpr (forward_range<_Base>) { return __outer_; >From d5d061075d3b86104880fd3a4fd9ac35474612f8 Mon Sep 17 00:00:00 2001 From: Jakub Mazurkiewicz <mazku...@gmail.com> Date: Mon, 27 Nov 2023 22:11:36 +0100 Subject: [PATCH 10/11] Add extra static assertion for `[range.join.iterator] Note 1` Comment: https://github.com/llvm/llvm-project/pull/66033#discussion_r1396578912 --- libcxx/include/__ranges/join_view.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libcxx/include/__ranges/join_view.h b/libcxx/include/__ranges/join_view.h index 9b7399c24e3a5c7..f80beda33b11ed9 100644 --- a/libcxx/include/__ranges/join_view.h +++ b/libcxx/include/__ranges/join_view.h @@ -214,6 +214,8 @@ namespace ranges { using _Inner = iterator_t<range_reference_t<_Base>>; using _InnerRange = range_reference_t<_View>; + static_assert(!_Const || forward_range<_Base>, "Const can only be true when Base models forward_range."); + static constexpr bool __ref_is_glvalue = is_reference_v<range_reference_t<_Base>>; static constexpr bool _OuterPresent = forward_range<_Base>; >From 3861ffa29062879070bc6acea0dde8fff036aba2 Mon Sep 17 00:00:00 2001 From: Jakub Mazurkiewicz <mazku...@gmail.com> Date: Mon, 27 Nov 2023 22:36:12 +0100 Subject: [PATCH 11/11] Fix comment: `!forward_range<iterator_t<Base>>` -> `!forward_range<Base>` Comment: https://github.com/llvm/llvm-project/pull/66033#discussion_r1396594058 --- .../range.adaptors/range.join/range.join.iterator/eq.pass.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libcxx/test/std/ranges/range.adaptors/range.join/range.join.iterator/eq.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.join/range.join.iterator/eq.pass.cpp index 8b7e694b080f47f..5c831f33e67c70b 100644 --- a/libcxx/test/std/ranges/range.adaptors/range.join/range.join.iterator/eq.pass.cpp +++ b/libcxx/test/std/ranges/range.adaptors/range.join/range.join.iterator/eq.pass.cpp @@ -42,7 +42,7 @@ constexpr bool test() { } { - // !forward_range<iterator_t<Base>> + // !forward_range<Base> using Inner = BufferView<int*>; using Outer = BufferView<cpp20_input_iterator<Inner*>, sentinel_wrapper<cpp20_input_iterator<Inner*>>>; static_assert(!std::equality_comparable<std::ranges::iterator_t<Outer>>); _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits