[libcxx-commits] [llvm] [clang] [clang-tools-extra] [libcxx] [libc++] P2770R0: "Stashing stashing iterators for proper flattening" (PR #66033)
Jakub Mazurkiewicz via libcxx-commits
libcxx-commits at lists.llvm.org
Tue Dec 5 03:38:56 PST 2023
https://github.com/JMazurkiewicz updated https://github.com/llvm/llvm-project/pull/66033
>From 600a282d49011782fde23c4388ba1346284153a1 Mon Sep 17 00:00:00 2001
From: Jakub Mazurkiewicz <mazkuba3 at gmail.com>
Date: Fri, 8 Sep 2023 18:20:59 +0200
Subject: [PATCH 01/17] [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 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 19b1dd8eb5a44..38b77d42ec5b9 100644
--- a/libcxx/docs/Status/Cxx23Papers.csv
+++ b/libcxx/docs/Status/Cxx23Papers.csv
@@ -104,7 +104,7 @@
"`P2708R1 <https://wg21.link/P2708R1>`__","LWG", "No Further Fundamentals TSes", "November 2022","|Nothing to do|","",""
"","","","","","",""
"`P0290R4 <https://wg21.link/P0290R4>`__","LWG", "``apply()`` for ``synchronized_value<T>``","February 2023","","","|concurrency TS|"
-"`P2770R0 <https://wg21.link/P2770R0>`__","LWG", "Stashing stashing ``iterators`` for proper flattening","February 2023","|In Progress|","","|ranges|"
+"`P2770R0 <https://wg21.link/P2770R0>`__","LWG", "Stashing stashing ``iterators`` for proper flattening","February 2023","|Partial| [#note-P2770R0]_","","|ranges|"
"`P2164R9 <https://wg21.link/P2164R9>`__","LWG", "``views::enumerate``","February 2023","","","|ranges|"
"`P2711R1 <https://wg21.link/P2711R1>`__","LWG", "Making multi-param constructors of ``views`` ``explicit``","February 2023","|In Progress| [#note-P2711R1]_","","|ranges|"
"`P2609R3 <https://wg21.link/P2609R3>`__","LWG", "Relaxing Ranges Just A Smidge","February 2023","","","|ranges|"
diff --git a/libcxx/docs/UsingLibcxx.rst b/libcxx/docs/UsingLibcxx.rst
index 24d6a7b95f5b2..2d52a7c9ef2b8 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 889d7fedbf296..7aad3a4c62434 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..812a6f9379a85 100644
--- a/libcxx/include/__ranges/join_view.h
+++ b/libcxx/include/__ranges/join_view.h
@@ -32,6 +32,8 @@
#include <__ranges/view_interface.h>
#include <__type_traits/common_type.h>
#include <__type_traits/maybe_const.h>
+#include <__utility/as_lvalue.h>
+#include <__utility/empty.h>
#include <__utility/forward.h>
#include <optional>
@@ -41,10 +43,7 @@
_LIBCPP_BEGIN_NAMESPACE_STD
-// Note: `join_view` is still marked experimental because there is an ABI-breaking change that affects `join_view` in
-// the pipeline (https://isocpp.org/files/papers/D2770R0.html).
-// TODO: make `join_view` non-experimental once D2770 is implemented.
-#if _LIBCPP_STD_VER >= 20 && defined(_LIBCPP_ENABLE_EXPERIMENTAL)
+#if _LIBCPP_STD_VER >= 20
namespace ranges {
template<class>
@@ -84,11 +83,16 @@ namespace ranges {
template <class>
friend struct std::__segmented_iterator_traits;
- static constexpr bool _UseCache = !is_reference_v<_InnerRange>;
- using _Cache = _If<_UseCache, __non_propagating_cache<remove_cvref_t<_InnerRange>>, __empty_cache>;
- _LIBCPP_NO_UNIQUE_ADDRESS _Cache __cache_;
_LIBCPP_NO_UNIQUE_ADDRESS _View __base_ = _View();
+ static constexpr bool _UseOuterCache = !forward_range<_View>;
+ using _OuterCache = _If<_UseOuterCache, __non_propagating_cache<iterator_t<_View>>, __empty_cache>;
+ _LIBCPP_NO_UNIQUE_ADDRESS _OuterCache __outer_;
+
+ static constexpr bool _UseInnerCache = !is_reference_v<_InnerRange>;
+ using _InnerCache = _If<_UseInnerCache, __non_propagating_cache<remove_cvref_t<_InnerRange>>, __empty_cache>;
+ _LIBCPP_NO_UNIQUE_ADDRESS _InnerCache __inner_;
+
public:
_LIBCPP_HIDE_FROM_ABI
join_view() requires default_initializable<_View> = default;
@@ -105,16 +109,22 @@ namespace ranges {
_LIBCPP_HIDE_FROM_ABI
constexpr auto begin() {
- constexpr bool __use_const = __simple_view<_View> &&
- is_reference_v<range_reference_t<_View>>;
- return __iterator<__use_const>{*this, ranges::begin(__base_)};
+ if constexpr (forward_range<_View>) {
+ constexpr bool __use_const = __simple_view<_View> &&
+ is_reference_v<range_reference_t<_View>>;
+ return __iterator<__use_const>{*this, ranges::begin(__base_)};
+ } else {
+ __outer_.__emplace(ranges::begin(__base_));
+ return __iterator<false>{*this};
+ }
}
template<class _V2 = _View>
_LIBCPP_HIDE_FROM_ABI
constexpr auto begin() const
- requires input_range<const _V2> &&
- is_reference_v<range_reference_t<const _V2>>
+ requires forward_range<const _V2> &&
+ is_reference_v<range_reference_t<const _V2>> &&
+ input_range<range_reference_t<const _V2>>
{
return __iterator<true>{*this, ranges::begin(__base_)};
}
@@ -134,13 +144,12 @@ namespace ranges {
template<class _V2 = _View>
_LIBCPP_HIDE_FROM_ABI
constexpr auto end() const
- requires input_range<const _V2> &&
- is_reference_v<range_reference_t<const _V2>>
+ requires forward_range<const _V2> &&
+ is_reference_v<range_reference_t<const _V2>> &&
+ input_range<range_reference_t<const _V2>>
{
using _ConstInnerRange = range_reference_t<const _View>;
- if constexpr (forward_range<const _View> &&
- is_reference_v<_ConstInnerRange> &&
- forward_range<_ConstInnerRange> &&
+ if constexpr (forward_range<_ConstInnerRange> &&
common_range<const _View> &&
common_range<_ConstInnerRange>) {
return __iterator<true>{*this, ranges::end(__base_)};
@@ -154,11 +163,10 @@ namespace ranges {
requires view<_View> && input_range<range_reference_t<_View>>
template<bool _Const>
struct join_view<_View>::__sentinel {
- template<bool>
- friend struct __sentinel;
-
private:
- using _Parent = __maybe_const<_Const, join_view<_View>>;
+ friend join_view;
+
+ using _Parent = __maybe_const<_Const, join_view>;
using _Base = __maybe_const<_Const, _View>;
sentinel_t<_Base> __end_ = sentinel_t<_Base>();
@@ -179,7 +187,7 @@ namespace ranges {
requires sentinel_for<sentinel_t<_Base>, iterator_t<__maybe_const<_OtherConst, _View>>>
_LIBCPP_HIDE_FROM_ABI
friend constexpr bool operator==(const __iterator<_OtherConst>& __x, const __sentinel& __y) {
- return __x.__outer_ == __y.__end_;
+ return __x.__get_outer() == __y.__end_;
}
};
@@ -191,9 +199,7 @@ namespace ranges {
template<bool _Const>
struct join_view<_View>::__iterator final
: public __join_view_iterator_category<__maybe_const<_Const, _View>> {
-
- template<bool>
- friend struct __iterator;
+ friend join_view;
template <class>
friend struct std::__segmented_iterator_traits;
@@ -209,8 +215,11 @@ namespace ranges {
static constexpr bool __ref_is_glvalue = is_reference_v<range_reference_t<_Base>>;
+ static constexpr bool _OuterPresent = forward_range<_Base>;
+ using _OuterType = _If<_OuterPresent, _Outer, std::__empty>;
+
public:
- _Outer __outer_ = _Outer();
+ _LIBCPP_NO_UNIQUE_ADDRESS _OuterType __outer_ = _OuterType();
private:
optional<_Inner> __inner_;
@@ -218,12 +227,12 @@ namespace ranges {
_LIBCPP_HIDE_FROM_ABI
constexpr void __satisfy() {
- for (; __outer_ != ranges::end(__parent_->__base_); ++__outer_) {
- auto&& __inner = [&]() -> auto&& {
+ for (; __get_outer() != ranges::end(__parent_->__base_); ++__get_outer()) {
+ auto&& __inner = [this]() -> auto&& {
if constexpr (__ref_is_glvalue)
- return *__outer_;
+ return *__get_outer();
else
- return __parent_->__cache_.__emplace_from([&]() -> decltype(auto) { return *__outer_; });
+ return __parent_->__inner_.__emplace_from([&]() -> decltype(auto) { return *__get_outer(); });
}();
__inner_ = ranges::begin(__inner);
if (*__inner_ != ranges::end(__inner))
@@ -234,8 +243,37 @@ namespace ranges {
__inner_.reset();
}
+ _LIBCPP_HIDE_FROM_ABI constexpr _Outer& __get_outer() {
+ if constexpr (forward_range<_Base>) {
+ return __outer_;
+ } else {
+ return *__parent_->__outer_;
+ }
+ }
+
+ _LIBCPP_HIDE_FROM_ABI constexpr const _Outer& __get_outer() const {
+ if constexpr (forward_range<_Base>) {
+ return __outer_;
+ } else {
+ return *__parent_->__outer_;
+ }
+ }
+
+ _LIBCPP_HIDE_FROM_ABI constexpr __iterator(_Parent& __parent, _Outer __outer)
+ requires forward_range<_Base>
+ : __outer_(std::move(__outer)), __parent_(std::addressof(__parent)) {
+ __satisfy();
+ }
+
+ _LIBCPP_HIDE_FROM_ABI constexpr __iterator(_Parent& __parent)
+ requires(!forward_range<_Base>)
+ : __parent_(std::addressof(__parent)) {
+ __satisfy();
+ }
+
_LIBCPP_HIDE_FROM_ABI constexpr __iterator(_Parent* __parent, _Outer __outer, _Inner __inner)
- : __outer_(std::move(__outer)), __inner_(std::move(__inner)), __parent_(__parent) {}
+ requires forward_range<_Base>
+ : __outer_(std::move(__outer)), __inner_(std::move(__inner)), __parent_(__parent) {}
public:
using iterator_concept = _If<
@@ -254,15 +292,7 @@ namespace ranges {
using difference_type = common_type_t<
range_difference_t<_Base>, range_difference_t<range_reference_t<_Base>>>;
- _LIBCPP_HIDE_FROM_ABI
- __iterator() requires default_initializable<_Outer> = default;
-
- _LIBCPP_HIDE_FROM_ABI
- constexpr __iterator(_Parent& __parent, _Outer __outer)
- : __outer_(std::move(__outer))
- , __parent_(std::addressof(__parent)) {
- __satisfy();
- }
+ _LIBCPP_HIDE_FROM_ABI __iterator() = default;
_LIBCPP_HIDE_FROM_ABI
constexpr __iterator(__iterator<!_Const> __i)
@@ -287,14 +317,14 @@ namespace ranges {
_LIBCPP_HIDE_FROM_ABI
constexpr __iterator& operator++() {
- auto&& __inner = [&]() -> auto&& {
+ auto __get_inner_range = [&]() -> decltype(auto) {
if constexpr (__ref_is_glvalue)
- return *__outer_;
+ return *__get_outer();
else
- return *__parent_->__cache_;
- }();
- if (++*__inner_ == ranges::end(__inner)) {
- ++__outer_;
+ return *__parent_->__inner_;
+ };
+ if (++*__inner_ == ranges::end(ranges::__as_lvalue(__get_inner_range()))) {
+ ++__get_outer();
__satisfy();
}
return *this;
@@ -324,11 +354,11 @@ namespace ranges {
common_range<range_reference_t<_Base>>
{
if (__outer_ == ranges::end(__parent_->__base_))
- __inner_ = ranges::end(*--__outer_);
+ __inner_ = ranges::end(ranges::__as_lvalue(*--__outer_));
// Skip empty inner ranges when going backwards.
- while (*__inner_ == ranges::begin(*__outer_)) {
- __inner_ = ranges::end(*--__outer_);
+ while (*__inner_ == ranges::begin(ranges::__as_lvalue(*__outer_))) {
+ __inner_ = ranges::end(ranges::__as_lvalue(*--__outer_));
}
--*__inner_;
@@ -350,7 +380,7 @@ namespace ranges {
_LIBCPP_HIDE_FROM_ABI
friend constexpr bool operator==(const __iterator& __x, const __iterator& __y)
requires __ref_is_glvalue &&
- equality_comparable<iterator_t<_Base>> &&
+ forward_range<_Base> &&
equality_comparable<iterator_t<range_reference_t<_Base>>>
{
return __x.__outer_ == __y.__outer_ && __x.__inner_ == __y.__inner_;
@@ -436,7 +466,7 @@ struct __segmented_iterator_traits<_JoinViewIterator> {
}
};
-#endif // #if _LIBCPP_STD_VER >= 20 && defined(_LIBCPP_ENABLE_EXPERIMENTAL)
+#endif // #if _LIBCPP_STD_VER >= 20
_LIBCPP_END_NAMESPACE_STD
diff --git a/libcxx/include/__utility/as_lvalue.h b/libcxx/include/__utility/as_lvalue.h
new file mode 100644
index 0000000000000..b4df650edbf65
--- /dev/null
+++ b/libcxx/include/__utility/as_lvalue.h
@@ -0,0 +1,39 @@
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef _LIBCPP___UTILITY_AS_LVALUE_H
+#define _LIBCPP___UTILITY_AS_LVALUE_H
+
+#include <__config>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+# pragma GCC system_header
+#endif
+
+_LIBCPP_PUSH_MACROS
+#include <__undef_macros>
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+#if _LIBCPP_STD_VER >= 20
+
+namespace ranges {
+template <class _Tp>
+_LIBCPP_HIDE_FROM_ABI constexpr _Tp& __as_lvalue(_LIBCPP_LIFETIMEBOUND _Tp&& __t) {
+ return static_cast<_Tp&>(__t);
+}
+} // namespace ranges
+
+#endif // _LIBCPP_STD_VER >= 20
+
+_LIBCPP_END_NAMESPACE_STD
+
+_LIBCPP_POP_MACROS
+
+#endif // _LIBCPP___UTILITY_AS_LVALUE_H
diff --git a/libcxx/include/module.modulemap.in b/libcxx/include/module.modulemap.in
index 17ebe48f32996..8364dde16ccf9 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 e8865ac1089d6..59d3af2a4bcb3 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 <class T>
#include <__assert> // all public C++ headers provide the assertion handler
#include <__config>
#include <__utility/as_const.h>
+#include <__utility/as_lvalue.h>
#include <__utility/auto_cast.h>
#include <__utility/cmp.h>
#include <__utility/declval.h>
diff --git a/libcxx/modules/std/ranges.inc b/libcxx/modules/std/ranges.inc
index 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.verify.cpp b/libcxx/test/libcxx/ranges/range.adaptors/range.adaptor.helpers/as-lvalue.verify.cpp
new file mode 100644
index 0000000000000..878ef91b13839
--- /dev/null
+++ b/libcxx/test/libcxx/ranges/range.adaptors/range.adaptor.helpers/as-lvalue.verify.cpp
@@ -0,0 +1,48 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+
+// <ranges>
+
+// template<class T>
+// constexpr T& as-lvalue(T&& t) { // exposition only
+
+#include <ranges>
+
+#include <concepts>
+#include <utility>
+
+constexpr bool test() {
+ // Check glvalue
+ {
+ int lvalue{};
+ [[maybe_unused]] std::same_as<int&> decltype(auto) check = std::ranges::__as_lvalue(lvalue);
+ }
+
+ // Check prvalue
+ {
+ [[maybe_unused]] std::same_as<int&> decltype(auto) check = std::ranges::__as_lvalue(
+ 0); // expected-warning {{temporary bound to local reference 'check' will be destroyed at the end of the full-expression}}
+ }
+
+ // Check xvalue
+ {
+ int xvalue{};
+ [[maybe_unused]] std::same_as<int&> decltype(auto) check = std::ranges::__as_lvalue(std::move(xvalue));
+ }
+
+ return true;
+}
+
+int main(int, char**) {
+ test();
+ static_assert(test());
+
+ return 0;
+}
diff --git a/libcxx/test/libcxx/ranges/range.adaptors/range.adaptor.tuple/tuple-for-each.pass.cpp b/libcxx/test/libcxx/ranges/range.adaptors/range.adaptor.helpers/tuple-for-each.pass.cpp
similarity index 100%
rename from libcxx/test/libcxx/ranges/range.adaptors/range.adaptor.tuple/tuple-for-each.pass.cpp
rename to libcxx/test/libcxx/ranges/range.adaptors/range.adaptor.helpers/tuple-for-each.pass.cpp
diff --git a/libcxx/test/libcxx/ranges/range.adaptors/range.join/segmented_iterator.compile.pass.cpp b/libcxx/test/libcxx/ranges/range.adaptors/range.join/segmented_iterator.compile.pass.cpp
index 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 <ranges>
#include <utility>
diff --git a/libcxx/test/std/algorithms/alg.modifying.operations/alg.copy/ranges.copy.segmented.pass.cpp b/libcxx/test/std/algorithms/alg.modifying.operations/alg.copy/ranges.copy.segmented.pass.cpp
index 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 <algorithm>
#include <array>
diff --git a/libcxx/test/std/algorithms/alg.modifying.operations/alg.copy/ranges.copy_backward.pass.cpp b/libcxx/test/std/algorithms/alg.modifying.operations/alg.copy/ranges.copy_backward.pass.cpp
index 184008c3e2fd0..301fbcbc533c2 100644
--- a/libcxx/test/std/algorithms/alg.modifying.operations/alg.copy/ranges.copy_backward.pass.cpp
+++ b/libcxx/test/std/algorithms/alg.modifying.operations/alg.copy/ranges.copy_backward.pass.cpp
@@ -9,8 +9,6 @@
// <algorithm>
// UNSUPPORTED: c++03, c++11, c++14, c++17
-// TODO: make `join_view` non-experimental once D2770 is implemented.
-// UNSUPPORTED: !c++experimental
// UNSUPPORTED: GCC-ALWAYS_INLINE-FIXME
// template<bidirectional_iterator I1, sentinel_for<I1> S1, bidirectional_iterator I2>
diff --git a/libcxx/test/std/ranges/range.adaptors/range.join.view/iterator/ctor.parent.outer.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.join.view/iterator/ctor.parent.outer.pass.cpp
deleted file mode 100644
index 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 <cassert>
-#include <ranges>
-
-#include "../types.h"
-
-using NonDefaultCtrIter = cpp20_input_iterator<int*>;
-static_assert(!std::default_initializable<NonDefaultCtrIter>);
-
-using NonDefaultCtrIterView = BufferView<NonDefaultCtrIter, sentinel_wrapper<NonDefaultCtrIter>>;
-static_assert(std::ranges::input_range<NonDefaultCtrIterView>);
-
-constexpr bool test() {
- int buffer[4][4] = {{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}, {13, 14, 15, 16}};
- {
- CopyableChild children[4] = {CopyableChild(buffer[0]), CopyableChild(buffer[1]), CopyableChild(buffer[2]),
- CopyableChild(buffer[3])};
- CopyableParent parent{children};
- std::ranges::join_view jv(parent);
- std::ranges::iterator_t<decltype(jv)> iter(jv, std::ranges::begin(parent));
- assert(*iter == 1);
- }
-
- {
- // LWG3569 Inner iterator not default_initializable
- // With the current spec, the constructor under test invokes Inner iterator's default constructor
- // even if it is not default constructible
- // This test is checking that this constructor can be invoked with an inner range with non default
- // constructible iterator
- NonDefaultCtrIterView inners[] = {buffer[0], buffer[1]};
- auto outer = std::views::all(inners);
- std::ranges::join_view jv(outer);
- std::ranges::iterator_t<decltype(jv)> iter(jv, std::ranges::begin(outer));
- assert(*iter == 1);
- }
-
- return true;
-}
-
-int main(int, char**) {
- test();
- static_assert(test());
-
- return 0;
-}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.join.view/adaptor.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.join/adaptor.pass.cpp
similarity index 99%
rename from libcxx/test/std/ranges/range.adaptors/range.join.view/adaptor.pass.cpp
rename to libcxx/test/std/ranges/range.adaptors/range.join/adaptor.pass.cpp
index 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<V>;
// constexpr V base() &&;
diff --git a/libcxx/test/std/ranges/range.adaptors/range.join.view/begin.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.join/begin.pass.cpp
similarity index 83%
rename from libcxx/test/std/ranges/range.adaptors/range.join.view/begin.pass.cpp
rename to libcxx/test/std/ranges/range.adaptors/range.join/begin.pass.cpp
index 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<const V> &&
-// is_reference_v<range_reference_t<const V>>;
+// requires forward_range<const V> &&
+// is_reference_v<range_reference_t<const V>> &&
+// input_range<range_reference_t<const V>>;
+#include <algorithm>
#include <cassert>
#include <ranges>
+#include <string_view>
#include "types.h"
@@ -120,7 +122,7 @@ constexpr bool test() {
static_assert(HasConstBegin<decltype(jv)>);
}
- // !input_range<const V>
+ // !forward_range<const V>
{
std::ranges::join_view jv{ConstNotRange{}};
static_assert(!HasConstBegin<decltype(jv)>);
@@ -146,6 +148,27 @@ constexpr bool test() {
static_assert(std::same_as<decltype(jv.begin()), decltype(std::as_const(jv).begin())>);
}
+ // Check stashing iterators (LWG3698: regex_iterator and join_view don't work together very well)
+ {
+ std::ranges::join_view<StashingRange> jv;
+ assert(std::ranges::equal(std::views::counted(jv.begin(), 10), std::string_view{"aababcabcd"}));
+ }
+
+ // LWG3700: The `const begin` of the `join_view` family does not require `InnerRng` to be a range
+ {
+ std::ranges::join_view<ConstNonJoinableRange> jv;
+ static_assert(!HasConstBegin<decltype(jv)>);
+ }
+
+ // Check example from LWG3700
+ {
+ auto r = std::views::iota(0, 5) | std::views::split(1);
+ auto s = std::views::single(r);
+ auto j = s | std::views::join;
+ auto f = j.front();
+ assert(std::ranges::equal(f, std::views::single(0)));
+ }
+
return true;
}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.join.view/ctad.compile.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.join/ctad.compile.pass.cpp
similarity index 98%
rename from libcxx/test/std/ranges/range.adaptors/range.join.view/ctad.compile.pass.cpp
rename to libcxx/test/std/ranges/range.adaptors/range.join/ctad.compile.pass.cpp
index 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<class R>
// explicit join_view(R&&) -> join_view<views::all_t<R>>;
diff --git a/libcxx/test/std/ranges/range.adaptors/range.join.view/ctad.verify.cpp b/libcxx/test/std/ranges/range.adaptors/range.join/ctad.verify.cpp
similarity index 97%
rename from libcxx/test/std/ranges/range.adaptors/range.join.view/ctad.verify.cpp
rename to libcxx/test/std/ranges/range.adaptors/range.join/ctad.verify.cpp
index 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<class R>
// explicit join_view(R&&) -> join_view<views::all_t<R>>;
diff --git a/libcxx/test/std/ranges/range.adaptors/range.join.view/ctor.default.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.join/ctor.default.pass.cpp
similarity index 97%
rename from libcxx/test/std/ranges/range.adaptors/range.join.view/ctor.default.pass.cpp
rename to libcxx/test/std/ranges/range.adaptors/range.join/ctor.default.pass.cpp
index 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<V> = default;
diff --git a/libcxx/test/std/ranges/range.adaptors/range.join.view/ctor.view.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.join/ctor.view.pass.cpp
similarity index 97%
rename from libcxx/test/std/ranges/range.adaptors/range.join.view/ctor.view.pass.cpp
rename to libcxx/test/std/ranges/range.adaptors/range.join/ctor.view.pass.cpp
index 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<const V> &&
+// is_reference_v<range_reference_t<const V>> &&
+// input_range<range_reference_t<const V>>
#include <cassert>
#include <ranges>
@@ -33,13 +35,13 @@ concept HasConstEnd = requires (const T& t){
// | 3 | Y | Y | Y | Y | N | Y |sentinel<true> |sentinel<true>|
// | 4 | Y | Y | Y | N | Y | Y |sentinel<true> | - |
// | 5 | Y | Y | N | Y | Y | Y |sentinel<true> |sentinel<true>|
-// | 6 | Y | N | Y | Y | Y | Y |sentinel<true> |sentinel<true>|
+// | 6 | Y | N | Y | Y | Y | Y |sentinel<true> | - |
// | 7 | N | Y | Y | Y | Y | Y |iterator<false>|iterator<true>|
// | 8 | N | Y | Y | Y | Y | N |sentinel<false>|sentinel<true>|
// | 9 | N | Y | Y | Y | N | Y |sentinel<false>|sentinel<true>|
// | 10 | N | Y | Y | N | Y | Y |sentinel<false>| - |
// | 11 | N | Y | N | Y | Y | Y |sentinel<false>|sentinel<true>|
-// | 12 | N | N | Y | Y | Y | Y |sentinel<false>|sentinel<true>|
+// | 12 | N | N | Y | Y | Y | Y |sentinel<false>| - |
//
//
@@ -131,10 +133,8 @@ constexpr bool test() {
std::ranges::join_view jv(outer);
assert(jv.end() == std::ranges::next(jv.begin(), 16));
- assert(std::as_const(jv).end() == std::ranges::next(std::as_const(jv).begin(), 16));
- static_assert(HasConstEnd<decltype(jv)>);
- static_assert(std::same_as<decltype(jv.end()), decltype(std::as_const(jv).end())>);
+ static_assert(!HasConstEnd<decltype(jv)>);
static_assert(!std::ranges::common_range<decltype(jv)>);
static_assert(!std::ranges::common_range<const decltype(jv)>);
}
@@ -219,10 +219,8 @@ constexpr bool test() {
std::ranges::join_view jv(outer);
assert(jv.end() == std::ranges::next(jv.begin(), 16));
- assert(std::as_const(jv).end() == std::ranges::next(std::as_const(jv).begin(), 16));
- static_assert(HasConstEnd<decltype(jv)>);
- static_assert(!std::same_as<decltype(jv.end()), decltype(std::as_const(jv).end())>);
+ static_assert(!HasConstEnd<decltype(jv)>);
static_assert(!std::ranges::common_range<decltype(jv)>);
static_assert(!std::ranges::common_range<const decltype(jv)>);
}
@@ -288,6 +286,12 @@ constexpr bool test() {
assert(jv.end() == std::ranges::next(jv.begin(), 12));
}
+ // LWG3700: The `const begin` of the `join_view` family does not require `InnerRng` to be a range
+ {
+ std::ranges::join_view<ConstNonJoinableRange> jv;
+ static_assert(!HasConstEnd<decltype(jv)>);
+ }
+
return true;
}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.join.view/general.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.join/general.pass.cpp
similarity index 98%
rename from libcxx/test/std/ranges/range.adaptors/range.join.view/general.pass.cpp
rename to libcxx/test/std/ranges/range.adaptors/range.join/general.pass.cpp
index 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.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<InnerIter> && copyable<InnerIter>;
diff --git a/libcxx/test/std/ranges/range.adaptors/range.join.view/iterator/ctor.default.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.join/range.join.iterator/ctor.default.pass.cpp
similarity index 70%
rename from libcxx/test/std/ranges/range.adaptors/range.join.view/iterator/ctor.default.pass.cpp
rename to libcxx/test/std/ranges/range.adaptors/range.join/range.join.iterator/ctor.default.pass.cpp
index 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<OuterIter> = default;
+// iterator() = default;
#include <ranges>
@@ -29,19 +28,12 @@ constexpr void test_default_constructible() {
using JoinView = std::ranges::join_view<view<It>>;
using JoinIterator = std::ranges::iterator_t<JoinView>;
static_assert(std::is_default_constructible_v<JoinIterator>);
- JoinIterator it; (void)it;
-}
-
-template <class It>
-constexpr void test_non_default_constructible() {
- using JoinView = std::ranges::join_view<view<It>>;
- using JoinIterator = std::ranges::iterator_t<JoinView>;
- static_assert(!std::is_default_constructible_v<JoinIterator>);
+ [[maybe_unused]] JoinIterator it;
}
constexpr bool test() {
- test_non_default_constructible<cpp17_input_iterator<ChildView*>>();
- // NOTE: cpp20_input_iterator can't be used with join_view because it is not copyable.
+ test_default_constructible<cpp17_input_iterator<ChildView*>>();
+ test_default_constructible<cpp20_input_iterator<ChildView*>>();
test_default_constructible<forward_iterator<ChildView*>>();
test_default_constructible<bidirectional_iterator<ChildView*>>();
test_default_constructible<random_access_iterator<ChildView*>>();
diff --git a/libcxx/test/std/ranges/range.adaptors/range.join.view/iterator/ctor.other.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.join/range.join.iterator/ctor.other.pass.cpp
similarity index 97%
rename from libcxx/test/std/ranges/range.adaptors/range.join.view/iterator/ctor.other.pass.cpp
rename to libcxx/test/std/ranges/range.adaptors/range.join/range.join.iterator/ctor.other.pass.cpp
index 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<!Const> i)
// requires Const &&
@@ -37,7 +36,7 @@ constexpr bool test() {
{
CopyableChild children[4] = {CopyableChild(buffer[0]), CopyableChild(buffer[1]), CopyableChild(buffer[2]),
CopyableChild(buffer[3])};
- std::ranges::join_view jv(CopyableParent{children});
+ std::ranges::join_view jv(ForwardCopyableParent{children});
auto iter1 = jv.begin();
using iterator = decltype(iter1);
using const_iterator = decltype(std::as_const(jv).begin());
diff --git a/libcxx/test/std/ranges/range.adaptors/range.join.view/iterator/decrement.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.join/range.join.iterator/decrement.pass.cpp
similarity index 90%
rename from libcxx/test/std/ranges/range.adaptors/range.join.view/iterator/decrement.pass.cpp
rename to libcxx/test/std/ranges/range.adaptors/range.join/range.join.iterator/decrement.pass.cpp
index 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<Base> &&
@@ -18,9 +17,12 @@
// bidirectional_range<range_reference_t<Base>> &&
// common_range<range_reference_t<Base>>;
+#include <algorithm>
+#include <array>
#include <cassert>
#include <ranges>
#include <type_traits>
+#include <vector>
#include "../types.h"
@@ -150,6 +152,15 @@ constexpr bool test() {
static_assert(!CanPostDecrement<decltype(iter)>);
}
+ {
+ // LWG3791: `join_view::iterator::operator--` may be ill-formed
+ std::vector<std::vector<int>> vec = {{1, 2}, {3, 4}, {5, 6}};
+ auto r = vec | std::views::transform([](auto& x) -> auto&& { return std::move(x); }) | std::views::join;
+ auto e = --r.end();
+ assert(*e == 6);
+ assert(std::ranges::equal(std::views::reverse(r), std::array{6, 5, 4, 3, 2, 1}));
+ }
+
return true;
}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.join.view/iterator/eq.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.join/range.join.iterator/eq.pass.cpp
similarity index 89%
rename from libcxx/test/std/ranges/range.adaptors/range.join.view/iterator/eq.pass.cpp
rename to libcxx/test/std/ranges/range.adaptors/range.join/range.join.iterator/eq.pass.cpp
index 327cc82b06b08..8b7e694b080f4 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.join.view/iterator/eq.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.join/range.join.iterator/eq.pass.cpp
@@ -7,10 +7,9 @@
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17
-// UNSUPPORTED: !c++experimental
// friend constexpr bool operator==(const iterator& x, const iterator& y);
-// requires ref-is-glvalue && equality_comparable<iterator_t<Base>> &&
+// requires ref-is-glvalue && forward_range<Base> &&
// equality_comparable<iterator_t<range_reference_t<Base>>>;
#include <cassert>
@@ -43,7 +42,7 @@ constexpr bool test() {
}
{
- // !equality_comparable<iterator_t<Base>>
+ // !forward_range<iterator_t<Base>>
using Inner = BufferView<int*>;
using Outer = BufferView<cpp20_input_iterator<Inner*>, sentinel_wrapper<cpp20_input_iterator<Inner*>>>;
static_assert(!std::equality_comparable<std::ranges::iterator_t<Outer>>);
@@ -51,8 +50,6 @@ constexpr bool test() {
std::ranges::join_view jv(Outer{inners});
auto iter = jv.begin();
static_assert(!std::equality_comparable<decltype(iter)>);
- auto const_iter = std::as_const(jv).begin();
- static_assert(!std::equality_comparable<decltype(const_iter)>);
}
{
diff --git a/libcxx/test/std/ranges/range.adaptors/range.join.view/iterator/increment.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.join/range.join.iterator/increment.pass.cpp
similarity index 94%
rename from libcxx/test/std/ranges/range.adaptors/range.join.view/iterator/increment.pass.cpp
rename to libcxx/test/std/ranges/range.adaptors/range.join/range.join.iterator/increment.pass.cpp
index 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<decltype(iter++)>);
}
+ {
+ // Check stashing iterators (LWG3698: regex_iterator and join_view don't work together very well)
+ std::ranges::join_view<StashingRange> jv;
+ auto it = jv.begin();
+ assert(*it == 'a');
+ ++it;
+ assert(*it == 'a');
+ ++it;
+ assert(*it == 'b');
+ it++;
+ assert(*it == 'a');
+ it++;
+ assert(*it == 'b');
+ ++it;
+ assert(*it == 'c');
+ }
+
return true;
}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.join.view/iterator/iter.move.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.join/range.join.iterator/iter.move.pass.cpp
similarity index 98%
rename from libcxx/test/std/ranges/range.adaptors/range.join.view/iterator/iter.move.pass.cpp
rename to libcxx/test/std/ranges/range.adaptors/range.join/range.join.iterator/iter.move.pass.cpp
index 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::<iterator>.
diff --git a/libcxx/test/std/ranges/range.adaptors/range.join.view/iterator/star.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.join/range.join.iterator/star.pass.cpp
similarity index 97%
rename from libcxx/test/std/ranges/range.adaptors/range.join.view/iterator/star.pass.cpp
rename to libcxx/test/std/ranges/range.adaptors/range.join/range.join.iterator/star.pass.cpp
index 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 c2d7058746d75..4bd8025efb5c1 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.join.view/sentinel/ctor.other.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.join/range.join.sentinel/ctor.other.pass.cpp
@@ -7,7 +7,6 @@
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17
-// UNSUPPORTED: !c++experimental
// constexpr sentinel(sentinel<!Const> s);
// requires Const && convertible_to<sentinel_t<V>, sentinel_t<Base>>;
diff --git a/libcxx/test/std/ranges/range.adaptors/range.join.view/sentinel/ctor.parent.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.join/range.join.sentinel/ctor.parent.pass.cpp
similarity index 97%
rename from libcxx/test/std/ranges/range.adaptors/range.join.view/sentinel/ctor.parent.pass.cpp
rename to libcxx/test/std/ranges/range.adaptors/range.join/range.join.sentinel/ctor.parent.pass.cpp
index 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<bool OtherConst>
// requires sentinel_for<sentinel_t<Base>, iterator_t<maybe-const<OtherConst, V>>>
@@ -17,6 +16,7 @@
#include <concepts>
#include <functional>
#include <ranges>
+#include <type_traits>
#include "../types.h"
@@ -61,18 +61,27 @@ static_assert(EqualityComparable<std::ranges::iterator_t<const ConstComparableVi
constexpr bool test() {
int buffer[4][4] = {{1111, 2222, 3333, 4444}, {555, 666, 777, 888}, {99, 1010, 1111, 1212}, {13, 14, 15, 16}};
+ // test iterator<false> == sentinel<false>
{
ChildView children[4] = {ChildView(buffer[0]), ChildView(buffer[1]), ChildView(buffer[2]), ChildView(buffer[3])};
- auto jv = std::ranges::join_view(ParentView(children));
+ auto jv = std::ranges::join_view(ParentView(children));
assert(jv.end() == std::ranges::next(jv.begin(), 16));
- static_assert(!EqualityComparable<decltype(std::as_const(jv).begin()), decltype(jv.end())>);
- static_assert(!EqualityComparable<decltype(jv.begin()), decltype(std::as_const(jv).end())>);
}
+ // test iterator<false> == sentinel<true>
+ {
+ ChildView children[4] = {ChildView(buffer[0]), ChildView(buffer[1]), ChildView(buffer[2]), ChildView(buffer[3])};
+ using ParentT = std::remove_all_extents_t<decltype(children)>;
+ auto jv = std::ranges::join_view(ForwardParentView<ParentT>(children));
+ assert(std::as_const(jv).end() == std::ranges::next(jv.begin(), 16));
+ }
+
+ // test iterator<true> == sentinel<true>
{
CopyableChild children[4] = {CopyableChild(buffer[0]), CopyableChild(buffer[1]), CopyableChild(buffer[2]),
CopyableChild(buffer[3])};
- const auto jv = std::ranges::join_view(ParentView(children));
+ using ParentT = std::remove_all_extents_t<decltype(children)>;
+ const auto jv = std::ranges::join_view(ForwardParentView<ParentT>(children));
assert(jv.end() == std::ranges::next(jv.begin(), 16));
}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.join.view/types.h b/libcxx/test/std/ranges/range.adaptors/range.join/types.h
similarity index 88%
rename from libcxx/test/std/ranges/range.adaptors/range.join.view/types.h
rename to libcxx/test/std/ranges/range.adaptors/range.join/types.h
index 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 <concepts>
#include <cstdint>
+#include <string>
#include <tuple>
#include "test_macros.h"
@@ -52,13 +53,13 @@ inline ChildView globalChildren[4] = {
ChildView(globalBuffer[3]),
};
-template <class T>
+template <class T, template<class...> class Iter = cpp17_input_iterator>
struct ParentView : std::ranges::view_base {
T* ptr_;
unsigned size_;
- using iterator = cpp20_input_iterator<T*>;
- using const_iterator = cpp20_input_iterator<const T*>;
+ using iterator = Iter<T*>;
+ using const_iterator = Iter<const T*>;
using sentinel = sentinel_wrapper<iterator>;
using const_sentinel = sentinel_wrapper<const_iterator>;
@@ -80,6 +81,9 @@ struct ParentView : std::ranges::view_base {
template <class T>
ParentView(T*) -> ParentView<T>;
+template<class T>
+using ForwardParentView = ParentView<T, forward_iterator>;
+
struct CopyableChild : std::ranges::view_base {
int* ptr_;
unsigned size_;
@@ -97,15 +101,16 @@ struct CopyableChild : std::ranges::view_base {
constexpr const_sentinel end() const { return const_sentinel(const_iterator(ptr_ + size_)); }
};
-struct CopyableParent : std::ranges::view_base {
+template<template<class...> class Iter>
+struct CopyableParentTemplate : std::ranges::view_base {
CopyableChild* ptr_;
- using iterator = cpp17_input_iterator<CopyableChild*>;
- using const_iterator = cpp17_input_iterator<const CopyableChild*>;
+ using iterator = Iter<CopyableChild*>;
+ using const_iterator = Iter<const CopyableChild*>;
using sentinel = sentinel_wrapper<iterator>;
using const_sentinel = sentinel_wrapper<const_iterator>;
- constexpr CopyableParent(CopyableChild* ptr) : ptr_(ptr) {}
+ constexpr CopyableParentTemplate(CopyableChild* ptr) : ptr_(ptr) {}
constexpr iterator begin() { return iterator(ptr_); }
constexpr const_iterator begin() const { return const_iterator(ptr_); }
@@ -113,6 +118,9 @@ struct CopyableParent : std::ranges::view_base {
constexpr const_sentinel end() const { return const_sentinel(const_iterator(ptr_ + 4)); }
};
+using CopyableParent = CopyableParentTemplate<cpp17_input_iterator>;
+using ForwardCopyableParent = CopyableParentTemplate<forward_iterator>;
+
struct Box {
int x;
};
@@ -392,4 +400,48 @@ struct IterMoveSwapAwareView : BufferView<int*> {
};
static_assert(std::ranges::input_range<IterMoveSwapAwareView>);
+class StashingIterator {
+public:
+ using difference_type = std::ptrdiff_t;
+ using value_type = std::string;
+
+ constexpr StashingIterator() : letter_('a') {}
+
+ constexpr StashingIterator& operator++() {
+ str_ += letter_;
+ ++letter_;
+ return *this;
+ }
+
+ constexpr void operator++(int) { ++*this; }
+
+ constexpr value_type operator*() const { return str_; }
+
+ constexpr bool operator==(std::default_sentinel_t) const { return letter_ > 'z'; }
+
+private:
+ char letter_;
+ value_type str_;
+};
+
+using StashingRange = std::ranges::subrange<StashingIterator, std::default_sentinel_t>;
+static_assert(std::ranges::input_range<StashingRange>);
+static_assert(!std::ranges::forward_range<StashingRange>);
+
+class ConstNonJoinableRange : public std::ranges::view_base {
+public:
+ constexpr StashingIterator begin() { return {}; }
+ constexpr std::default_sentinel_t end() { return {}; }
+
+ constexpr const int* begin() const { return &val_; }
+ constexpr const int* end() const { return &val_ + 1; }
+
+private:
+ int val_ = 1;
+};
+static_assert(std::ranges::input_range<ConstNonJoinableRange>);
+static_assert(std::ranges::input_range<const ConstNonJoinableRange>);
+static_assert(std::ranges::input_range<std::ranges::range_reference_t<ConstNonJoinableRange>>);
+static_assert(!std::ranges::input_range<std::ranges::range_reference_t<const ConstNonJoinableRange>>);
+
#endif // TEST_STD_RANGES_RANGE_ADAPTORS_RANGE_JOIN_TYPES_H
diff --git a/libcxx/test/std/re/re.iter/re.regiter/iterator_concept_conformance.compile.pass.cpp b/libcxx/test/std/re/re.iter/re.regiter/iterator_concept_conformance.compile.pass.cpp
index 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 <iterator>
-static_assert(std::forward_iterator<std::cregex_iterator>);
-static_assert(!std::bidirectional_iterator<std::cregex_iterator>);
+static_assert(std::input_iterator<std::cregex_iterator>);
+static_assert(!std::forward_iterator<std::cregex_iterator>);
static_assert(!std::indirectly_writable<std::cregex_iterator, char>);
static_assert(std::sentinel_for<std::cregex_iterator, std::cregex_iterator>);
static_assert(!std::sized_sentinel_for<std::cregex_iterator, std::cregex_iterator>);
diff --git a/libcxx/test/std/re/re.iter/re.regiter/types.pass.cpp b/libcxx/test/std/re/re.iter/re.regiter/types.pass.cpp
index 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 <regex>
#include <type_traits>
@@ -36,6 +37,9 @@ test()
static_assert((std::is_same<typename I::pointer, const std::match_results<const CharT*>*>::value), "");
static_assert((std::is_same<typename I::reference, const std::match_results<const CharT*>&>::value), "");
static_assert((std::is_same<typename I::iterator_category, std::forward_iterator_tag>::value), "");
+#if TEST_STD_VER >= 20
+ static_assert(std::is_same_v<typename I::iterator_concept, std::input_iterator_tag>);
+#endif
}
int main(int, char**)
diff --git a/libcxx/test/std/re/re.iter/re.tokiter/iterator_concept_conformance.compile.pass.cpp b/libcxx/test/std/re/re.iter/re.tokiter/iterator_concept_conformance.compile.pass.cpp
index 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 <iterator>
-static_assert(std::forward_iterator<std::cregex_token_iterator>);
-static_assert(!std::bidirectional_iterator<std::cregex_token_iterator>);
+static_assert(std::input_iterator<std::cregex_token_iterator>);
+static_assert(!std::forward_iterator<std::cregex_token_iterator>);
static_assert(!std::indirectly_writable<std::cregex_token_iterator, char>);
static_assert(std::sentinel_for<std::cregex_token_iterator, std::cregex_token_iterator>);
static_assert(!std::sized_sentinel_for<std::cregex_token_iterator, std::cregex_token_iterator>);
diff --git a/libcxx/test/std/re/re.iter/re.tokiter/types.pass.cpp b/libcxx/test/std/re/re.iter/re.tokiter/types.pass.cpp
index 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 <regex>
#include <type_traits>
@@ -36,6 +37,9 @@ test()
static_assert((std::is_same<typename I::pointer, const std::sub_match<const CharT*>*>::value), "");
static_assert((std::is_same<typename I::reference, const std::sub_match<const CharT*>&>::value), "");
static_assert((std::is_same<typename I::iterator_category, std::forward_iterator_tag>::value), "");
+#if TEST_STD_VER >= 20
+ static_assert(std::is_same_v<typename I::iterator_concept, std::input_iterator_tag>);
+#endif
}
int main(int, char**)
diff --git a/libcxx/utils/data/ignore_format.txt b/libcxx/utils/data/ignore_format.txt
index 123d06d56e29a..c10745ce3edad 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 <mazkuba3 at gmail.com>
Date: Mon, 27 Nov 2023 15:40:34 +0100
Subject: [PATCH 02/17] 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 812a6f9379a85..fd68358837e0f 100644
--- a/libcxx/include/__ranges/join_view.h
+++ b/libcxx/include/__ranges/join_view.h
@@ -323,7 +323,7 @@ namespace ranges {
else
return *__parent_->__inner_;
};
- if (++*__inner_ == ranges::end(ranges::__as_lvalue(__get_inner_range()))) {
+ if (++*__inner_ == ranges::end(std::__as_lvalue(__get_inner_range()))) {
++__get_outer();
__satisfy();
}
@@ -354,11 +354,11 @@ namespace ranges {
common_range<range_reference_t<_Base>>
{
if (__outer_ == ranges::end(__parent_->__base_))
- __inner_ = ranges::end(ranges::__as_lvalue(*--__outer_));
+ __inner_ = ranges::end(std::__as_lvalue(*--__outer_));
// Skip empty inner ranges when going backwards.
- while (*__inner_ == ranges::begin(ranges::__as_lvalue(*__outer_))) {
- __inner_ = ranges::end(ranges::__as_lvalue(*--__outer_));
+ while (*__inner_ == ranges::begin(std::__as_lvalue(*__outer_))) {
+ __inner_ = ranges::end(std::__as_lvalue(*--__outer_));
}
--*__inner_;
diff --git a/libcxx/include/__utility/as_lvalue.h b/libcxx/include/__utility/as_lvalue.h
index b4df650edbf65..159f45dad4d41 100644
--- a/libcxx/include/__utility/as_lvalue.h
+++ b/libcxx/include/__utility/as_lvalue.h
@@ -21,16 +21,14 @@ _LIBCPP_PUSH_MACROS
_LIBCPP_BEGIN_NAMESPACE_STD
-#if _LIBCPP_STD_VER >= 20
+#ifndef _LIBCPP_CXX03_LANG
-namespace ranges {
template <class _Tp>
_LIBCPP_HIDE_FROM_ABI constexpr _Tp& __as_lvalue(_LIBCPP_LIFETIMEBOUND _Tp&& __t) {
return static_cast<_Tp&>(__t);
}
-} // namespace ranges
-#endif // _LIBCPP_STD_VER >= 20
+#endif // !_LIBCPP_CXX03_LANG
_LIBCPP_END_NAMESPACE_STD
diff --git a/libcxx/test/libcxx/ranges/range.adaptors/range.adaptor.helpers/as-lvalue.verify.cpp b/libcxx/test/libcxx/ranges/range.adaptors/range.adaptor.helpers/as-lvalue.verify.cpp
index 878ef91b13839..8efd7e5ccf983 100644
--- a/libcxx/test/libcxx/ranges/range.adaptors/range.adaptor.helpers/as-lvalue.verify.cpp
+++ b/libcxx/test/libcxx/ranges/range.adaptors/range.adaptor.helpers/as-lvalue.verify.cpp
@@ -6,15 +6,11 @@
//
//===----------------------------------------------------------------------===//
-// UNSUPPORTED: c++03, c++11, c++14, c++17
-
-// <ranges>
+// UNSUPPORTED: c++03
// template<class T>
// constexpr T& as-lvalue(T&& t) { // exposition only
-#include <ranges>
-
#include <concepts>
#include <utility>
@@ -22,19 +18,19 @@ constexpr bool test() {
// Check glvalue
{
int lvalue{};
- [[maybe_unused]] std::same_as<int&> decltype(auto) check = std::ranges::__as_lvalue(lvalue);
+ [[maybe_unused]] std::same_as<int&> decltype(auto) check = std::__as_lvalue(lvalue);
}
// Check prvalue
{
- [[maybe_unused]] std::same_as<int&> decltype(auto) check = std::ranges::__as_lvalue(
+ [[maybe_unused]] std::same_as<int&> decltype(auto) check = std::__as_lvalue(
0); // expected-warning {{temporary bound to local reference 'check' will be destroyed at the end of the full-expression}}
}
// Check xvalue
{
int xvalue{};
- [[maybe_unused]] std::same_as<int&> decltype(auto) check = std::ranges::__as_lvalue(std::move(xvalue));
+ [[maybe_unused]] std::same_as<int&> decltype(auto) check = std::__as_lvalue(std::move(xvalue));
}
return true;
>From be16b577a981cc96f2eaa00024ecb341c6219085 Mon Sep 17 00:00:00 2001
From: Jakub Mazurkiewicz <mazkuba3 at gmail.com>
Date: Mon, 27 Nov 2023 16:12:40 +0100
Subject: [PATCH 03/17] 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 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<class T>
+// constexpr T& as-lvalue(T&& t) { // exposition only
+
+#include <utility>
+
+void test() {
+ // Check prvalue
+ {
+ [[maybe_unused]] auto& check = std::__as_lvalue(
+ 0); // expected-warning {{temporary bound to local reference 'check' will be destroyed at the end of the full-expression}}
+ }
+}
diff --git a/libcxx/test/libcxx/ranges/range.adaptors/range.adaptor.helpers/as-lvalue.verify.cpp b/libcxx/test/libcxx/ranges/range.adaptors/range.adaptor.helpers/as-lvalue.pass.cpp
similarity index 79%
rename from libcxx/test/libcxx/ranges/range.adaptors/range.adaptor.helpers/as-lvalue.verify.cpp
rename to libcxx/test/libcxx/ranges/range.adaptors/range.adaptor.helpers/as-lvalue.pass.cpp
index 8efd7e5ccf983..14a3db6367ddc 100644
--- a/libcxx/test/libcxx/ranges/range.adaptors/range.adaptor.helpers/as-lvalue.verify.cpp
+++ b/libcxx/test/libcxx/ranges/range.adaptors/range.adaptor.helpers/as-lvalue.pass.cpp
@@ -21,12 +21,6 @@ constexpr bool test() {
[[maybe_unused]] std::same_as<int&> decltype(auto) check = std::__as_lvalue(lvalue);
}
- // Check prvalue
- {
- [[maybe_unused]] std::same_as<int&> decltype(auto) check = std::__as_lvalue(
- 0); // expected-warning {{temporary bound to local reference 'check' will be destroyed at the end of the full-expression}}
- }
-
// Check xvalue
{
int xvalue{};
>From 181cd853f50801d7ea5ecf232ae3413ac10f4c83 Mon Sep 17 00:00:00 2001
From: Jakub Mazurkiewicz <mazkuba3 at gmail.com>
Date: Mon, 27 Nov 2023 16:20:24 +0100
Subject: [PATCH 04/17] 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 fd68358837e0f..909ca9a06d3ad 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 <mazkuba3 at gmail.com>
Date: Mon, 27 Nov 2023 17:22:35 +0100
Subject: [PATCH 05/17] Restore old `__sentinel<C>` friendship in
`join_view::_sentinel`
Comment: https://github.com/llvm/llvm-project/pull/66033#discussion_r1396587214
---
libcxx/include/__ranges/join_view.h | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/libcxx/include/__ranges/join_view.h b/libcxx/include/__ranges/join_view.h
index 909ca9a06d3ad..e1d54c4e4bbc5 100644
--- a/libcxx/include/__ranges/join_view.h
+++ b/libcxx/include/__ranges/join_view.h
@@ -164,10 +164,11 @@ namespace ranges {
template<bool _Const>
struct join_view<_View>::__sentinel {
private:
- friend join_view;
+ template <bool>
+ friend struct __sentinel;
- using _Parent = __maybe_const<_Const, join_view>;
- using _Base = __maybe_const<_Const, _View>;
+ using _Parent = __maybe_const<_Const, join_view>;
+ using _Base = __maybe_const<_Const, _View>;
sentinel_t<_Base> __end_ = sentinel_t<_Base>();
public:
>From 03454c21dade534913e91ef137d2a16f2031a618 Mon Sep 17 00:00:00 2001
From: Jakub Mazurkiewicz <mazkuba3 at gmail.com>
Date: Mon, 27 Nov 2023 18:16:30 +0100
Subject: [PATCH 06/17] 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 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 <algorithm>
#include <array>
diff --git a/libcxx/test/std/algorithms/alg.modifying.operations/alg.copy/ranges.copy_n.segmented.pass.cpp b/libcxx/test/std/algorithms/alg.modifying.operations/alg.copy/ranges.copy_n.segmented.pass.cpp
index 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 <algorithm>
#include <array>
diff --git a/libcxx/test/std/algorithms/alg.modifying.operations/alg.move/ranges.move.segmented.pass.cpp b/libcxx/test/std/algorithms/alg.modifying.operations/alg.move/ranges.move.segmented.pass.cpp
index 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 <algorithm>
#include <array>
diff --git a/libcxx/test/std/algorithms/alg.modifying.operations/alg.move/ranges.move_backward.segmented.pass.cpp b/libcxx/test/std/algorithms/alg.modifying.operations/alg.move/ranges.move_backward.segmented.pass.cpp
index 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 <algorithm>
#include <array>
diff --git a/libcxx/test/std/library/description/conventions/customization.point.object/cpo.compile.pass.cpp b/libcxx/test/std/library/description/conventions/customization.point.object/cpo.compile.pass.cpp
index 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
>From 7de9a775a69fdf5496e3d73be9592ae768e9ce40 Mon Sep 17 00:00:00 2001
From: Jakub Mazurkiewicz <mazkuba3 at gmail.com>
Date: Mon, 27 Nov 2023 21:21:06 +0100
Subject: [PATCH 07/17] 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 e1d54c4e4bbc5..e75e61270721c 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 <mazkuba3 at gmail.com>
Date: Mon, 27 Nov 2023 21:45:52 +0100
Subject: [PATCH 08/17] 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 0000000000000..c1e81aef5f8e5
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.join/lwg3698.pass.cpp
@@ -0,0 +1,31 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+// UNSUPPORTED: no-localization
+
+// Check LWG-3698: `regex_iterator` and `join_view` don't work together very well
+
+#include <algorithm>
+#include <array>
+#include <cassert>
+#include <ranges>
+#include <regex>
+#include <string_view>
+
+int main(int, char**) {
+ char const text[] = "Hello";
+ std::regex regex{"[a-z]"};
+
+ auto lower =
+ std::ranges::subrange(
+ std::cregex_iterator(std::ranges::begin(text), std::ranges::end(text), regex), std::cregex_iterator{}) |
+ std::views::join | std::views::transform([](auto const& sm) { return std::string_view(sm.first, sm.second); });
+
+ assert(std::ranges::equal(lower, std::to_array<std::string_view>({"e", "l", "l", "o"})));
+}
>From 1f00358e80414f42ff2b42249c7ed9fe5399e881 Mon Sep 17 00:00:00 2001
From: Jakub Mazurkiewicz <mazkuba3 at gmail.com>
Date: Mon, 27 Nov 2023 21:58:02 +0100
Subject: [PATCH 09/17] 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 e75e61270721c..9b7399c24e3a5 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 <mazkuba3 at gmail.com>
Date: Mon, 27 Nov 2023 22:11:36 +0100
Subject: [PATCH 10/17] 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 9b7399c24e3a5..f80beda33b11e 100644
--- a/libcxx/include/__ranges/join_view.h
+++ b/libcxx/include/__ranges/join_view.h
@@ -214,6 +214,8 @@ namespace ranges {
using _Inner = iterator_t<range_reference_t<_Base>>;
using _InnerRange = range_reference_t<_View>;
+ static_assert(!_Const || forward_range<_Base>, "Const can only be true when Base models forward_range.");
+
static constexpr bool __ref_is_glvalue = is_reference_v<range_reference_t<_Base>>;
static constexpr bool _OuterPresent = forward_range<_Base>;
>From 3861ffa29062879070bc6acea0dde8fff036aba2 Mon Sep 17 00:00:00 2001
From: Jakub Mazurkiewicz <mazkuba3 at gmail.com>
Date: Mon, 27 Nov 2023 22:36:12 +0100
Subject: [PATCH 11/17] Fix comment: `!forward_range<iterator_t<Base>>` ->
`!forward_range<Base>`
Comment: https://github.com/llvm/llvm-project/pull/66033#discussion_r1396594058
---
.../range.adaptors/range.join/range.join.iterator/eq.pass.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/libcxx/test/std/ranges/range.adaptors/range.join/range.join.iterator/eq.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.join/range.join.iterator/eq.pass.cpp
index 8b7e694b080f4..5c831f33e67c7 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.join/range.join.iterator/eq.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.join/range.join.iterator/eq.pass.cpp
@@ -42,7 +42,7 @@ constexpr bool test() {
}
{
- // !forward_range<iterator_t<Base>>
+ // !forward_range<Base>
using Inner = BufferView<int*>;
using Outer = BufferView<cpp20_input_iterator<Inner*>, sentinel_wrapper<cpp20_input_iterator<Inner*>>>;
static_assert(!std::equality_comparable<std::ranges::iterator_t<Outer>>);
>From 0e927818e45d361e3fdc76df9f5938ea291f7bf1 Mon Sep 17 00:00:00 2001
From: Jakub Mazurkiewicz <mazkuba3 at gmail.com>
Date: Tue, 28 Nov 2023 00:53:35 +0100
Subject: [PATCH 12/17] 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 14a3db6367ddc..d5cd81f397749 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<class T>
// constexpr T& as-lvalue(T&& t) { // exposition only
-#include <concepts>
+#include <cassert>
+#include <type_traits>
#include <utility>
-constexpr bool test() {
- // Check glvalue
- {
- int lvalue{};
- [[maybe_unused]] std::same_as<int&> decltype(auto) check = std::__as_lvalue(lvalue);
- }
+constexpr bool test(int value = 0) {
+ static_assert(std::is_same<decltype(std::__as_lvalue(value)), int&>::value, "");
+ static_assert(std::is_same<decltype(std::__as_lvalue(std::move(value))), int&>::value, "");
- // Check xvalue
- {
- int xvalue{};
- [[maybe_unused]] std::same_as<int&> 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 <mazkuba3 at gmail.com>
Date: Wed, 29 Nov 2023 17:47:07 +0100
Subject: [PATCH 13/17] 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 c1e81aef5f8e5..0abe37bf17f7e 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<std::string_view>({"e", "l", "l", "o"})));
+
+ return 0;
}
>From 62fa3a7d86b63459dde492711040c11a5f6bc4c5 Mon Sep 17 00:00:00 2001
From: Jakub Mazurkiewicz <mazkuba3 at gmail.com>
Date: Wed, 29 Nov 2023 17:48:07 +0100
Subject: [PATCH 14/17] 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 d5cd81f397749..14a3db6367ddc 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<class T>
// constexpr T& as-lvalue(T&& t) { // exposition only
-#include <cassert>
-#include <type_traits>
+#include <concepts>
#include <utility>
-constexpr bool test(int value = 0) {
- static_assert(std::is_same<decltype(std::__as_lvalue(value)), int&>::value, "");
- static_assert(std::is_same<decltype(std::__as_lvalue(std::move(value))), int&>::value, "");
+constexpr bool test() {
+ // Check glvalue
+ {
+ int lvalue{};
+ [[maybe_unused]] std::same_as<int&> 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<int&> 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 <mazkuba3 at gmail.com>
Date: Wed, 29 Nov 2023 17:48:40 +0100
Subject: [PATCH 15/17] 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 14a3db6367ddc..721279fcd586b 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<class T>
// constexpr T& as-lvalue(T&& t) { // exposition only
-#include <concepts>
+#include <type_traits>
#include <utility>
constexpr bool test() {
// Check glvalue
{
int lvalue{};
- [[maybe_unused]] std::same_as<int&> decltype(auto) check = std::__as_lvalue(lvalue);
+ [[maybe_unused]] decltype(auto) check = std::__as_lvalue(lvalue);
+ static_assert(std::is_same<decltype(check), int&>::value, "");
}
// Check xvalue
{
int xvalue{};
- [[maybe_unused]] std::same_as<int&> 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<decltype(check), int&>::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 <mazkuba3 at gmail.com>
Date: Tue, 5 Dec 2023 12:15:42 +0100
Subject: [PATCH 16/17] 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 0000000000000..9bf55f0a3423a
--- /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<Base>; // exposition only
+
+#include <cassert>
+#include <ranges>
+#include <string>
+#include <utility>
+
+#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<false>`
+ 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<true>`
+ 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<int*>;
+ static_assert(!std::default_initializable<NonDefaultCtrIter>);
+ using NonDefaultCtrIterView = BufferView<NonDefaultCtrIter, sentinel_wrapper<NonDefaultCtrIter>>;
+ static_assert(std::ranges::input_range<NonDefaultCtrIterView>);
+
+ 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 0000000000000..a5b88ed01773c
--- /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 <cassert>
+#include <cstddef>
+#include <ranges>
+
+#include "test_iterators.h"
+
+template <std::forward_iterator Iter>
+struct DieOnCopyIterator {
+ using value_type = std::iter_value_t<Iter>;
+ using difference_type = std::iter_difference_t<Iter>;
+
+ 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<Iter>
+ {
+ 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<Iter>
+ {
+ return left.iter_ == right.iter_;
+ }
+
+ friend constexpr bool operator==(const DieOnCopyIterator& it, const sentinel_wrapper<Iter>& se) {
+ return it.iter_ == se;
+ }
+
+private:
+ Iter iter_ = Iter();
+};
+
+template <class Iter>
+explicit DieOnCopyIterator(Iter) -> DieOnCopyIterator<Iter>;
+
+static_assert(std::forward_iterator<DieOnCopyIterator<int*>>);
+static_assert(!std::bidirectional_iterator<DieOnCopyIterator<int*>>);
+static_assert(std::sentinel_for<sentinel_wrapper<int*>, DieOnCopyIterator<int*>>);
+
+template <std::input_iterator Iter, std::sentinel_for<Iter> 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 <class Iter, class Sent>
+MoveOnAccessSubrange(Iter, Sent) -> MoveOnAccessSubrange<Iter, Sent>;
+
+static_assert(std::ranges::input_range<MoveOnAccessSubrange<int*, sentinel_wrapper<int*>>>);
+static_assert(std::ranges::forward_range<MoveOnAccessSubrange<DieOnCopyIterator<int*>>>);
+
+template <class Iter, class Sent>
+ requires(!std::same_as<Iter, Sent>)
+struct BufferView : std::ranges::view_base {
+ using T = std::iter_value_t<Iter>;
+ T* data_;
+ std::size_t size_;
+
+ template <std::size_t N>
+ 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<BufferView<int*, sentinel_wrapper<int*>>>);
+
+#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 <mazkuba3 at gmail.com>
Date: Tue, 5 Dec 2023 12:34:46 +0100
Subject: [PATCH 17/17] 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 0000000000000..bb8debb642b99
--- /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<Base>); // exposition only
+
+#include <string>
+#include <ranges>
+
+#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 a5b88ed01773c..0652d4bdb4717 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 <std::forward_iterator Iter>
+template <std::input_iterator Iter>
struct DieOnCopyIterator {
using value_type = std::iter_value_t<Iter>;
using difference_type = std::iter_difference_t<Iter>;
- DieOnCopyIterator() = default;
+ DieOnCopyIterator()
+ requires std::default_initializable<Iter>
+ = 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 <class Iter>
explicit DieOnCopyIterator(Iter) -> DieOnCopyIterator<Iter>;
+static_assert(std::input_iterator<DieOnCopyIterator<cpp20_input_iterator<int*>>>);
+static_assert(!std::forward_iterator<DieOnCopyIterator<cpp20_input_iterator<int*>>>);
static_assert(std::forward_iterator<DieOnCopyIterator<int*>>);
static_assert(!std::bidirectional_iterator<DieOnCopyIterator<int*>>);
static_assert(std::sentinel_for<sentinel_wrapper<int*>, DieOnCopyIterator<int*>>);
More information about the libcxx-commits
mailing list