From 600a282d49011782fde23c4388ba1346284153a1 Mon Sep 17 00:00:00 2001 From: Jakub Mazurkiewicz Date: Fri, 8 Sep 2023 18:20:59 +0200 Subject: [PATCH 01/18] [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 839640a7c7e881..3e6e33f08c7ccf 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 19b1dd8eb5a446..38b77d42ec5b97 100644 --- a/libcxx/docs/Status/Cxx23Papers.csv +++ b/libcxx/docs/Status/Cxx23Papers.csv @@ -104,7 +104,7 @@ "`P2708R1 `__","LWG", "No Further Fundamentals TSes", "November 2022","|Nothing to do|","","" "","","","","","","" "`P0290R4 `__","LWG", "``apply()`` for ``synchronized_value``","February 2023","","","|concurrency TS|" -"`P2770R0 `__","LWG", "Stashing stashing ``iterators`` for proper flattening","February 2023","|In Progress|","","|ranges|" +"`P2770R0 `__","LWG", "Stashing stashing ``iterators`` for proper flattening","February 2023","|Partial| [#note-P2770R0]_","","|ranges|" "`P2164R9 `__","LWG", "``views::enumerate``","February 2023","","","|ranges|" "`P2711R1 `__","LWG", "Making multi-param constructors of ``views`` ``explicit``","February 2023","|In Progress| [#note-P2711R1]_","","|ranges|" "`P2609R3 `__","LWG", "Relaxing Ranges Just A Smidge","February 2023","","","|ranges|" diff --git a/libcxx/docs/UsingLibcxx.rst b/libcxx/docs/UsingLibcxx.rst index 24d6a7b95f5b2e..2d52a7c9ef2b8a 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 889d7fedbf2965..7aad3a4c624345 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 e6240dfd2580dc..812a6f9379a857 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 @@ -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 @@ -84,11 +83,16 @@ namespace ranges { template friend struct std::__segmented_iterator_traits; - static constexpr bool _UseCache = !is_reference_v<_InnerRange>; - using _Cache = _If<_UseCache, __non_propagating_cache>, __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>, __empty_cache>; + _LIBCPP_NO_UNIQUE_ADDRESS _OuterCache __outer_; + + static constexpr bool _UseInnerCache = !is_reference_v<_InnerRange>; + using _InnerCache = _If<_UseInnerCache, __non_propagating_cache>, __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>; - return __iterator<__use_const>{*this, ranges::begin(__base_)}; + if constexpr (forward_range<_View>) { + constexpr bool __use_const = __simple_view<_View> && + is_reference_v>; + return __iterator<__use_const>{*this, ranges::begin(__base_)}; + } else { + __outer_.__emplace(ranges::begin(__base_)); + return __iterator{*this}; + } } template _LIBCPP_HIDE_FROM_ABI constexpr auto begin() const - requires input_range && - is_reference_v> + requires forward_range && + is_reference_v> && + input_range> { return __iterator{*this, ranges::begin(__base_)}; } @@ -134,13 +144,12 @@ namespace ranges { template _LIBCPP_HIDE_FROM_ABI constexpr auto end() const - requires input_range && - is_reference_v> + requires forward_range && + is_reference_v> && + input_range> { using _ConstInnerRange = range_reference_t; - if constexpr (forward_range && - is_reference_v<_ConstInnerRange> && - forward_range<_ConstInnerRange> && + if constexpr (forward_range<_ConstInnerRange> && common_range && common_range<_ConstInnerRange>) { return __iterator{*this, ranges::end(__base_)}; @@ -154,11 +163,10 @@ namespace ranges { requires view<_View> && input_range> template struct join_view<_View>::__sentinel { - template - 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, 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 struct join_view<_View>::__iterator final : public __join_view_iterator_category<__maybe_const<_Const, _View>> { - - template - friend struct __iterator; + friend join_view; template friend struct std::__segmented_iterator_traits; @@ -209,8 +215,11 @@ namespace ranges { static constexpr bool __ref_is_glvalue = is_reference_v>; + 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>>; - _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 __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> { 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> && + forward_range<_Base> && equality_comparable>> { 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 00000000000000..b4df650edbf65e --- /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 +_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 17ebe48f329963..8364dde16ccf9f 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 e8865ac1089d6f..59d3af2a4bcb32 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 c5581d55e79bbb..1deef3db204107 100644 --- a/libcxx/include/utility +++ b/libcxx/include/utility @@ -249,6 +249,7 @@ template #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 a883103d812588..82c7d99f8979a8 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 00000000000000..878ef91b13839d --- /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 + +// + +// template +// constexpr T& as-lvalue(T&& t) { // exposition only + +#include + +#include +#include + +constexpr bool test() { + // Check glvalue + { + int lvalue{}; + [[maybe_unused]] std::same_as decltype(auto) check = std::ranges::__as_lvalue(lvalue); + } + + // Check prvalue + { + [[maybe_unused]] std::same_as 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 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 82e8cab503a275..6cd17c2b3f3533 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 #include 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 50fb479afcd064..ec60ab8db1609b 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 #include 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 184008c3e2fd0f..301fbcbc533c26 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 @@ // // 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 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 215318f15cad0d..00000000000000 --- 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 -#include - -#include "../types.h" - -using NonDefaultCtrIter = cpp20_input_iterator; -static_assert(!std::default_initializable); - -using NonDefaultCtrIterView = BufferView>; -static_assert(std::ranges::input_range); - -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 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 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 afaf3227210996..9beb3d282a27cc 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 13883e894ac7bf..caf018b582263a 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; // 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 9e4fa5f8c59a44..005d0d1d2d5cb7 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 && -// is_reference_v>; +// requires forward_range && +// is_reference_v> && +// input_range>; +#include #include #include +#include #include "types.h" @@ -120,7 +122,7 @@ constexpr bool test() { static_assert(HasConstBegin); } - // !input_range + // !forward_range { std::ranges::join_view jv{ConstNotRange{}}; static_assert(!HasConstBegin); @@ -146,6 +148,27 @@ constexpr bool test() { static_assert(std::same_as); } + // Check stashing iterators (LWG3698: regex_iterator and join_view don't work together very well) + { + std::ranges::join_view 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 jv; + static_assert(!HasConstBegin); + } + + // 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 2c470991be0b6b..a8eafc5a9c0211 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 // explicit join_view(R&&) -> join_view>; 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 eddc950747ba76..2c6eea500580d6 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 // explicit join_view(R&&) -> join_view>; 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 26206e32c358ce..0daff7d3b3c98a 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 = 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 ce5393062d7781..75d4c7e5916b0a 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 7e225202cc2312..516ba25a0e8596 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 && +// is_reference_v> && +// input_range> #include #include @@ -33,13 +35,13 @@ concept HasConstEnd = requires (const T& t){ // | 3 | Y | Y | Y | Y | N | Y |sentinel |sentinel| // | 4 | Y | Y | Y | N | Y | Y |sentinel | - | // | 5 | Y | Y | N | Y | Y | Y |sentinel |sentinel| -// | 6 | Y | N | Y | Y | Y | Y |sentinel |sentinel| +// | 6 | Y | N | Y | Y | Y | Y |sentinel | - | // | 7 | N | Y | Y | Y | Y | Y |iterator|iterator| // | 8 | N | Y | Y | Y | Y | N |sentinel|sentinel| // | 9 | N | Y | Y | Y | N | Y |sentinel|sentinel| // | 10 | N | Y | Y | N | Y | Y |sentinel| - | // | 11 | N | Y | N | Y | Y | Y |sentinel|sentinel| -// | 12 | N | N | Y | Y | Y | Y |sentinel|sentinel| +// | 12 | N | N | Y | Y | Y | Y |sentinel| - | // // @@ -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); - static_assert(std::same_as); + static_assert(!HasConstEnd); static_assert(!std::ranges::common_range); static_assert(!std::ranges::common_range); } @@ -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); - static_assert(!std::same_as); + static_assert(!HasConstEnd); static_assert(!std::ranges::common_range); static_assert(!std::ranges::common_range); } @@ -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 jv; + static_assert(!HasConstEnd); + } + 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 e9eab585260cdc..f92eb418fac77c 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 e610cde2c3b5be..ddcf66bfe775e7 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 && copyable; 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 e4f193e4e60642..82fe824fad1b2a 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 = default; +// iterator() = default; #include @@ -29,19 +28,12 @@ constexpr void test_default_constructible() { using JoinView = std::ranges::join_view>; using JoinIterator = std::ranges::iterator_t; static_assert(std::is_default_constructible_v); - JoinIterator it; (void)it; -} - -template -constexpr void test_non_default_constructible() { - using JoinView = std::ranges::join_view>; - using JoinIterator = std::ranges::iterator_t; - static_assert(!std::is_default_constructible_v); + [[maybe_unused]] JoinIterator it; } constexpr bool test() { - test_non_default_constructible>(); - // NOTE: cpp20_input_iterator can't be used with join_view because it is not copyable. + test_default_constructible>(); + test_default_constructible>(); test_default_constructible>(); test_default_constructible>(); test_default_constructible>(); 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 a0406f90c88c63..e220b2cfeac84a 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 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 4363fb0e330c3b..29720d93bab66f 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 && @@ -18,9 +17,12 @@ // bidirectional_range> && // common_range>; +#include +#include #include #include #include +#include #include "../types.h" @@ -150,6 +152,15 @@ constexpr bool test() { static_assert(!CanPostDecrement); } + { + // LWG3791: `join_view::iterator::operator--` may be ill-formed + std::vector> 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 327cc82b06b085..8b7e694b080f47 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> && +// requires ref-is-glvalue && forward_range && // equality_comparable>>; #include @@ -43,7 +42,7 @@ constexpr bool test() { } { - // !equality_comparable> + // !forward_range> using Inner = BufferView; using Outer = BufferView, sentinel_wrapper>>; static_assert(!std::equality_comparable>); @@ -51,8 +50,6 @@ constexpr bool test() { std::ranges::join_view jv(Outer{inners}); auto iter = jv.begin(); static_assert(!std::equality_comparable); - auto const_iter = std::as_const(jv).begin(); - static_assert(!std::equality_comparable); } { 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 4bcb4de7e9c886..dada91462a73ff 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); } + { + // Check stashing iterators (LWG3698: regex_iterator and join_view don't work together very well) + std::ranges::join_view 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 0bf6aa3d926146..917e72dc858545 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 e9b73f1a415966..28e1bf75726f63 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 17b98facd65081..b9b9d73d77e265 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::. 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 fa6f7bb031207a..73457b826df0b0 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 0eebe14af3fcba..42fcc733e181f4 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 c2d7058746d758..4bd8025efb5c1b 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 s); // requires Const && convertible_to, sentinel_t>; 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 a9df7c3881ba8f..1ac68277338fee 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 cbd03b84f208b9..bc7d4bec94d3e6 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 // requires sentinel_for, iterator_t>> @@ -17,6 +16,7 @@ #include #include #include +#include #include "../types.h" @@ -61,18 +61,27 @@ static_assert(EqualityComparable == sentinel { 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); - static_assert(!EqualityComparable); } + // test iterator == sentinel + { + ChildView children[4] = {ChildView(buffer[0]), ChildView(buffer[1]), ChildView(buffer[2]), ChildView(buffer[3])}; + using ParentT = std::remove_all_extents_t; + auto jv = std::ranges::join_view(ForwardParentView(children)); + assert(std::as_const(jv).end() == std::ranges::next(jv.begin(), 16)); + } + + // test iterator == sentinel { 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; + const auto jv = std::ranges::join_view(ForwardParentView(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 b2ef5f090b5731..c1378dc1144b40 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 #include +#include #include #include "test_macros.h" @@ -52,13 +53,13 @@ inline ChildView globalChildren[4] = { ChildView(globalBuffer[3]), }; -template +template class Iter = cpp17_input_iterator> struct ParentView : std::ranges::view_base { T* ptr_; unsigned size_; - using iterator = cpp20_input_iterator; - using const_iterator = cpp20_input_iterator; + using iterator = Iter; + using const_iterator = Iter; using sentinel = sentinel_wrapper; using const_sentinel = sentinel_wrapper; @@ -80,6 +81,9 @@ struct ParentView : std::ranges::view_base { template ParentView(T*) -> ParentView; +template +using ForwardParentView = ParentView; + 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 class Iter> +struct CopyableParentTemplate : std::ranges::view_base { CopyableChild* ptr_; - using iterator = cpp17_input_iterator; - using const_iterator = cpp17_input_iterator; + using iterator = Iter; + using const_iterator = Iter; using sentinel = sentinel_wrapper; using const_sentinel = sentinel_wrapper; - 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; +using ForwardCopyableParent = CopyableParentTemplate; + struct Box { int x; }; @@ -392,4 +400,48 @@ struct IterMoveSwapAwareView : BufferView { }; static_assert(std::ranges::input_range); +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; +static_assert(std::ranges::input_range); +static_assert(!std::ranges::forward_range); + +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); +static_assert(std::ranges::input_range); +static_assert(std::ranges::input_range>); +static_assert(!std::ranges::input_range>); + #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 6f2da091c3709b..ad61baa76018da 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 -static_assert(std::forward_iterator); -static_assert(!std::bidirectional_iterator); +static_assert(std::input_iterator); +static_assert(!std::forward_iterator); static_assert(!std::indirectly_writable); static_assert(std::sentinel_for); static_assert(!std::sized_sentinel_for); 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 7d30b0adcc234c..8ee2c5006d31c4 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 #include @@ -36,6 +37,9 @@ test() static_assert((std::is_same*>::value), ""); static_assert((std::is_same&>::value), ""); static_assert((std::is_same::value), ""); +#if TEST_STD_VER >= 20 + static_assert(std::is_same_v); +#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 397226552edee0..23eea7f369c170 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 -static_assert(std::forward_iterator); -static_assert(!std::bidirectional_iterator); +static_assert(std::input_iterator); +static_assert(!std::forward_iterator); static_assert(!std::indirectly_writable); static_assert(std::sentinel_for); static_assert(!std::sized_sentinel_for); 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 73ad58f4eecfb6..a9c18e8a1b77a1 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 #include @@ -36,6 +37,9 @@ test() static_assert((std::is_same*>::value), ""); static_assert((std::is_same&>::value), ""); static_assert((std::is_same::value), ""); +#if TEST_STD_VER >= 20 + static_assert(std::is_same_v); +#endif } int main(int, char**) diff --git a/libcxx/utils/data/ignore_format.txt b/libcxx/utils/data/ignore_format.txt index 123d06d56e29a5..c10745ce3edadf 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 Date: Mon, 27 Nov 2023 15:40:34 +0100 Subject: [PATCH 02/18] 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 812a6f9379a857..fd68358837e0fa 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> { 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 b4df650edbf65e..159f45dad4d41c 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 _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 878ef91b13839d..8efd7e5ccf983a 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 - -// +// UNSUPPORTED: c++03 // template // constexpr T& as-lvalue(T&& t) { // exposition only -#include - #include #include @@ -22,19 +18,19 @@ constexpr bool test() { // Check glvalue { int lvalue{}; - [[maybe_unused]] std::same_as decltype(auto) check = std::ranges::__as_lvalue(lvalue); + [[maybe_unused]] std::same_as decltype(auto) check = std::__as_lvalue(lvalue); } // Check prvalue { - [[maybe_unused]] std::same_as decltype(auto) check = std::ranges::__as_lvalue( + [[maybe_unused]] std::same_as 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 decltype(auto) check = std::ranges::__as_lvalue(std::move(xvalue)); + [[maybe_unused]] std::same_as decltype(auto) check = std::__as_lvalue(std::move(xvalue)); } return true; From be16b577a981cc96f2eaa00024ecb341c6219085 Mon Sep 17 00:00:00 2001 From: Jakub Mazurkiewicz Date: Mon, 27 Nov 2023 16:12:40 +0100 Subject: [PATCH 03/18] 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 00000000000000..7046936b1b7a7f --- /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 +// constexpr T& as-lvalue(T&& t) { // exposition only + +#include + +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 8efd7e5ccf983a..14a3db6367ddc9 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 decltype(auto) check = std::__as_lvalue(lvalue); } - // Check prvalue - { - [[maybe_unused]] std::same_as 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 Date: Mon, 27 Nov 2023 16:20:24 +0100 Subject: [PATCH 04/18] 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 fd68358837e0fa..909ca9a06d3ad1 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 Date: Mon, 27 Nov 2023 17:22:35 +0100 Subject: [PATCH 05/18] Restore old `__sentinel` 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 909ca9a06d3ad1..e1d54c4e4bbc5f 100644 --- a/libcxx/include/__ranges/join_view.h +++ b/libcxx/include/__ranges/join_view.h @@ -164,10 +164,11 @@ namespace ranges { template struct join_view<_View>::__sentinel { private: - friend join_view; + template + 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 Date: Mon, 27 Nov 2023 18:16:30 +0100 Subject: [PATCH 06/18] 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 c434cea1208cfe..efeada57625581 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 #include 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 eae40cefa663f8..7da0f30775905f 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 #include 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 2df6a10b18504c..e29ba8af07d6f8 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 #include 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 0f0a71439a10dd..50f371a6d64d3a 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 #include 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 e6c0e09dfff5f8..060f179fe16832 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 09b77c0901a229..5efd6c72a13dbf 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 Date: Mon, 27 Nov 2023 21:21:06 +0100 Subject: [PATCH 07/18] 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 e1d54c4e4bbc5f..e75e61270721c6 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 Date: Mon, 27 Nov 2023 21:45:52 +0100 Subject: [PATCH 08/18] 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 00000000000000..c1e81aef5f8e5d --- /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 +#include +#include +#include +#include +#include + +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({"e", "l", "l", "o"}))); +} From 1f00358e80414f42ff2b42249c7ed9fe5399e881 Mon Sep 17 00:00:00 2001 From: Jakub Mazurkiewicz Date: Mon, 27 Nov 2023 21:58:02 +0100 Subject: [PATCH 09/18] 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 e75e61270721c6..9b7399c24e3a5c 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 Date: Mon, 27 Nov 2023 22:11:36 +0100 Subject: [PATCH 10/18] 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 9b7399c24e3a5c..f80beda33b11ed 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>; 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>; static constexpr bool _OuterPresent = forward_range<_Base>; From 3861ffa29062879070bc6acea0dde8fff036aba2 Mon Sep 17 00:00:00 2001 From: Jakub Mazurkiewicz Date: Mon, 27 Nov 2023 22:36:12 +0100 Subject: [PATCH 11/18] Fix comment: `!forward_range>` -> `!forward_range` 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 8b7e694b080f47..5c831f33e67c70 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> + // !forward_range using Inner = BufferView; using Outer = BufferView, sentinel_wrapper>>; static_assert(!std::equality_comparable>); From 0e927818e45d361e3fdc76df9f5938ea291f7bf1 Mon Sep 17 00:00:00 2001 From: Jakub Mazurkiewicz Date: Tue, 28 Nov 2023 00:53:35 +0100 Subject: [PATCH 12/18] Make `as-lvalue.pass.cpp` C++11 friendly --- .../range.adaptor.helpers/as-lvalue.pass.cpp | 22 ++++++------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/libcxx/test/libcxx/ranges/range.adaptors/range.adaptor.helpers/as-lvalue.pass.cpp b/libcxx/test/libcxx/ranges/range.adaptors/range.adaptor.helpers/as-lvalue.pass.cpp index 14a3db6367ddc9..d5cd81f3977495 100644 --- a/libcxx/test/libcxx/ranges/range.adaptors/range.adaptor.helpers/as-lvalue.pass.cpp +++ b/libcxx/test/libcxx/ranges/range.adaptors/range.adaptor.helpers/as-lvalue.pass.cpp @@ -11,28 +11,20 @@ // template // constexpr T& as-lvalue(T&& t) { // exposition only -#include +#include +#include #include -constexpr bool test() { - // Check glvalue - { - int lvalue{}; - [[maybe_unused]] std::same_as decltype(auto) check = std::__as_lvalue(lvalue); - } +constexpr bool test(int value = 0) { + static_assert(std::is_same::value, ""); + static_assert(std::is_same::value, ""); - // Check xvalue - { - int xvalue{}; - [[maybe_unused]] std::same_as decltype(auto) check = std::__as_lvalue(std::move(xvalue)); - } - - return true; + return (assert(&std::__as_lvalue(value) == &value), assert(&std::__as_lvalue(std::move(value)) == &value), true); } int main(int, char**) { test(); - static_assert(test()); + static_assert(test(), ""); return 0; } From 54c31fc10fbf73839c4d1b1e434f6fd9cfca2ca7 Mon Sep 17 00:00:00 2001 From: Jakub Mazurkiewicz Date: Wed, 29 Nov 2023 17:47:07 +0100 Subject: [PATCH 13/18] Add `return 0;` in LWG-3698 test Comment: https://github.com/llvm/llvm-project/pull/66033#discussion_r1409553823 --- .../test/std/ranges/range.adaptors/range.join/lwg3698.pass.cpp | 2 ++ 1 file changed, 2 insertions(+) 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 index c1e81aef5f8e5d..0abe37bf17f7e8 100644 --- a/libcxx/test/std/ranges/range.adaptors/range.join/lwg3698.pass.cpp +++ b/libcxx/test/std/ranges/range.adaptors/range.join/lwg3698.pass.cpp @@ -28,4 +28,6 @@ int main(int, char**) { 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({"e", "l", "l", "o"}))); + + return 0; } From 62fa3a7d86b63459dde492711040c11a5f6bc4c5 Mon Sep 17 00:00:00 2001 From: Jakub Mazurkiewicz Date: Wed, 29 Nov 2023 17:48:07 +0100 Subject: [PATCH 14/18] Revert "Make `as-lvalue.pass.cpp` C++11 friendly" This reverts commit 0e927818e45d361e3fdc76df9f5938ea291f7bf1. --- .../range.adaptor.helpers/as-lvalue.pass.cpp | 22 +++++++++++++------ 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/libcxx/test/libcxx/ranges/range.adaptors/range.adaptor.helpers/as-lvalue.pass.cpp b/libcxx/test/libcxx/ranges/range.adaptors/range.adaptor.helpers/as-lvalue.pass.cpp index d5cd81f3977495..14a3db6367ddc9 100644 --- a/libcxx/test/libcxx/ranges/range.adaptors/range.adaptor.helpers/as-lvalue.pass.cpp +++ b/libcxx/test/libcxx/ranges/range.adaptors/range.adaptor.helpers/as-lvalue.pass.cpp @@ -11,20 +11,28 @@ // template // constexpr T& as-lvalue(T&& t) { // exposition only -#include -#include +#include #include -constexpr bool test(int value = 0) { - static_assert(std::is_same::value, ""); - static_assert(std::is_same::value, ""); +constexpr bool test() { + // Check glvalue + { + int lvalue{}; + [[maybe_unused]] std::same_as decltype(auto) check = std::__as_lvalue(lvalue); + } - return (assert(&std::__as_lvalue(value) == &value), assert(&std::__as_lvalue(std::move(value)) == &value), true); + // Check xvalue + { + int xvalue{}; + [[maybe_unused]] std::same_as decltype(auto) check = std::__as_lvalue(std::move(xvalue)); + } + + return true; } int main(int, char**) { test(); - static_assert(test(), ""); + static_assert(test()); return 0; } From aebbbac53d1b3a1537e04610c3ed7d7436676e76 Mon Sep 17 00:00:00 2001 From: Jakub Mazurkiewicz Date: Wed, 29 Nov 2023 17:48:40 +0100 Subject: [PATCH 15/18] Make `as-lvalue.pass.cpp` C++14 friendly Comment: https://github.com/llvm/llvm-project/pull/66033#discussion_r1409545297 --- .../range.adaptor.helpers/as-lvalue.pass.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/libcxx/test/libcxx/ranges/range.adaptors/range.adaptor.helpers/as-lvalue.pass.cpp b/libcxx/test/libcxx/ranges/range.adaptors/range.adaptor.helpers/as-lvalue.pass.cpp index 14a3db6367ddc9..721279fcd586b0 100644 --- a/libcxx/test/libcxx/ranges/range.adaptors/range.adaptor.helpers/as-lvalue.pass.cpp +++ b/libcxx/test/libcxx/ranges/range.adaptors/range.adaptor.helpers/as-lvalue.pass.cpp @@ -6,25 +6,27 @@ // //===----------------------------------------------------------------------===// -// UNSUPPORTED: c++03 +// UNSUPPORTED: c++03, c++11 // template // constexpr T& as-lvalue(T&& t) { // exposition only -#include +#include #include constexpr bool test() { // Check glvalue { int lvalue{}; - [[maybe_unused]] std::same_as decltype(auto) check = std::__as_lvalue(lvalue); + [[maybe_unused]] decltype(auto) check = std::__as_lvalue(lvalue); + static_assert(std::is_same::value, ""); } // Check xvalue { int xvalue{}; - [[maybe_unused]] std::same_as decltype(auto) check = std::__as_lvalue(std::move(xvalue)); + [[maybe_unused]] decltype(auto) check = std::__as_lvalue(std::move(xvalue)); + static_assert(std::is_same::value, ""); } return true; @@ -32,7 +34,7 @@ constexpr bool test() { int main(int, char**) { test(); - static_assert(test()); + static_assert(test(), ""); return 0; } From ca61a7060e4f0004da00fabd2ace58f8d523ccff Mon Sep 17 00:00:00 2001 From: Jakub Mazurkiewicz Date: Tue, 5 Dec 2023 12:15:42 +0100 Subject: [PATCH 16/18] Test `iterator(Parent& parent, OuterIter outer)` constructor Comments: * https://github.com/llvm/llvm-project/pull/66033#discussion_r1396589173 * https://github.com/llvm/llvm-project/pull/66033#discussion_r1396590292 (partially) --- .../ctor.parent.outer.pass.cpp | 65 +++++++++++ .../range.join/range.join.iterator/types.h | 109 ++++++++++++++++++ 2 files changed, 174 insertions(+) create mode 100644 libcxx/test/libcxx/ranges/range.adaptors/range.join/range.join.iterator/ctor.parent.outer.pass.cpp create mode 100644 libcxx/test/libcxx/ranges/range.adaptors/range.join/range.join.iterator/types.h diff --git a/libcxx/test/libcxx/ranges/range.adaptors/range.join/range.join.iterator/ctor.parent.outer.pass.cpp b/libcxx/test/libcxx/ranges/range.adaptors/range.join/range.join.iterator/ctor.parent.outer.pass.cpp new file mode 100644 index 00000000000000..9bf55f0a3423ae --- /dev/null +++ b/libcxx/test/libcxx/ranges/range.adaptors/range.join/range.join.iterator/ctor.parent.outer.pass.cpp @@ -0,0 +1,65 @@ +//===----------------------------------------------------------------------===// +// +// 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 iterator(Parent& parent, OuterIter outer) +// requires forward_range; // exposition only + +#include +#include +#include +#include + +#include "types.h" + +constexpr bool test() { + std::string strings[4] = {"aaaa", "bbbb", "cccc", "dddd"}; + + { // Check if `outer_` is initialized with `std::move(outer)` for `iterator` + MoveOnAccessSubrange r(DieOnCopyIterator(strings), sentinel_wrapper(strings + 4)); + std::ranges::join_view jv(std::move(r)); + auto iter = jv.begin(); // Calls `iterator(Parent& parent, OuterIter outer)` + assert(*iter == 'a'); + } + + { // Check if `outer_` is initialized with `std::move(outer)` for `iterator` + MoveOnAccessSubrange r(DieOnCopyIterator(strings), sentinel_wrapper(strings + 4)); + std::ranges::join_view jv(std::ranges::ref_view{r}); + auto iter = std::as_const(jv).begin(); // Calls `iterator(Parent& parent, OuterIter outer)` + assert(*iter == 'a'); + } + + { + // 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. + using NonDefaultCtrIter = cpp20_input_iterator; + static_assert(!std::default_initializable); + using NonDefaultCtrIterView = BufferView>; + static_assert(std::ranges::input_range); + + int buffer[2][2] = {{1, 2}, {3, 4}}; + NonDefaultCtrIterView inners[] = {buffer[0], buffer[1]}; + auto outer = std::views::all(inners); + std::ranges::join_view jv(outer); + auto iter = jv.begin(); // Calls `iterator(Parent& parent, OuterIter outer)` + assert(*iter == 1); + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/libcxx/ranges/range.adaptors/range.join/range.join.iterator/types.h b/libcxx/test/libcxx/ranges/range.adaptors/range.join/range.join.iterator/types.h new file mode 100644 index 00000000000000..a5b88ed01773c7 --- /dev/null +++ b/libcxx/test/libcxx/ranges/range.adaptors/range.join/range.join.iterator/types.h @@ -0,0 +1,109 @@ +//===----------------------------------------------------------------------===// +// +// 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 TEST_LIBCXX_RANGES_RANGE_ADAPTORS_RANGE_JOIN_RANGE_JOIN_ITERATOR_TYPES_H +#define TEST_LIBCXX_RANGES_RANGE_ADAPTORS_RANGE_JOIN_RANGE_JOIN_ITERATOR_TYPES_H + +#include +#include +#include + +#include "test_iterators.h" + +template +struct DieOnCopyIterator { + using value_type = std::iter_value_t; + using difference_type = std::iter_difference_t; + + DieOnCopyIterator() = default; + constexpr explicit DieOnCopyIterator(Iter iter) : iter_(std::move(iter)) {} + constexpr DieOnCopyIterator(DieOnCopyIterator&& other) = default; + DieOnCopyIterator& operator=(DieOnCopyIterator&&) = default; + + constexpr DieOnCopyIterator(const DieOnCopyIterator&) { assert(false); } + constexpr DieOnCopyIterator& operator=(const DieOnCopyIterator&) { assert(false); } + + constexpr DieOnCopyIterator& operator++() { + ++iter_; + return *this; + } + + constexpr void operator++(int) { iter_++; } + + constexpr DieOnCopyIterator operator++(int) + requires std::forward_iterator + { + auto tmp = *this; + ++tmp; + return tmp; + } + + constexpr decltype(auto) operator*() const { return *iter_; } + + friend constexpr bool operator==(const DieOnCopyIterator& left, const DieOnCopyIterator& right) + requires std::equality_comparable + { + return left.iter_ == right.iter_; + } + + friend constexpr bool operator==(const DieOnCopyIterator& it, const sentinel_wrapper& se) { + return it.iter_ == se; + } + +private: + Iter iter_ = Iter(); +}; + +template +explicit DieOnCopyIterator(Iter) -> DieOnCopyIterator; + +static_assert(std::forward_iterator>); +static_assert(!std::bidirectional_iterator>); +static_assert(std::sentinel_for, DieOnCopyIterator>); + +template Sent = Iter> +struct MoveOnAccessSubrange : std::ranges::view_base { + constexpr explicit MoveOnAccessSubrange(Iter iter, Sent sent) : iter_(std::move(iter)), sent_(std::move(sent)) {} + + MoveOnAccessSubrange(MoveOnAccessSubrange&&) = default; + MoveOnAccessSubrange& operator=(MoveOnAccessSubrange&&) = default; + + MoveOnAccessSubrange(const MoveOnAccessSubrange&) = delete; + MoveOnAccessSubrange& operator=(const MoveOnAccessSubrange&) = delete; + + constexpr Iter begin() { return std::move(iter_); } + constexpr Sent end() { return std::move(sent_); } + +private: + Iter iter_; + Sent sent_; +}; + +template +MoveOnAccessSubrange(Iter, Sent) -> MoveOnAccessSubrange; + +static_assert(std::ranges::input_range>>); +static_assert(std::ranges::forward_range>>); + +template + requires(!std::same_as) +struct BufferView : std::ranges::view_base { + using T = std::iter_value_t; + T* data_; + std::size_t size_; + + template + constexpr BufferView(T (&b)[N]) : data_(b), size_(N) {} + + constexpr Iter begin() const { return Iter(data_); } + constexpr Sent end() const { return Sent(Iter(data_ + size_)); } +}; + +static_assert(std::ranges::input_range>>); + +#endif // TEST_LIBCXX_RANGES_RANGE_ADAPTORS_RANGE_JOIN_RANGE_JOIN_ITERATOR_TYPES_H From 024b9e240cf19316c36712784f927e4b8e0dff8a Mon Sep 17 00:00:00 2001 From: Jakub Mazurkiewicz Date: Tue, 5 Dec 2023 12:34:46 +0100 Subject: [PATCH 17/18] Test `iterator(Parent& parent)` constructor Comment: https://github.com/llvm/llvm-project/pull/66033#discussion_r1396590292 --- .../range.join.iterator/ctor.parent.pass.cpp | 36 +++++++++++++++++++ .../range.join/range.join.iterator/types.h | 9 +++-- 2 files changed, 43 insertions(+), 2 deletions(-) create mode 100644 libcxx/test/libcxx/ranges/range.adaptors/range.join/range.join.iterator/ctor.parent.pass.cpp diff --git a/libcxx/test/libcxx/ranges/range.adaptors/range.join/range.join.iterator/ctor.parent.pass.cpp b/libcxx/test/libcxx/ranges/range.adaptors/range.join/range.join.iterator/ctor.parent.pass.cpp new file mode 100644 index 00000000000000..bb8debb642b993 --- /dev/null +++ b/libcxx/test/libcxx/ranges/range.adaptors/range.join/range.join.iterator/ctor.parent.pass.cpp @@ -0,0 +1,36 @@ +//===----------------------------------------------------------------------===// +// +// 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(Parent& parent) +// requires (!forward_range); // exposition only + +#include +#include + +#include "types.h" + +constexpr bool test() { + std::string strings[4] = {"eeee", "ffff", "gggg", "hhhh"}; + + MoveOnAccessSubrange r( + DieOnCopyIterator(cpp20_input_iterator(strings)), sentinel_wrapper(cpp20_input_iterator(strings + 4))); + std::ranges::join_view jv(std::move(r)); + auto iter = jv.begin(); // Calls `iterator(Parent& parent)` + assert(*iter == 'e'); + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/libcxx/ranges/range.adaptors/range.join/range.join.iterator/types.h b/libcxx/test/libcxx/ranges/range.adaptors/range.join/range.join.iterator/types.h index a5b88ed01773c7..0652d4bdb4717c 100644 --- a/libcxx/test/libcxx/ranges/range.adaptors/range.join/range.join.iterator/types.h +++ b/libcxx/test/libcxx/ranges/range.adaptors/range.join/range.join.iterator/types.h @@ -15,12 +15,15 @@ #include "test_iterators.h" -template +template struct DieOnCopyIterator { using value_type = std::iter_value_t; using difference_type = std::iter_difference_t; - DieOnCopyIterator() = default; + DieOnCopyIterator() + requires std::default_initializable + = default; + constexpr explicit DieOnCopyIterator(Iter iter) : iter_(std::move(iter)) {} constexpr DieOnCopyIterator(DieOnCopyIterator&& other) = default; DieOnCopyIterator& operator=(DieOnCopyIterator&&) = default; @@ -62,6 +65,8 @@ struct DieOnCopyIterator { template explicit DieOnCopyIterator(Iter) -> DieOnCopyIterator; +static_assert(std::input_iterator>>); +static_assert(!std::forward_iterator>>); static_assert(std::forward_iterator>); static_assert(!std::bidirectional_iterator>); static_assert(std::sentinel_for, DieOnCopyIterator>); From 710398a5f10f949eab07ef4e2767f3619bad5e61 Mon Sep 17 00:00:00 2001 From: Jakub Mazurkiewicz Date: Tue, 5 Dec 2023 13:24:04 +0100 Subject: [PATCH 18/18] Address GCC's complaints --- .../range.join/range.join.iterator/ctor.parent.outer.pass.cpp | 4 ++-- .../range.join/range.join.iterator/ctor.parent.pass.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/libcxx/test/libcxx/ranges/range.adaptors/range.join/range.join.iterator/ctor.parent.outer.pass.cpp b/libcxx/test/libcxx/ranges/range.adaptors/range.join/range.join.iterator/ctor.parent.outer.pass.cpp index 9bf55f0a3423ae..a54980bec287fc 100644 --- a/libcxx/test/libcxx/ranges/range.adaptors/range.join/range.join.iterator/ctor.parent.outer.pass.cpp +++ b/libcxx/test/libcxx/ranges/range.adaptors/range.join/range.join.iterator/ctor.parent.outer.pass.cpp @@ -22,14 +22,14 @@ constexpr bool test() { std::string strings[4] = {"aaaa", "bbbb", "cccc", "dddd"}; { // Check if `outer_` is initialized with `std::move(outer)` for `iterator` - MoveOnAccessSubrange r(DieOnCopyIterator(strings), sentinel_wrapper(strings + 4)); + MoveOnAccessSubrange r{DieOnCopyIterator(strings), sentinel_wrapper(strings + 4)}; std::ranges::join_view jv(std::move(r)); auto iter = jv.begin(); // Calls `iterator(Parent& parent, OuterIter outer)` assert(*iter == 'a'); } { // Check if `outer_` is initialized with `std::move(outer)` for `iterator` - MoveOnAccessSubrange r(DieOnCopyIterator(strings), sentinel_wrapper(strings + 4)); + MoveOnAccessSubrange r{DieOnCopyIterator(strings), sentinel_wrapper(strings + 4)}; std::ranges::join_view jv(std::ranges::ref_view{r}); auto iter = std::as_const(jv).begin(); // Calls `iterator(Parent& parent, OuterIter outer)` assert(*iter == 'a'); diff --git a/libcxx/test/libcxx/ranges/range.adaptors/range.join/range.join.iterator/ctor.parent.pass.cpp b/libcxx/test/libcxx/ranges/range.adaptors/range.join/range.join.iterator/ctor.parent.pass.cpp index bb8debb642b993..3026a02abf00f3 100644 --- a/libcxx/test/libcxx/ranges/range.adaptors/range.join/range.join.iterator/ctor.parent.pass.cpp +++ b/libcxx/test/libcxx/ranges/range.adaptors/range.join/range.join.iterator/ctor.parent.pass.cpp @@ -19,8 +19,8 @@ constexpr bool test() { std::string strings[4] = {"eeee", "ffff", "gggg", "hhhh"}; - MoveOnAccessSubrange r( - DieOnCopyIterator(cpp20_input_iterator(strings)), sentinel_wrapper(cpp20_input_iterator(strings + 4))); + MoveOnAccessSubrange r{ + DieOnCopyIterator(cpp20_input_iterator(strings)), sentinel_wrapper(cpp20_input_iterator(strings + 4))}; std::ranges::join_view jv(std::move(r)); auto iter = jv.begin(); // Calls `iterator(Parent& parent)` assert(*iter == 'e');