diff --git a/libcxx/docs/Status/Cxx23.rst b/libcxx/docs/Status/Cxx23.rst index 839640a7c7e88..3e6e33f08c7cc 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 5cc9e488297b9..4f84af4df31bc 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 cdab2c36eab74..8d9f795da977e 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 d8faf6467b79a..533b7ac9103ab 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 e6240dfd2580d..f80beda33b11e 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,12 +163,12 @@ namespace ranges { requires view<_View> && input_range> template struct join_view<_View>::__sentinel { - template + private: + template friend struct __sentinel; - private: - using _Parent = __maybe_const<_Const, join_view<_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: @@ -179,7 +188,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 +200,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; @@ -207,23 +214,25 @@ 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>; - public: - _Outer __outer_ = _Outer(); + static constexpr bool _OuterPresent = forward_range<_Base>; + using _OuterType = _If<_OuterPresent, _Outer, std::__empty>; + _LIBCPP_NO_UNIQUE_ADDRESS _OuterType __outer_ = _OuterType(); - private: optional<_Inner> __inner_; - _Parent *__parent_ = nullptr; + _Parent* __parent_ = nullptr; _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 explicit __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(std::__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(std::__as_lvalue(*--__outer_)); // Skip empty inner ranges when going backwards. - while (*__inner_ == ranges::begin(*__outer_)) { - __inner_ = ranges::end(*--__outer_); + while (*__inner_ == ranges::begin(std::__as_lvalue(*__outer_))) { + __inner_ = ranges::end(std::__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 0000000000000..159f45dad4d41 --- /dev/null +++ b/libcxx/include/__utility/as_lvalue.h @@ -0,0 +1,37 @@ +// -*- 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 + +#ifndef _LIBCPP_CXX03_LANG + +template +_LIBCPP_HIDE_FROM_ABI constexpr _Tp& __as_lvalue(_LIBCPP_LIFETIMEBOUND _Tp&& __t) { + return static_cast<_Tp&>(__t); +} + +#endif // !_LIBCPP_CXX03_LANG + +_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 90ee7fbb2157c..7e93e0a155033 100644 --- a/libcxx/include/module.modulemap.in +++ b/libcxx/include/module.modulemap.in @@ -2019,6 +2019,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 4424af8d37db0..e2559d255dcdd 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 c5581d55e79bb..1deef3db20410 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 a883103d81258..82c7d99f8979a 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.lifetimebound.verify.cpp b/libcxx/test/libcxx/ranges/range.adaptors/range.adaptor.helpers/as-lvalue.lifetimebound.verify.cpp new file mode 100644 index 0000000000000..7046936b1b7a7 --- /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.pass.cpp b/libcxx/test/libcxx/ranges/range.adaptors/range.adaptor.helpers/as-lvalue.pass.cpp new file mode 100644 index 0000000000000..721279fcd586b --- /dev/null +++ b/libcxx/test/libcxx/ranges/range.adaptors/range.adaptor.helpers/as-lvalue.pass.cpp @@ -0,0 +1,40 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// template +// constexpr T& as-lvalue(T&& t) { // exposition only + +#include +#include + +constexpr bool test() { + // Check glvalue + { + int lvalue{}; + [[maybe_unused]] decltype(auto) check = std::__as_lvalue(lvalue); + static_assert(std::is_same::value, ""); + } + + // Check xvalue + { + int xvalue{}; + [[maybe_unused]] decltype(auto) check = std::__as_lvalue(std::move(xvalue)); + static_assert(std::is_same::value, ""); + } + + 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/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 0000000000000..a54980bec287f --- /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/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 0000000000000..3026a02abf00f --- /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 new file mode 100644 index 0000000000000..0652d4bdb4717 --- /dev/null +++ b/libcxx/test/libcxx/ranges/range.adaptors/range.join/range.join.iterator/types.h @@ -0,0 +1,114 @@ +//===----------------------------------------------------------------------===// +// +// 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() + requires std::default_initializable + = 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::input_iterator>>); +static_assert(!std::forward_iterator>>); +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 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 82e8cab503a27..6cd17c2b3f353 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 50fb479afcd06..ec60ab8db1609 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 feca8fd3be858..343447446ab2d 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/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 c434cea1208cf..efeada5762558 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 eae40cefa663f..7da0f30775905 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 2df6a10b18504..e29ba8af07d6f 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 0f0a71439a10d..50f371a6d64d3 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 e6c0e09dfff5f..060f179fe1683 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 09b77c0901a22..5efd6c72a13db 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 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 215318f15cad0..0000000000000 --- 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 afaf322721099..9beb3d282a27c 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 13883e894ac7b..caf018b582263 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 9e4fa5f8c59a4..005d0d1d2d5cb 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 2c470991be0b6..a8eafc5a9c021 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 eddc950747ba7..2c6eea500580d 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 26206e32c358c..0daff7d3b3c98 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 ce5393062d778..75d4c7e5916b0 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 7e225202cc231..516ba25a0e859 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 e9eab585260cd..f92eb418fac77 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/lwg3698.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.join/lwg3698.pass.cpp new file mode 100644 index 0000000000000..0abe37bf17f7e --- /dev/null +++ b/libcxx/test/std/ranges/range.adaptors/range.join/lwg3698.pass.cpp @@ -0,0 +1,33 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// 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"}))); + + return 0; +} 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 e610cde2c3b5b..ddcf66bfe775e 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 e4f193e4e6064..82fe824fad1b2 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 a0406f90c88c6..e220b2cfeac84 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 4363fb0e330c3..29720d93bab66 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 327cc82b06b08..5c831f33e67c7 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 4bcb4de7e9c88..dada91462a73f 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 0bf6aa3d92614..917e72dc85854 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 e9b73f1a41596..28e1bf75726f6 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 17b98facd6508..b9b9d73d77e26 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 fa6f7bb031207..73457b826df0b 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 0eebe14af3fcb..42fcc733e181f 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 96196dcbaa5b3..5ef3e7416ef10 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 a9df7c3881ba8..1ac68277338fe 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 cbd03b84f208b..bc7d4bec94d3e 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 b2ef5f090b573..c1378dc1144b4 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 6f2da091c3709..ad61baa76018d 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 7d30b0adcc234..8ee2c5006d31c 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 397226552edee..23eea7f369c17 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 73ad58f4eecfb..a9c18e8a1b77a 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**)