diff --git a/stl/inc/ranges b/stl/inc/ranges index f99d906a71..edcb62f86b 100644 --- a/stl/inc/ranges +++ b/stl/inc/ranges @@ -3567,37 +3567,36 @@ namespace ranges { #ifdef __clang__ template // TRANSITION, LLVM-47414 - concept _Can_const_join = input_range && is_reference_v>; + concept _Can_const_join = forward_range && is_reference_v> + && input_range>; #endif // ^^^ workaround ^^^ + template + _NODISCARD constexpr _Ty& _As_lvalue(_Ty&& _Val) noexcept { + return static_cast<_Ty&>(_Val); + } + template requires is_reference_v> class _Join_view_base<_Vw> : public view_interface> {}; + template + class _Join_view_outer_iter_base : public _Join_view_base<_Vw> { + protected: + _Non_propagating_cache> _Outer; + }; + + template + class _Join_view_outer_iter_base<_Vw> : public _Join_view_base<_Vw> {}; + _EXPORT_STD template requires view<_Vw> && input_range> - class join_view : public _Join_view_base<_Vw> { - -#ifndef _USE_JOIN_VIEW_INPUT_RANGE - static_assert(forward_range<_Vw>, - "Due to a design flaw, join_view can misbehave " - "with some input-only ranges (see https://wg21.link/lwg3698). " - "We believe that WG21 will be unable to fix this problem without breaking ABI. " - "To minimize breakage when a fix is implemented, " - "we are temporarily disabling potentially problematic cases. " - "You can define _USE_JOIN_VIEW_INPUT_RANGE to suppress this error, " - "but be aware that you will almost certainly need to recompile " - "when we release a fix."); -#endif // _USE_JOIN_VIEW_INPUT_RANGE - + class join_view : public _Join_view_outer_iter_base<_Vw> { private: template using _InnerRng = range_reference_t<_Maybe_const<_Const, _Vw>>; /* [[no_unique_address]] */ _Vw _Range{}; - template - class _Sentinel; - template struct _Category_base {}; @@ -3614,14 +3613,28 @@ namespace ranges { }; template - class _Iterator + class _Iterator_base + : public _Category_base<_Maybe_const<_Const, _Vw>, _InnerRng<_Const>, is_reference_v<_InnerRng<_Const>>> {}; + + template + requires forward_range<_Maybe_const<_Const, _Vw>> + class _Iterator_base<_Const> : public _Category_base<_Maybe_const<_Const, _Vw>, _InnerRng<_Const>, is_reference_v<_InnerRng<_Const>>> { + protected: + using _OuterIter = iterator_t<_Maybe_const<_Const, _Vw>>; + + _Iterator_base() = default; + constexpr explicit _Iterator_base(_OuterIter&& _Outer_) : _Outer(_STD move(_Outer_)) {} + + /* [[no_unique_address]] */ _OuterIter _Outer{}; + }; + + template + class _Iterator : public _Iterator_base<_Const> { private: - template - friend class _Iterator; - template - friend class _Sentinel; + friend join_view; + using _Mybase = _Iterator_base<_Const>; using _Parent_t = _Maybe_const<_Const, join_view>; using _Base = _Maybe_const<_Const, _Vw>; using _OuterIter = iterator_t<_Base>; @@ -3630,21 +3643,53 @@ namespace ranges { // True if and only if the expression *i, where i is an iterator from the outer range, is a glvalue: static constexpr bool _Deref_is_glvalue = is_reference_v<_InnerRng<_Const>>; - /* [[no_unique_address]] */ _OuterIter _Outer{}; /* [[no_unique_address]] */ _Defaultabox<_InnerIter> _Inner{}; // Non-standard extension: when _Inner_iter // is default-constructible, we don't wrap in // an optional-like. _Parent_t* _Parent{}; + constexpr _Iterator(_Parent_t& _Parent_, _OuterIter _Outer_) + requires forward_range<_Base> + : _Mybase{_STD move(_Outer_)}, _Parent{_STD addressof(_Parent_)} { +#if _ITERATOR_DEBUG_LEVEL != 0 + _Adl_verify_range(this->_Outer, _RANGES end(_Parent_._Range)); + _Adl_verify_range(_RANGES begin(_Parent_._Range), this->_Outer); +#endif // _ITERATOR_DEBUG_LEVEL != 0 + _Satisfy(); + } + + constexpr explicit _Iterator(_Parent_t& _Parent) + requires (!forward_range<_Base>) + : _Parent{_STD addressof(_Parent)} { + _Satisfy(); + } + + _NODISCARD constexpr _OuterIter& _Get_outer() noexcept { + if constexpr (forward_range<_Base>) { + return this->_Outer; + } else { + return *_Parent->_Outer; + } + } + + _NODISCARD constexpr const _OuterIter& _Get_outer() const noexcept { + if constexpr (forward_range<_Base>) { + return this->_Outer; + } else { + return *_Parent->_Outer; + } + } + constexpr auto&& _Update_inner() { if constexpr (_Deref_is_glvalue) { - return *_Outer; + return *_Get_outer(); } else { - return _Parent->_Inner._Emplace(_Not_quite_object::_Construct_tag{}, _Outer)._Val; + return _Parent->_Inner._Emplace(_Not_quite_object::_Construct_tag{}, _Get_outer())._Val; } } constexpr void _Satisfy() { + auto& _Outer = _Get_outer(); const auto _Last = _RANGES end(_Parent->_Range); for (; _Outer != _Last; ++_Outer) { auto&& _Tmp = _Update_inner(); @@ -3661,10 +3706,10 @@ namespace ranges { #if _ITERATOR_DEBUG_LEVEL != 0 constexpr void _Check_dereference() const noexcept { _STL_VERIFY(_Parent != nullptr, "cannot dereference value-initialized join_view iterator"); - _STL_VERIFY(_Outer != _RANGES end(_Parent->_Range), "cannot dereference join_view end iterator"); + _STL_VERIFY(_Get_outer() != _RANGES end(_Parent->_Range), "cannot dereference join_view end iterator"); sentinel_t<_InnerRng<_Const>> _Last; if constexpr (_Deref_is_glvalue) { - _Last = _RANGES end(*_Outer); + _Last = _RANGES end(_As_lvalue(*_Get_outer())); } else { _Last = _RANGES end((*_Parent->_Inner)._Val); } @@ -3691,21 +3736,10 @@ namespace ranges { _Iterator() requires default_initializable<_OuterIter> = default; // clang-format on - constexpr _Iterator(_Parent_t& _Parent_, _OuterIter _Outer_) - : _Outer{_STD move(_Outer_)}, _Parent{_STD addressof(_Parent_)} { -#if _ITERATOR_DEBUG_LEVEL != 0 - _Adl_verify_range(_Outer, _RANGES end(_Parent_._Range)); - if constexpr (forward_range<_Base>) { - _Adl_verify_range(_RANGES begin(_Parent_._Range), _Outer); - } -#endif // _ITERATOR_DEBUG_LEVEL != 0 - _Satisfy(); - } - constexpr _Iterator(_Iterator _It) requires _Const && convertible_to, _OuterIter> && convertible_to>, _InnerIter> - : _Outer(_STD move(_It._Outer)), _Inner(_STD move(_It._Inner)), _Parent(_It._Parent) {} + : _Mybase(_STD move(_It._Outer)), _Inner(_STD move(_It._Inner)), _Parent(_It._Parent) {} _NODISCARD constexpr decltype(auto) operator*() const noexcept(noexcept(**_Inner)) /* strengthened */ { #if _ITERATOR_DEBUG_LEVEL != 0 @@ -3725,8 +3759,9 @@ namespace ranges { } constexpr _Iterator& operator++() { + auto& _Outer = _Get_outer(); if constexpr (_Deref_is_glvalue) { - if (++*_Inner == _RANGES end(*_Outer)) { + if (++*_Inner == _RANGES end(_As_lvalue(*_Outer))) { ++_Outer; _Satisfy(); } @@ -3754,13 +3789,14 @@ namespace ranges { requires _Deref_is_glvalue && bidirectional_range<_Base> && bidirectional_range<_InnerRng<_Const>> && common_range<_InnerRng<_Const>> { // clang-format on + auto& _Outer = _Get_outer(); if (_Outer == _RANGES end(_Parent->_Range)) { --_Outer; - _Inner = _RANGES end(*_Outer); + _Inner = _RANGES end(_As_lvalue(*_Outer)); } - while (*_Inner == _RANGES begin(*_Outer)) { + while (*_Inner == _RANGES begin(_As_lvalue(*_Outer))) { --_Outer; - *_Inner = _RANGES end(*_Outer); + *_Inner = _RANGES end(_As_lvalue(*_Outer)); } --*_Inner; return *this; @@ -3780,7 +3816,7 @@ namespace ranges { _NODISCARD_FRIEND constexpr bool operator==(const _Iterator& _Left, const _Iterator& _Right) noexcept( noexcept(_Fake_copy_init(_Left._Outer == _Right._Outer && _Left._Inner == _Right._Inner))) /* strengthened */ - requires _Deref_is_glvalue && equality_comparable<_OuterIter> && equality_comparable<_InnerIter> { + requires _Deref_is_glvalue && forward_range<_Base> && equality_comparable<_InnerIter> { // clang-format on #if _ITERATOR_DEBUG_LEVEL != 0 _Left._Same_range(_Right); @@ -3812,10 +3848,7 @@ namespace ranges { template class _Sentinel { private: - template - friend class _Iterator; - template - friend class _Sentinel; + friend join_view; using _Parent_t = _Maybe_const<_Const, join_view>; using _Base = _Maybe_const<_Const, _Vw>; @@ -3829,9 +3862,9 @@ namespace ranges { template requires sentinel_for, _Maybe_const_iter<_OtherConst>> _NODISCARD constexpr bool _Equal(const _Iterator<_OtherConst>& _It) const noexcept( - noexcept(_Fake_copy_init(_It._Outer == _Last))) { + noexcept(_Fake_copy_init(_It._Get_outer() == _Last))) { // clang-format on - return _It._Outer == _Last; + return _It._Get_outer() == _Last; } public: @@ -3874,15 +3907,20 @@ namespace ranges { } _NODISCARD constexpr auto begin() { - constexpr bool _Use_const = _Simple_view<_Vw> && is_reference_v<_InnerRng>; - return _Iterator<_Use_const>{*this, _RANGES begin(_Range)}; + if constexpr (forward_range<_Vw>) { + constexpr bool _Use_const = _Simple_view<_Vw> && is_reference_v<_InnerRng>; + return _Iterator<_Use_const>{*this, _RANGES begin(_Range)}; + } else { + this->_Outer._Emplace(_RANGES begin(_Range)); + return _Iterator{*this}; + } } _NODISCARD constexpr _Iterator begin() const #ifdef __clang__ // TRANSITION, LLVM-47414 requires _Can_const_join<_Vw> #else // ^^^ workaround / no workaround vvv - requires input_range && is_reference_v<_InnerRng> + requires forward_range && is_reference_v<_InnerRng> && input_range<_InnerRng> #endif // TRANSITION, LLVM-47414 { return _Iterator{*this, _RANGES begin(_Range)}; @@ -3901,11 +3939,10 @@ namespace ranges { #ifdef __clang__ // TRANSITION, LLVM-47414 requires _Can_const_join<_Vw> #else // ^^^ workaround / no workaround vvv - requires input_range && is_reference_v<_InnerRng> + requires forward_range && is_reference_v<_InnerRng> && input_range<_InnerRng> #endif // TRANSITION, LLVM-47414 { - if constexpr (forward_range && forward_range<_InnerRng> && common_range - && common_range<_InnerRng>) { + if constexpr (forward_range<_InnerRng> && common_range && common_range<_InnerRng>) { return _Iterator{*this, _RANGES end(_Range)}; } else { return _Sentinel{*this}; @@ -3943,7 +3980,8 @@ namespace ranges { #ifdef __clang__ template // TRANSITION, LLVM-47414 concept _Can_const_join_with = - input_range && forward_range && is_reference_v>; + forward_range && forward_range && is_reference_v> + && input_range>; #endif // ^^^ workaround ^^^ _EXPORT_STD template @@ -3971,10 +4009,19 @@ namespace ranges { requires is_reference_v> class _Join_with_view_base<_Vw, _Pat> : public view_interface> {}; + template + class _Join_with_view_outer_iter_base : public _Join_with_view_base<_Vw, _Pat> { + protected: + _Non_propagating_cache> _Outer_it; + }; + + template + class _Join_with_view_outer_iter_base<_Vw, _Pat> : public _Join_with_view_base<_Vw, _Pat> {}; + _EXPORT_STD template requires view<_Vw> && input_range> && view<_Pat> && _Compatible_joinable_ranges, _Pat> - class join_with_view : public _Join_with_view_base<_Vw, _Pat> { + class join_with_view : public _Join_with_view_outer_iter_base<_Vw, _Pat> { private: template using _InnerRng = range_reference_t<_Maybe_const<_Const, _Vw>>; @@ -3982,9 +4029,6 @@ namespace ranges { /* [[no_unique_address]] */ _Vw _Range{}; /* [[no_unique_address]] */ _Pat _Pattern{}; - template - class _Sentinel; - template struct _Category_base {}; @@ -4011,10 +4055,26 @@ namespace ranges { }; template - class _Iterator : public _Category_base<_Const> { + class _Iterator_base : public _Category_base<_Const> {}; + + template + requires forward_range<_Maybe_const<_Const, _Vw>> + class _Iterator_base<_Const> : public _Category_base<_Const> { + protected: + using _OuterIter = iterator_t<_Maybe_const<_Const, _Vw>>; + + _Iterator_base() = default; + constexpr explicit _Iterator_base(_OuterIter&& _Outer_it_) : _Outer_it(_STD move(_Outer_it_)) {} + + /* [[no_unique_address]] */ _OuterIter _Outer_it{}; + }; + + template + class _Iterator : public _Iterator_base<_Const> { private: friend join_with_view; + using _Mybase = _Iterator_base<_Const>; using _Parent_t = _Maybe_const<_Const, join_with_view>; using _Base = _Maybe_const<_Const, _Vw>; using _PatternBase = _Maybe_const<_Const, _Pat>; @@ -4027,29 +4087,53 @@ namespace ranges { static constexpr bool _Deref_is_glvalue = is_reference_v<_InnerRng<_Const>>; _Parent_t* _Parent{}; - /* [[no_unique_address]] */ _OuterIter _Outer_it{}; _Variantish<_PatternIter, _InnerIter> _Inner_it{}; - constexpr _Iterator(_Parent_t& _Parent_, iterator_t<_Base> _Outer_) - : _Parent(_STD addressof(_Parent_)), _Outer_it(_STD move(_Outer_)) { - if (_Outer_it != _RANGES end(_Parent->_Range)) { - auto&& _Inner = _Update_inner(); - _Inner_it._Emplace_second(_RANGES begin(_Inner)); + constexpr _Iterator(_Parent_t& _Parent_, _OuterIter _Outer_) + requires forward_range<_Base> + : _Mybase(_STD move(_Outer_)), _Parent(_STD addressof(_Parent_)) { + if (this->_Outer_it != _RANGES end(_Parent->_Range)) { + _Inner_it._Emplace_second(_RANGES begin(_Update_inner())); + _Satisfy(); + } + } + + constexpr explicit _Iterator(_Parent_t& _Parent_) + requires (!forward_range<_Base>) + : _Parent{_STD addressof(_Parent_)} { + if (*_Parent->_Outer_it != _RANGES end(_Parent->_Range)) { + _Inner_it._Emplace_second(_RANGES begin(_Update_inner())); _Satisfy(); } } - _NODISCARD constexpr auto&& _Update_inner() { + _NODISCARD constexpr _OuterIter& _Get_outer() noexcept { + if constexpr (forward_range<_Base>) { + return this->_Outer_it; + } else { + return *_Parent->_Outer_it; + } + } + + _NODISCARD constexpr const _OuterIter& _Get_outer() const noexcept { + if constexpr (forward_range<_Base>) { + return this->_Outer_it; + } else { + return *_Parent->_Outer_it; + } + } + + _NODISCARD constexpr auto& _Update_inner() { if constexpr (_Deref_is_glvalue) { - return *_Outer_it; + return _As_lvalue(*_Get_outer()); } else { - return _Parent->_Inner._Emplace(_Not_quite_object::_Construct_tag{}, _Outer_it)._Val; + return _Parent->_Inner._Emplace(_Not_quite_object::_Construct_tag{}, _Get_outer())._Val; } } - _NODISCARD constexpr auto&& _Get_inner() noexcept { + _NODISCARD constexpr auto& _Get_inner() noexcept { if constexpr (_Deref_is_glvalue) { - return *_Outer_it; + return _As_lvalue(*_Get_outer()); } else { return (*_Parent->_Inner)._Val; } @@ -4073,16 +4157,15 @@ namespace ranges { break; } - auto&& _Inner = _Update_inner(); - _Inner_it._Emplace_second(_RANGES begin(_Inner)); + _Inner_it._Emplace_second(_RANGES begin(_Update_inner())); } else { _STL_INTERNAL_CHECK(_Inner_it._Contains == _Variantish_state::_Holds_second); - auto&& _Inner = _Get_inner(); - if (_Inner_it._Second != _RANGES end(_Inner)) { + if (_Inner_it._Second != _RANGES end(_Get_inner())) { break; } + auto& _Outer_it = _Get_outer(); ++_Outer_it; if (_Outer_it == _RANGES end(_Parent->_Range)) { if constexpr (_Deref_is_glvalue) { @@ -4115,7 +4198,7 @@ namespace ranges { && convertible_to, _OuterIter> // && convertible_to>, _InnerIter> // && convertible_to, _PatternIter> // - : _Parent(_It._Parent), _Outer_it(_STD move(_It._Outer_it)) { + : _Mybase(_STD move(_It._Outer_it)), _Parent(_It._Parent) { switch (_It._Inner_it._Contains) { case _Variantish_state::_Holds_first: _Inner_it._Emplace_first(_STD move(_It._Inner_it._First)); @@ -4164,10 +4247,10 @@ namespace ranges { requires _Deref_is_glvalue && bidirectional_range<_Base> // && _Bidi_common_range<_InnerRng<_Const>> && _Bidi_common_range<_PatternBase> { + auto& _Outer_it = _Get_outer(); if (_Outer_it == _RANGES end(_Parent->_Range)) { --_Outer_it; - auto&& _Inner = *_Outer_it; - _Inner_it._Emplace_second(_RANGES end(_Inner)); + _Inner_it._Emplace_second(_RANGES end(_Get_inner())); } for (;;) { @@ -4175,15 +4258,13 @@ namespace ranges { auto& _It = _Inner_it._First; if (_It == _RANGES begin(_Parent->_Pattern)) { --_Outer_it; - auto&& _Inner = *_Outer_it; - _Inner_it._Emplace_second(_RANGES end(_Inner)); + _Inner_it._Emplace_second(_RANGES end(_Get_inner())); } else { break; } } else if (_Inner_it._Contains == _Variantish_state::_Holds_second) { - auto& _It = _Inner_it._Second; - auto&& _Inner = *_Outer_it; - if (_It == _RANGES begin(_Inner)) { + auto& _It = _Inner_it._Second; + if (_It == _RANGES begin(_Get_inner())) { _Inner_it._Emplace_first(_RANGES end(_Parent->_Pattern)); } else { break; @@ -4216,7 +4297,7 @@ namespace ranges { } _NODISCARD_FRIEND constexpr bool operator==(const _Iterator& _Left, const _Iterator& _Right) - requires _Deref_is_glvalue && equality_comparable<_OuterIter> && equality_comparable<_InnerIter> + requires _Deref_is_glvalue && forward_range<_Base> && equality_comparable<_InnerIter> { if (_Left._Outer_it != _Right._Outer_it) { return false; @@ -4293,10 +4374,10 @@ namespace ranges { template _NODISCARD constexpr bool _Equal(const _Iterator<_OtherConst>& _It) const - noexcept(noexcept(_Fake_copy_init(_It._Outer_it == _Last))) { + noexcept(noexcept(_Fake_copy_init(_It._Get_outer() == _Last))) { _STL_INTERNAL_STATIC_ASSERT( sentinel_for, iterator_t<_Maybe_const<_OtherConst, _Vw>>>); - return _It._Outer_it == _Last; + return _It._Get_outer() == _Last; } public: @@ -4342,15 +4423,21 @@ namespace ranges { } _NODISCARD constexpr auto begin() { - constexpr bool _Use_const = _Simple_view<_Vw> && is_reference_v<_InnerRng> && _Simple_view<_Pat>; - return _Iterator<_Use_const>{*this, _RANGES begin(_Range)}; + if constexpr (forward_range<_Vw>) { + constexpr bool _Use_const = _Simple_view<_Vw> && is_reference_v<_InnerRng> && _Simple_view<_Pat>; + return _Iterator<_Use_const>{*this, _RANGES begin(_Range)}; + } else { + this->_Outer_it._Emplace(_RANGES begin(_Range)); + return _Iterator{*this}; + } } _NODISCARD constexpr auto begin() const #ifdef __clang__ // TRANSITION, LLVM-47414 requires _Can_const_join_with<_Vw, _Pat> #else // ^^^ workaround / no workaround vvv - requires input_range && forward_range && is_reference_v<_InnerRng> + requires forward_range && forward_range && is_reference_v<_InnerRng> + && input_range<_InnerRng> #endif // TRANSITION, LLVM-47414 { return _Iterator{*this, _RANGES begin(_Range)}; @@ -4371,11 +4458,11 @@ namespace ranges { #ifdef __clang__ // TRANSITION, LLVM-47414 requires _Can_const_join_with<_Vw, _Pat> #else // ^^^ workaround / no workaround vvv - requires input_range && forward_range && is_reference_v<_InnerRng> + requires forward_range && forward_range && is_reference_v<_InnerRng> + && input_range<_InnerRng> #endif // TRANSITION, LLVM-47414 { - if constexpr (forward_range && forward_range<_InnerRng> // - && common_range<_Vw> && common_range<_InnerRng>) { + if constexpr (forward_range<_InnerRng> && common_range<_Vw> && common_range<_InnerRng>) { return _Iterator{*this, _RANGES end(_Range)}; } else { return _Sentinel{*this}; diff --git a/stl/inc/regex b/stl/inc/regex index dc5c484cf5..f783b5585c 100644 --- a/stl/inc/regex +++ b/stl/inc/regex @@ -2387,6 +2387,9 @@ public: using pointer = const value_type*; using reference = const value_type&; using iterator_category = forward_iterator_tag; +#if _HAS_CXX20 + using iterator_concept = input_iterator_tag; +#endif // _HAS_CXX20 regex_iterator() : _MyRe(nullptr) {} // construct end of sequence iterator @@ -2523,6 +2526,9 @@ public: using pointer = const value_type*; using reference = const value_type&; using iterator_category = forward_iterator_tag; +#if _HAS_CXX20 + using iterator_concept = input_iterator_tag; +#endif // _HAS_CXX20 regex_token_iterator() : _Res(nullptr) {} // construct end of sequence iterator diff --git a/stl/inc/yvals_core.h b/stl/inc/yvals_core.h index 0837c68a0e..2b502f7bba 100644 --- a/stl/inc/yvals_core.h +++ b/stl/inc/yvals_core.h @@ -289,6 +289,7 @@ // P2602R2 Poison Pills Are Too Toxic // P2609R3 Relaxing Ranges Just A Smidge // P2711R1 Making Multi-Param Constructors Of Views explicit +// P2770R0 Stashing Stashing Iterators For Proper Flattening // _HAS_CXX20 indirectly controls: // P0619R4 Removing C++17-Deprecated Features diff --git a/tests/libcxx/expected_results.txt b/tests/libcxx/expected_results.txt index cb9206752b..ee34f04da4 100644 --- a/tests/libcxx/expected_results.txt +++ b/tests/libcxx/expected_results.txt @@ -141,6 +141,15 @@ std/ranges/range.access/rbegin.pass.cpp FAIL std/ranges/range.access/rend.pass.cpp FAIL std/ranges/range.access/size.pass.cpp FAIL +# libc++ doesn't implement P2770R0 "Stashing stashing iterators for proper flattening" +std/ranges/range.adaptors/range.join.view/end.pass.cpp FAIL +std/ranges/range.adaptors/range.join.view/iterator/ctor.other.pass.cpp FAIL +std/ranges/range.adaptors/range.join.view/iterator/ctor.parent.outer.pass.cpp FAIL +std/ranges/range.adaptors/range.join.view/iterator/eq.pass.cpp FAIL +std/ranges/range.adaptors/range.join.view/sentinel/eq.pass.cpp FAIL +std/re/re.iter/re.regiter/iterator_concept_conformance.compile.pass.cpp FAIL +std/re/re.iter/re.tokiter/iterator_concept_conformance.compile.pass.cpp FAIL + # libc++ doesn't implement LWG-3865 Sorting a range of pairs std/utilities/tuple/tuple.tuple/tuple.apply/make_from_tuple.pass.cpp FAIL diff --git a/tests/libcxx/usual_matrix.lst b/tests/libcxx/usual_matrix.lst index 4a66aa7f1f..5604d27fed 100644 --- a/tests/libcxx/usual_matrix.lst +++ b/tests/libcxx/usual_matrix.lst @@ -3,7 +3,7 @@ RUNALL_INCLUDE ..\universal_prefix.lst RUNALL_CROSSLIST -PM_CL="/EHsc /MTd /std:c++latest /permissive- /utf-8 /FImsvc_stdlib_force_include.h /wd4643 /D_STL_CALL_ABORT_INSTEAD_OF_INVALID_PARAMETER /D_USE_JOIN_VIEW_INPUT_RANGE" +PM_CL="/EHsc /MTd /std:c++latest /permissive- /utf-8 /FImsvc_stdlib_force_include.h /wd4643 /D_STL_CALL_ABORT_INSTEAD_OF_INVALID_PARAMETER" RUNALL_CROSSLIST PM_CL="/analyze:autolog- /Zc:preprocessor /wd6262" PM_COMPILER="clang-cl" PM_CL="-fno-ms-compatibility -fno-delayed-template-parsing -Wno-unqualified-std-cast-call" diff --git a/tests/std/include/range_algorithm_support.hpp b/tests/std/include/range_algorithm_support.hpp index e6b629025b..95f2b94011 100644 --- a/tests/std/include/range_algorithm_support.hpp +++ b/tests/std/include/range_algorithm_support.hpp @@ -112,7 +112,7 @@ namespace test { enum class CanDifference : bool { no, yes }; enum class CanCompare : bool { no, yes }; - enum class ProxyRef { no, yes, prvalue }; + enum class ProxyRef { no, yes, prvalue, xvalue }; enum class WrappedState { wrapped, unwrapped, @@ -394,8 +394,9 @@ namespace test { template struct init_list_not_constructible_iterator { - using difference_type = int; - using value_type = T; + using iterator_category = std::forward_iterator_tag; + using difference_type = int; + using value_type = T; init_list_not_constructible_iterator() = default; init_list_not_constructible_iterator(T*) {} @@ -407,10 +408,11 @@ namespace test { init_list_not_constructible_iterator& operator++(); // not defined init_list_not_constructible_iterator operator++(int); // not defined + bool operator==(init_list_not_constructible_iterator) const; // not defined bool operator==(init_list_not_constructible_sentinel) const; // not defined }; - static_assert(std::input_iterator>); + static_assert(std::forward_iterator>); static_assert( std::sentinel_for, init_list_not_constructible_iterator>); @@ -433,7 +435,8 @@ namespace test { static constexpr bool at_least = derived_from; using ReferenceType = conditional_t, - conditional_t, Element&>>; + conditional_t, + conditional_t>>; struct post_increment_proxy { Element* ptr_; @@ -475,7 +478,7 @@ namespace test { } [[nodiscard]] constexpr ReferenceType operator*() const noexcept { - return ReferenceType{*ptr_}; + return static_cast(*ptr_); } template diff --git a/tests/std/tests/P0896R4_views_elements/test.cpp b/tests/std/tests/P0896R4_views_elements/test.cpp index 1bff24a240..61a76c174f 100644 --- a/tests/std/tests/P0896R4_views_elements/test.cpp +++ b/tests/std/tests/P0896R4_views_elements/test.cpp @@ -396,7 +396,7 @@ constexpr void instantiation_test() { // GH-3014 ": list-initialization is misused" void test_gh_3014() { // COMPILE-ONLY - struct InRange { + struct FwdRange { P* begin() { return nullptr; } @@ -410,7 +410,7 @@ void test_gh_3014() { // COMPILE-ONLY } }; - auto r = InRange{} | views::elements<0>; + auto r = FwdRange{} | views::elements<0>; [[maybe_unused]] decltype(as_const(r).begin()) i = r.begin(); // Check 'iterator(iterator i)' } diff --git a/tests/std/tests/P0896R4_views_join/test.cpp b/tests/std/tests/P0896R4_views_join/test.cpp index ba5949952d..96d87e350f 100644 --- a/tests/std/tests/P0896R4_views_join/test.cpp +++ b/tests/std/tests/P0896R4_views_join/test.cpp @@ -1,8 +1,6 @@ // Copyright (c) Microsoft Corporation. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -#define _USE_JOIN_VIEW_INPUT_RANGE - #include #include #include @@ -145,7 +143,10 @@ constexpr bool test_one(Outer&& rng, Expected&& expected) { // Validate join_view::begin static_assert(CanMemberBegin); - static_assert(CanMemberBegin == (input_range && is_reference_v>) ); + // clang-format off + static_assert(CanMemberBegin == (forward_range && is_reference_v> + && input_range>) ); + // clang-format on if (forward_range) { const iterator_t i = r.begin(); if (!is_empty) { @@ -179,8 +180,9 @@ constexpr bool test_one(Outer&& rng, Expected&& expected) { // Validate join_view::end static_assert(CanMemberEnd); - static_assert(CanMemberEnd == (input_range && is_reference_v>) ); // clang-format off + static_assert(CanMemberEnd == (forward_range && is_reference_v> + && input_range>) ); static_assert(common_range == (forward_range && is_reference_v> && common_range && forward_range && common_range) ); static_assert(common_range == (forward_range && is_reference_v> @@ -512,7 +514,7 @@ void test_non_trivially_destructible_type() { // COMPILE-ONLY // GH-3014 ": list-initialization is misused" void test_gh_3014() { // COMPILE-ONLY - struct InRange { + struct FwdRange { string* begin() { return nullptr; } @@ -526,10 +528,87 @@ void test_gh_3014() { // COMPILE-ONLY } }; - auto r = InRange{} | views::join; + auto r = FwdRange{} | views::join; [[maybe_unused]] decltype(as_const(r).begin()) i = r.begin(); // Check 'iterator(iterator i)' } +constexpr bool test_lwg3698() { + // LWG-3698 "regex_iterator and join_view don't work together very well" + struct stashing_iterator { + using difference_type = int; + using value_type = span; + + int x = 1; + + constexpr stashing_iterator& operator++() { + ++x; + return *this; + } + constexpr void operator++(int) { + ++x; + } + constexpr value_type operator*() const { + return {&x, &x + 1}; + } + constexpr bool operator==(default_sentinel_t) const { + return x > 3; + } + }; + + auto r = ranges::subrange{stashing_iterator{}, default_sentinel} | views::join; + auto r2 = r; + auto it = r.begin(); + auto it2 = r2.begin(); + + auto itcopy = it; + it = ++it2; + assert(*itcopy == 1); + + struct intricate_range { + constexpr stashing_iterator begin() { + return {}; + } + constexpr default_sentinel_t end() { + return {}; + } + constexpr const span* begin() const { + return ranges::begin(intervals); + } + constexpr const span* end() const { + return ranges::end(intervals); + } + }; + + auto jv = intricate_range{} | views::join; + auto cit = as_const(jv).begin(); + assert(*++cit == 1); + assert(*--cit == 0); + assert(ranges::equal(as_const(jv), expected_ints)); + + return true; +} + +void test_lwg3700() { // COMPILE-ONLY + // LWG-3700 "The const begin of the join_view family does not require InnerRng to be a range" + auto r = views::iota(0, 5) | views::filter([](auto) { return true; }); + auto j = views::single(r) | views::join; + using J = decltype(j); + STATIC_ASSERT(!CanMemberBegin); + STATIC_ASSERT(!CanMemberEnd); +} + +constexpr bool test_lwg3791() { + // LWG-3791 "join_view::iterator::operator-- may be ill-formed" + // Validate that join_view works when range_reference_t is an rvalue reference + using inner = test::range; + using outer = test::range; + + instantiator::call(); + + return true; +} + int main() { // Validate views constexpr string_view expected = "Hello World!"sv; @@ -622,4 +701,10 @@ int main() { STATIC_ASSERT(instantiation_test()); instantiation_test(); + + STATIC_ASSERT(test_lwg3698()); + assert(test_lwg3698()); + + STATIC_ASSERT(test_lwg3791()); + assert(test_lwg3791()); } diff --git a/tests/std/tests/P0896R4_views_transform/test.cpp b/tests/std/tests/P0896R4_views_transform/test.cpp index e314e7e6a3..57bfc5020c 100644 --- a/tests/std/tests/P0896R4_views_transform/test.cpp +++ b/tests/std/tests/P0896R4_views_transform/test.cpp @@ -813,7 +813,7 @@ void test_gh_1709() { // GH-3014 ": list-initialization is misused" void test_gh_3014() { // COMPILE-ONLY - struct InRange { + struct FwdRange { int* begin() { return nullptr; } @@ -827,7 +827,7 @@ void test_gh_3014() { // COMPILE-ONLY } }; - auto r = InRange{} | views::transform(identity{}); + auto r = FwdRange{} | views::transform(identity{}); [[maybe_unused]] decltype(as_const(r).begin()) i = r.begin(); // Check 'iterator(iterator i)' } diff --git a/tests/std/tests/P2441R2_views_join_with/test.cpp b/tests/std/tests/P2441R2_views_join_with/test.cpp index 852d78745c..a1e61bf65a 100644 --- a/tests/std/tests/P2441R2_views_join_with/test.cpp +++ b/tests/std/tests/P2441R2_views_join_with/test.cpp @@ -187,7 +187,8 @@ constexpr void test_one(Outer&& rng, Delimiter&& delimiter, Expected&& expected) // Validate join_with_view::begin STATIC_ASSERT(CanMemberBegin); STATIC_ASSERT(CanMemberBegin - == (input_range && forward_range && is_reference_v>) ); + == (forward_range && forward_range && is_reference_v> + && input_range>) ); if (forward_range) { // intentionally not if constexpr const auto i = r.begin(); if (!is_empty) { @@ -222,7 +223,8 @@ constexpr void test_one(Outer&& rng, Delimiter&& delimiter, Expected&& expected) // Validate join_with_view::end static_assert(CanMemberEnd); static_assert(CanMemberEnd - == (input_range && forward_range && is_reference_v>) ); + == (forward_range && forward_range && is_reference_v> + && input_range>) ); static_assert(common_range == (forward_range && is_reference_v> && common_range && forward_range && common_range) ); @@ -570,7 +572,7 @@ struct FakeStr { }; void test_gh_3014() { // COMPILE-ONLY - struct InRange { + struct FwdRange { FakeStr* begin() { return nullptr; } @@ -588,11 +590,81 @@ void test_gh_3014() { // COMPILE-ONLY } }; - auto r = InRange{} | views::join_with('-'); + auto r = FwdRange{} | views::join_with('-'); [[maybe_unused]] decltype(as_const(r).begin()) i = r.begin(); // Check 'iterator(iterator i)' [[maybe_unused]] decltype(as_const(r).end()) s = r.end(); // Check 'sentinel(sentinel s)' } +constexpr bool test_lwg3698() { + // LWG-3698 "regex_iterator and join_view don't work together very well" + struct stashing_iterator { + using difference_type = int; + using value_type = span; + + int x = 1; + + constexpr stashing_iterator& operator++() { + ++x; + return *this; + } + constexpr void operator++(int) { + ++x; + } + constexpr value_type operator*() const { + return {&x, &x + 1}; + } + constexpr bool operator==(default_sentinel_t) const { + return x > 3; + } + }; + + auto r = ranges::subrange{stashing_iterator{}, default_sentinel} | views::join_with(views::empty); + auto r2 = r; + auto it = r.begin(); + auto it2 = r2.begin(); + + auto itcopy = it; + it = ++it2; + assert(*itcopy == 1); + + constexpr int expected_ints[] = {1, 2, 3, 5, 7}; + span intervals[2] = {{expected_ints + 0, expected_ints + 3}, {expected_ints + 3, expected_ints + 5}}; + + struct intricate_range { + span* p; + + constexpr stashing_iterator begin() { + return {}; + } + constexpr default_sentinel_t end() { + return {}; + } + constexpr const span* begin() const { + return p; + } + constexpr const span* end() const { + return p + 2; + } + }; + + auto jwv = intricate_range{.p = intervals} | views::join_with(views::empty); + auto cit = as_const(jwv).begin(); + assert(*++cit == 2); + assert(*--cit == 1); + assert(ranges::equal(as_const(jwv), expected_ints)); + + return true; +} + +void test_lwg3700() { // COMPILE-ONLY + // LWG-3700 "The const begin of the join_view family does not require InnerRng to be a range" + auto r = views::iota(0, 5) | views::filter([](auto) { return true; }); + auto j = views::single(r) | views::join_with(-1); + using J = decltype(j); + STATIC_ASSERT(!CanMemberBegin); + STATIC_ASSERT(!CanMemberEnd); +} + int main() { { auto filtered_and_joined = @@ -604,4 +676,7 @@ int main() { instantiation_test(); test_valueless_iterator(); + + STATIC_ASSERT(test_lwg3698()); + assert(test_lwg3698()); }