diff --git a/stl/inc/filesystem b/stl/inc/filesystem index 34fbee72264..4a78aa751b0 100644 --- a/stl/inc/filesystem +++ b/stl/inc/filesystem @@ -1455,8 +1455,10 @@ namespace filesystem { _Path_iterator(const _Base_iter& _Position_, const path* _Mypath_) noexcept : _Position(_Position_), _Element(), _Mypath(_Mypath_) {} - _Path_iterator(const _Base_iter& _Position_, wstring_view _Element_text, const path* _Mypath_) - : _Position(_Position_), _Element(_Element_text), _Mypath(_Mypath_) {} + _Path_iterator(const _Base_iter& _Position_, const path& _Element_, const path* _Mypath_) + : _Position(_Position_), _Element(_Element_), _Mypath(_Mypath_) {} + _Path_iterator(const _Base_iter& _Position_, path&& _Element_, const path* _Mypath_) + : _Position(_Position_), _Element(_STD move(_Element_)), _Mypath(_Mypath_) {} _Path_iterator(const _Path_iterator&) = default; _Path_iterator(_Path_iterator&&) = default; @@ -1600,8 +1602,13 @@ namespace filesystem { using _Prevent_inheriting_unwrap = _Path_iterator; template , int> = 0> - _NODISCARD _Path_iterator<_Unwrapped_t> _Unwrapped() const { - return {_Position._Unwrapped(), _Element.native(), _Mypath}; + _NODISCARD _Path_iterator<_Unwrapped_t> _Unwrapped() const& noexcept(false) { + return {_Position._Unwrapped(), _Element, _Mypath}; + } + template , int> = 0> + _NODISCARD _Path_iterator<_Unwrapped_t<_Iter2>> _Unwrapped() && noexcept { + _STL_INTERNAL_STATIC_ASSERT(noexcept(_Is_nothrow_unwrappable_v<_Iter2>)); + return {_Position._Unwrapped(), _STD move(_Element), _Mypath}; } static constexpr bool _Unwrap_when_unverified = _Do_unwrap_when_unverified_v<_Base_iter>; diff --git a/stl/inc/iterator b/stl/inc/iterator index f719511760a..8486fbee1d0 100644 --- a/stl/inc/iterator +++ b/stl/inc/iterator @@ -1371,12 +1371,19 @@ public: using _Prevent_inheriting_unwrap = counted_iterator; - _NODISCARD constexpr counted_iterator<_Unwrapped_t> - _Unwrapped() const& requires _Unwrappable_v { + // clang-format off + _NODISCARD constexpr counted_iterator<_Unwrapped_t> _Unwrapped() const& + noexcept(noexcept(counted_iterator<_Unwrapped_t>{_Current._Unwrapped(), _Length})) + requires _Unwrappable_v { + // clang-format on return counted_iterator<_Unwrapped_t>{_Current._Unwrapped(), _Length}; } - _NODISCARD constexpr counted_iterator<_Unwrapped_t<_Iter>> _Unwrapped() && requires _Unwrappable_v<_Iter> { + // clang-format off + _NODISCARD constexpr counted_iterator<_Unwrapped_t<_Iter>> _Unwrapped() && + noexcept(noexcept(counted_iterator<_Unwrapped_t<_Iter>>{_STD move(_Current)._Unwrapped(), _Length})) + requires _Unwrappable_v<_Iter> { + // clang-format on return counted_iterator<_Unwrapped_t<_Iter>>{_STD move(_Current)._Unwrapped(), _Length}; } diff --git a/stl/inc/ranges b/stl/inc/ranges index 09350ccf20b..1dd2390e79e 100644 --- a/stl/inc/ranges +++ b/stl/inc/ranges @@ -1917,24 +1917,26 @@ namespace ranges { input_iterator_tag>; }; - template + template class _Iterator : public _Category_base<_Const> { private: - template + template friend class _Iterator; template friend class _Sentinel; - using _Parent_t = _Maybe_const<_Const, transform_view>; - using _Base = _Maybe_const<_Const, _Vw>; + using _Parent_t = _Maybe_const<_Const, transform_view>; + using _Base = _Maybe_const<_Const, _Vw>; + using _Base_iter = _Maybe_unwrapped_iterator_t<_Base, _Is_unwrapped>; - iterator_t<_Base> _Current{}; + _Base_iter _Current{}; _Parent_t* _Parent{}; #if _ITERATOR_DEBUG_LEVEL != 0 constexpr void _Check_dereference() const noexcept { _STL_VERIFY(_Parent != nullptr, "cannot dereference value-initialized transform_view iterator"); - _STL_VERIFY(_Current != _RANGES end(_Parent->_Range), "cannot dereference end transform_view iterator"); + _STL_VERIFY(_Current != _Get_maybe_unwrapped<_Is_unwrapped>(_RANGES end(_Parent->_Range)), + "cannot dereference end transform_view iterator"); } #endif // _ITERATOR_DEBUG_LEVEL != 0 @@ -1952,32 +1954,33 @@ namespace ranges { using difference_type = range_difference_t<_Base>; // clang-format off - _Iterator() requires default_initializable> = default; + _Iterator() requires default_initializable<_Base_iter> = default; // clang-format on - constexpr _Iterator(_Parent_t& _Parent_, iterator_t<_Base> _Current_) noexcept( - is_nothrow_move_constructible_v>) // strengthened + constexpr _Iterator(_Parent_t& _Parent_, _Base_iter _Current_) noexcept( + is_nothrow_move_constructible_v<_Base_iter>) // strengthened : _Current{_STD move(_Current_)}, _Parent{_STD addressof(_Parent_)} { #if _ITERATOR_DEBUG_LEVEL != 0 - _Adl_verify_range(_Current, _RANGES end(_Parent_._Range)); + _Adl_verify_range(_Current, _Get_maybe_unwrapped<_Is_unwrapped>(_RANGES end(_Parent_._Range))); if constexpr (forward_range<_Base>) { - _Adl_verify_range(_RANGES begin(_Parent_._Range), _Current); + _Adl_verify_range(_Get_maybe_unwrapped<_Is_unwrapped>(_RANGES begin(_Parent_._Range)), _Current); } #endif // _ITERATOR_DEBUG_LEVEL != 0 } // clang-format off - constexpr _Iterator(_Iterator _It) - noexcept(is_nothrow_constructible_v, iterator_t<_Vw>>) // strengthened - requires _Const && convertible_to, iterator_t<_Base>> + constexpr _Iterator(_Iterator _It) + noexcept(is_nothrow_constructible_v<_Base_iter, _Base_iter>) // strengthened + requires _Const + && convertible_to<_Maybe_unwrapped_iterator_t<_Vw, _Is_unwrapped>, _Base_iter> : _Current{_STD move(_It._Current)}, _Parent{_It._Parent} {} // clang-format on - _NODISCARD constexpr const iterator_t<_Base>& base() const& noexcept { + _NODISCARD constexpr const _Base_iter& base() const& noexcept { return _Current; } - _NODISCARD constexpr iterator_t<_Base> base() && noexcept( - is_nothrow_move_constructible_v>) /* strengthened */ { + _NODISCARD constexpr _Base_iter base() && noexcept( + is_nothrow_move_constructible_v<_Base_iter>) /* strengthened */ { return _STD move(_Current); } @@ -1994,8 +1997,8 @@ namespace ranges { constexpr _Iterator& operator++() noexcept(noexcept(++_Current)) /* strengthened */ { #if _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(_Parent != nullptr, "Cannot increment value-initialized transform_view iterator"); - _STL_VERIFY( - _Current != _RANGES end(_Parent->_Range), "Cannot increment transform_view iterator past end"); + _STL_VERIFY(_Current != _Get_maybe_unwrapped<_Is_unwrapped>(_RANGES end(_Parent->_Range)), + "Cannot increment transform_view iterator past end"); #endif // _ITERATOR_DEBUG_LEVEL != 0 ++_Current; return *this; @@ -2003,7 +2006,7 @@ namespace ranges { constexpr decltype(auto) operator++(int) noexcept( noexcept(++_Current) - && (!forward_range<_Base> || is_nothrow_copy_constructible_v>) ) /* strengthened */ { + && (!forward_range<_Base> || is_nothrow_copy_constructible_v<_Base_iter>) ) /* strengthened */ { if constexpr (forward_range<_Base>) { auto _Tmp = *this; ++*this; @@ -2018,7 +2021,7 @@ namespace ranges { #if _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(_Parent != nullptr, "Cannot decrement value-initialized transform_view iterator"); if constexpr (forward_range<_Vw>) { - _STL_VERIFY(_Current != _RANGES begin(_Parent->_Range), + _STL_VERIFY(_Current != _Get_maybe_unwrapped<_Is_unwrapped>(_RANGES begin(_Parent->_Range)), "Cannot decrement transform_view iterator before begin"); } #endif // _ITERATOR_DEBUG_LEVEL != 0 @@ -2026,7 +2029,7 @@ namespace ranges { return *this; } constexpr _Iterator operator--(int) noexcept( - noexcept(--_Current) && is_nothrow_copy_constructible_v>) /* strengthened */ + noexcept(--_Current) && is_nothrow_copy_constructible_v<_Base_iter>) /* strengthened */ requires bidirectional_range<_Base> { auto _Tmp = *this; --*this; @@ -2039,23 +2042,26 @@ namespace ranges { #else // ^^^ _ITERATOR_DEBUG_LEVEL == 0 / _ITERATOR_DEBUG_LEVEL != 0 vvv _STL_VERIFY(_Off == 0 || _Parent, "cannot seek value-initialized transform_view iterator"); - if constexpr (_Offset_verifiable_v>) { + if constexpr (_Offset_verifiable_v<_Base_iter>) { _Current._Verify_offset(_Off); } else { if (_Off < 0) { - if constexpr (sized_sentinel_for, iterator_t<_Base>>) { - _STL_VERIFY(_Off >= _RANGES begin(_Parent->_Range) - _Current, + if constexpr (sized_sentinel_for<_Base_iter, _Base_iter>) { + _STL_VERIFY( + _Off >= _Get_maybe_unwrapped<_Is_unwrapped>(_RANGES begin(_Parent->_Range)) - _Current, "cannot seek transform_view iterator before begin"); } } else if (_Off > 0) { - if constexpr (sized_sentinel_for, iterator_t<_Base>>) { - _STL_VERIFY(_Off <= _RANGES end(_Parent->_Range) - _Current, + if constexpr (sized_sentinel_for, _Base_iter>) { + _STL_VERIFY( + _Off <= _Get_maybe_unwrapped<_Is_unwrapped>(_RANGES end(_Parent->_Range)) - _Current, "cannot seek transform_view iterator after end"); - } else if constexpr (sized_sentinel_for, - iterator_t<_Base>> && sized_range<_Base>) { + } else if constexpr (sized_sentinel_for<_Base_iter, _Base_iter> && sized_range<_Base>) { const auto _Size = _RANGES distance(_Parent->_Range); - _STL_VERIFY(_Off <= _Size - (_Current - _RANGES begin(_Parent->_Range)), - "cannot seek transform_view iterator after end"); + const auto _Distance_to_begin = + _Current - _Get_maybe_unwrapped<_Is_unwrapped>(_RANGES begin(_Parent->_Range)); + + _STL_VERIFY(_Off <= _Size - _Distance_to_begin), "cannot seek transform_view iterator after end"); } } } @@ -2091,8 +2097,8 @@ namespace ranges { } _NODISCARD_FRIEND constexpr bool operator==(const _Iterator& _Left, const _Iterator& _Right) noexcept( - noexcept(_Left._Current - == _Right._Current)) /* strengthened */ requires equality_comparable> { + noexcept( + _Left._Current == _Right._Current)) /* strengthened */ requires equality_comparable<_Base_iter> { #if _ITERATOR_DEBUG_LEVEL != 0 _Left._Same_range(_Right); #endif // _ITERATOR_DEBUG_LEVEL != 0 @@ -2121,7 +2127,7 @@ namespace ranges { // clang-format off _NODISCARD_FRIEND constexpr auto operator<=>(const _Iterator& _Left, const _Iterator& _Right) noexcept( noexcept(_Left._Current <=> _Right._Current)) /* strengthened */ - requires random_access_range<_Base> && three_way_comparable> { + requires random_access_range<_Base> && three_way_comparable<_Base_iter> { // clang-format on #if _ITERATOR_DEBUG_LEVEL != 0 _Left._Same_range(_Right); @@ -2157,12 +2163,41 @@ namespace ranges { _NODISCARD_FRIEND constexpr difference_type operator-(const _Iterator& _Left, const _Iterator& _Right) noexcept(noexcept(_Left._Current - _Right._Current)) /* strengthened */ - requires sized_sentinel_for, iterator_t<_Base>> { + requires sized_sentinel_for<_Base_iter, _Base_iter> { #if _ITERATOR_DEBUG_LEVEL != 0 _Left._Same_range(_Right); #endif // _ITERATOR_DEBUG_LEVEL != 0 return _Left._Current - _Right._Current; } + + using _Prevent_inheriting_unwrap = + conditional_t, _Iterator, void>; + + // clang-format off + constexpr _Iterator<_Const, true> _Unwrapped() const& + noexcept(noexcept(_Iterator<_Const, true>{*_Parent, _Current._Unwrapped()})) + requires _Unwrappable_v + { + // clang-format on + return _Iterator<_Const, true>{*_Parent, _Current._Unwrapped()}; + } + // clang-format off + constexpr _Iterator<_Const, true> _Unwrapped() && + noexcept(noexcept(_Iterator<_Const, true>{*_Parent, _STD move(_Current)._Unwrapped()})) + requires _Unwrappable_v<_Base_iter> + { + // clang-format on + return _Iterator<_Const, true>{*_Parent, _STD move(_Current)._Unwrapped()}; + } + + // clang-format off + constexpr void _Seek_to(_Iterator<_Const, true> _Other) + noexcept(noexcept(_Current._Seek_to(_Other._Current))) + requires _Unwrappable_v<_Base_iter> + { + // clang-format on + _Current._Seek_to(_Other._Current); + } }; template @@ -2390,12 +2425,15 @@ namespace ranges { // clang-format off _NODISCARD constexpr auto _Unwrapped() const& + noexcept(noexcept(_Sentinel<_Const, false>{_Get_unwrapped(_Last)})) requires _Wrapped && _Unwrappable_v&> { // clang-format on return _Sentinel<_Const, false>{_Get_unwrapped(_Last)}; } // clang-format off - _NODISCARD constexpr auto _Unwrapped() && requires _Wrapped && _Unwrappable_v> { + _NODISCARD constexpr auto _Unwrapped() && + noexcept(noexcept(_Sentinel<_Const, false>{_Get_unwrapped(_STD move(_Last))})) + requires _Wrapped && _Unwrappable_v> { // clang-format on return _Sentinel<_Const, false>{_Get_unwrapped(_STD move(_Last))}; } @@ -2646,12 +2684,15 @@ namespace ranges { // clang-format off _NODISCARD constexpr auto _Unwrapped() const& + noexcept(noexcept(_Sentinel<_Const, false>{_Get_unwrapped(_Last), _Pred})) requires _Wrapped && _Unwrappable_v&> { // clang-format on return _Sentinel<_Const, false>{_Get_unwrapped(_Last), _Pred}; } // clang-format off - _NODISCARD constexpr auto _Unwrapped() && requires _Wrapped && _Unwrappable_v> { + _NODISCARD constexpr auto _Unwrapped() && + noexcept(noexcept(_Sentinel<_Const, false>{_Get_unwrapped(_STD move(_Last)), _Pred})) + requires _Wrapped && _Unwrappable_v> { // clang-format on return _Sentinel<_Const, false>{_Get_unwrapped(_STD move(_Last)), _Pred}; } diff --git a/stl/inc/xutility b/stl/inc/xutility index 51736d0aa92..852373c647a 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -912,8 +912,15 @@ _INLINE_VAR constexpr bool _Unwrappable_v<_Iter, void_t&>()._Seek_to(_STD declval<_Iter>()._Unwrapped()))>> = _Allow_inheriting_unwrap_v<_Remove_cvref_t<_Iter>>; +template > +_INLINE_VAR constexpr bool _Is_nothrow_unwrappable_v = false; + +template +_INLINE_VAR constexpr bool _Is_nothrow_unwrappable_v<_Iter, true> = noexcept(declval<_Iter>()._Unwrapped()); + template -_NODISCARD constexpr decltype(auto) _Get_unwrapped(_Iter&& _It) { +_NODISCARD constexpr decltype(auto) _Get_unwrapped(_Iter&& _It) noexcept( + !_Unwrappable_v<_Iter> || _Is_nothrow_unwrappable_v<_Iter>) { // unwrap an iterator previously subjected to _Adl_verify_range or otherwise validated if constexpr (is_pointer_v>) { // special-case pointers and arrays return _It + 0; @@ -924,8 +931,22 @@ _NODISCARD constexpr decltype(auto) _Get_unwrapped(_Iter&& _It) { } } +template +_NODISCARD constexpr decltype(auto) _Get_maybe_unwrapped(_Iter&& _It) noexcept( + !_Do_unwrap || !_Unwrappable_v<_Iter> || _Is_nothrow_unwrappable_v<_Iter>) { + if constexpr (is_pointer_v>) { + return _It + 0; + } else if constexpr (_Do_unwrap && _Unwrappable_v<_Iter>) { + return static_cast<_Iter&&>(_It)._Unwrapped(); + } else { + return static_cast<_Iter&&>(_It); + } +} + template using _Unwrapped_t = _Remove_cvref_t()))>; +template +using _Maybe_unwrapped_t = _Remove_cvref_t(_STD declval<_Iter>()))>; template _INLINE_VAR constexpr bool _Do_unwrap_when_unverified_v = false; @@ -1363,9 +1384,15 @@ public: } template , int> = 0> - _NODISCARD constexpr reverse_iterator<_Unwrapped_t> _Unwrapped() const { + _NODISCARD constexpr reverse_iterator<_Unwrapped_t> _Unwrapped() const& noexcept( + noexcept(static_cast>>(current._Unwrapped()))) { return static_cast>>(current._Unwrapped()); } + template , int> = 0> + _NODISCARD constexpr reverse_iterator<_Unwrapped_t<_BidIt2>> _Unwrapped() && noexcept( + noexcept(static_cast>>(_STD move(current)._Unwrapped()))) { + return static_cast>>(_STD move(current)._Unwrapped()); + } static constexpr bool _Unwrap_when_unverified = _Do_unwrap_when_unverified_v<_BidIt>; @@ -1728,6 +1755,10 @@ namespace ranges { template using iterator_t = decltype(_RANGES begin(_STD declval<_Ty&>())); + template + using _Unwrapped_iterator_t = _Unwrapped_t>; + template + using _Maybe_unwrapped_iterator_t = _Maybe_unwrapped_t, _Is_unwrapped>; namespace _Unchecked_begin { template @@ -3435,11 +3466,13 @@ public: } template , int> = 0> - _NODISCARD constexpr move_iterator<_Unwrapped_t> _Unwrapped() const& { + _NODISCARD constexpr move_iterator<_Unwrapped_t> _Unwrapped() const& noexcept( + noexcept(static_cast>>(_Current._Unwrapped()))) { return static_cast>>(_Current._Unwrapped()); } template , int> = 0> - _NODISCARD constexpr move_iterator<_Unwrapped_t<_Iter2>> _Unwrapped() && { + _NODISCARD constexpr move_iterator<_Unwrapped_t<_Iter2>> _Unwrapped() && noexcept( + noexcept(static_cast>>(_STD move(_Current)._Unwrapped()))) { return static_cast>>(_STD move(_Current)._Unwrapped()); } diff --git a/tests/std/test.lst b/tests/std/test.lst index fcbeb035e20..bcdc71fa7d0 100644 --- a/tests/std/test.lst +++ b/tests/std/test.lst @@ -209,6 +209,8 @@ tests\GH_002711_Zc_alignedNew- tests\GH_002760_syncstream_memory_leak tests\GH_002769_handle_deque_block_pointers tests\GH_002789_Hash_vec_Tidy +tests\GH_002989_nothrow_unwrappable +tests\GH_002997_unwrapped_view_iterators tests\LWG2597_complex_branch_cut tests\LWG3018_shared_ptr_function tests\LWG3121_constrained_tuple_forwarding_ctor diff --git a/tests/std/tests/GH_002989_nothrow_unwrappable/env.lst b/tests/std/tests/GH_002989_nothrow_unwrappable/env.lst new file mode 100644 index 00000000000..2de7aab2959 --- /dev/null +++ b/tests/std/tests/GH_002989_nothrow_unwrappable/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\usual_17_matrix.lst diff --git a/tests/std/tests/GH_002989_nothrow_unwrappable/test.cpp b/tests/std/tests/GH_002989_nothrow_unwrappable/test.cpp new file mode 100644 index 00000000000..72461bfe096 --- /dev/null +++ b/tests/std/tests/GH_002989_nothrow_unwrappable/test.cpp @@ -0,0 +1,128 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include + +#if _HAS_CXX20 +#include +#endif + +using namespace std; +using filesystem::path; + +#define STATIC_ASSERT(...) static_assert(__VA_ARGS__, #__VA_ARGS__) + +struct Predicate { + template + bool operator()(const T&) const { + return true; + } +}; + +template +void do_single_test() { + if constexpr (_Unwrappable_v) { + STATIC_ASSERT(_Is_nothrow_unwrappable_v); + STATIC_ASSERT(_Is_nothrow_unwrappable_v); + } + STATIC_ASSERT(noexcept(_Get_unwrapped(declval()))); + + if constexpr (_Unwrappable_v) { + STATIC_ASSERT(_Is_nothrow_unwrappable_v == CopyUnwrapNothrow); + STATIC_ASSERT(_Is_nothrow_unwrappable_v == CopyUnwrapNothrow); + } + STATIC_ASSERT(noexcept(_Get_unwrapped(declval())) == CopyUnwrapNothrow); + STATIC_ASSERT(noexcept(_Get_unwrapped(declval())) == CopyUnwrapNothrow); +} + +template +void do_full_test() { + do_single_test(); + do_single_test, CopyUnwrapNothrow>(); + do_single_test, CopyUnwrapNothrow>(); + +#ifdef __cpp_lib_concepts // TRANSITION, GH-395 + using R = ranges::subrange; + + do_single_test, CopyUnwrapNothrow>(); + + // TRANSITION, GH-2997 + do_single_test>, true>(); + do_single_test>, CopyUnwrapNothrow>(); + if constexpr (ranges::bidirectional_range) { + do_single_test>, CopyUnwrapNothrow>(); + } +#endif // __cpp_lib_concepts +} + +struct BidiIterUnwrapThrowing : vector::iterator { + using _Base = vector::iterator; + + using _Base::_Base; + using _Base::iterator_category; + +#ifdef __cpp_lib_concepts // TRANSITION, GH-395 + using _Base::iterator_concept; +#endif + + using _Base::pointer; + using _Base::reference; + using _Base::value_type; + + friend bool operator==(const BidiIterUnwrapThrowing& lhs, const BidiIterUnwrapThrowing& rhs) noexcept { + return static_cast(lhs) == static_cast(rhs); + } + friend bool operator!=(const BidiIterUnwrapThrowing& lhs, const BidiIterUnwrapThrowing& rhs) noexcept { + return static_cast(lhs) != static_cast(rhs); + } + + BidiIterUnwrapThrowing& operator++() { + _Base::operator++(); + return *this; + } + BidiIterUnwrapThrowing operator++(int) { + auto res = *this; + _Base::operator++(); + return res; + } + BidiIterUnwrapThrowing& operator--() { + _Base::operator--(); + return *this; + } + BidiIterUnwrapThrowing operator--(int) { + auto res = *this; + _Base::operator--(); + return res; + } + + using _Prevent_inheriting_unwrap = BidiIterUnwrapThrowing; + + int* _Unwrapped() const& noexcept(false) { + return _Base::_Unwrapped(); + } + int* _Unwrapped() && noexcept { + return std::move(*this)._Base::_Unwrapped(); + } + + void _Seek_to(int* p) & noexcept { + _Base::_Seek_to(p); + } +}; + +int main() { + do_single_test(); + do_full_test(); + do_single_test(); + + do_full_test::iterator>(); + do_full_test::const_iterator>(); + do_full_test::iterator>(); + do_full_test::const_iterator>(); + + do_full_test(); + do_full_test(); +} diff --git a/tests/std/tests/GH_002997_unwrapped_view_iterators/env.lst b/tests/std/tests/GH_002997_unwrapped_view_iterators/env.lst new file mode 100644 index 00000000000..7b6bcff4830 --- /dev/null +++ b/tests/std/tests/GH_002997_unwrapped_view_iterators/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\strict_concepts_20_matrix.lst diff --git a/tests/std/tests/GH_002997_unwrapped_view_iterators/test.cpp b/tests/std/tests/GH_002997_unwrapped_view_iterators/test.cpp new file mode 100644 index 00000000000..42bc81d2ab2 --- /dev/null +++ b/tests/std/tests/GH_002997_unwrapped_view_iterators/test.cpp @@ -0,0 +1,124 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include + +using namespace std; + +#define STATIC_ASSERT(...) static_assert(__VA_ARGS__, #__VA_ARGS__) + +template +struct UnwrappableBase : vector::iterator { + using _Base = vector::iterator; + + using _Base::_Base; + + Derived& operator++() { + _Base::operator++(); + return static_cast(*this); + } + Derived operator++(int) { + auto res = static_cast(*this); + _Base::operator++(); + return res; + } + Derived& operator--() { + _Base::operator--(); + return static_cast(*this); + } + Derived operator--(int) { + auto res = static_cast(*this); + _Base::operator--(); + return res; + } + + using _Prevent_inheriting_unwrap = Derived; + int* _Unwrapped() const& noexcept(false) requires !MoveOnly { + return _Base::_Unwrapped(); + } + int* _Unwrapped() && noexcept { + return _Base::_Unwrapped(); + } + void _Seek_to(int* _It) noexcept { + _Base::_Seek_to(_It); + } + + bool operator==(const UnwrappableBase&) const = default; + auto operator<=>(const UnwrappableBase&) const = default; +}; + +struct ThrowingUnwrappable : UnwrappableBase { + using UnwrappableBase::UnwrappableBase; + + bool operator==(const ThrowingUnwrappable&) const = default; + auto operator<=>(const ThrowingUnwrappable&) const = default; +}; +struct MoveUnwrappable : UnwrappableBase { + using UnwrappableBase::UnwrappableBase; + + bool operator==(const MoveUnwrappable&) const = default; + auto operator<=>(const MoveUnwrappable&) const = default; +}; + +template