diff --git a/stl/inc/algorithm b/stl/inc/algorithm index a7a04ca6003..7fc01e3cc4a 100644 --- a/stl/inc/algorithm +++ b/stl/inc/algorithm @@ -932,17 +932,10 @@ namespace ranges { // We've trimmed matching prefixes and matching suffixes. // Now we need to compare each range's prefix to the other range's suffix. -#ifdef _M_CEE // TRANSITION, VSO-1663257 - const auto _ProjectedPred = [&](auto&& _Left, auto&& _Right) -> bool { - return _STD invoke(_Pred, _STD invoke(_Proj1, _STD forward(_Left)), - _STD invoke(_Proj2, _STD forward(_Right))); - }; -#else // ^^^ workaround / no workaround vvv const auto _ProjectedPred = [&](_Ty1&& _Left, _Ty2&& _Right) -> bool { return _STD invoke(_Pred, _STD invoke(_Proj1, _STD forward<_Ty1>(_Left)), _STD invoke(_Proj2, _STD forward<_Ty2>(_Right))); }; -#endif // ^^^ no workaround ^^^ const _TrimResult _Res = _Trim_completely(_First1, _Final1, _First2, _Final2, _ProjectedPred); @@ -1028,17 +1021,10 @@ namespace ranges { // We've trimmed matching prefixes and matching suffixes. // Now we need to compare each range's prefix to the other range's suffix. -#ifdef _M_CEE // TRANSITION, VSO-1663257 - const auto _ProjectedPred = [&](auto&& _Left, auto&& _Right) -> bool { - return _STD invoke(_Pred, _STD invoke(_Proj1, _STD forward(_Left)), - _STD invoke(_Proj2, _STD forward(_Right))); - }; -#else // ^^^ workaround / no workaround vvv const auto _ProjectedPred = [&](_Ty1&& _Left, _Ty2&& _Right) -> bool { return _STD invoke(_Pred, _STD invoke(_Proj1, _STD forward<_Ty1>(_Left)), _STD invoke(_Proj2, _STD forward<_Ty2>(_Right))); }; -#endif // ^^^ no workaround ^^^ const _TrimResult _Res = _Trim_completely(_First1, _Final1, _First2, _Final2, _ProjectedPred); diff --git a/stl/inc/bitset b/stl/inc/bitset index e90b1c5c3cd..0edffa4ee4c 100644 --- a/stl/inc/bitset +++ b/stl/inc/bitset @@ -32,6 +32,8 @@ public: friend bitset<_Bits>; public: + _CONSTEXPR23 reference(const reference&) = default; + _CONSTEXPR23 ~reference() noexcept {} // TRANSITION, ABI _CONSTEXPR23 reference& operator=(const bool _Val) noexcept { @@ -44,11 +46,6 @@ public: return *this; } - _CONSTEXPR23 reference& flip() noexcept { - _Pbitset->_Flip_unchecked(_Mypos); - return *this; - } - _NODISCARD _CONSTEXPR23 bool operator~() const noexcept { return !_Pbitset->_Subscript(_Mypos); } @@ -57,6 +54,11 @@ public: return _Pbitset->_Subscript(_Mypos); } + _CONSTEXPR23 reference& flip() noexcept { + _Pbitset->_Flip_unchecked(_Mypos); + return *this; + } + private: _CONSTEXPR23 reference() noexcept : _Pbitset(nullptr), _Mypos(0) {} diff --git a/stl/inc/format b/stl/inc/format index 1706947036d..7c78aada0bd 100644 --- a/stl/inc/format +++ b/stl/inc/format @@ -1960,12 +1960,7 @@ public: _NODISCARD size_t _Estimate_required_capacity() const noexcept { using _CharT = typename _Context::char_type; size_t _Result = 0; -#ifdef _M_CEE // TRANSITION, VSO-1663257 - const auto _Visitor = [&_Result](const auto _Arg) noexcept { - using _ArgTy = remove_const_t; -#else // ^^^ workaround / no workaround vvv const auto _Visitor = [&_Result](const _ArgTy _Arg) noexcept { -#endif // ^^^ no workaround ^^^ if constexpr (is_same_v<_ArgTy, basic_string_view<_CharT>>) { _Result += _Arg.size(); } else if constexpr (is_same_v<_ArgTy, const _CharT*>) { diff --git a/stl/inc/iterator b/stl/inc/iterator index 6af048c0988..5eeb541f246 100644 --- a/stl/inc/iterator +++ b/stl/inc/iterator @@ -187,13 +187,13 @@ public: constexpr move_sentinel() = default; constexpr explicit move_sentinel(_Se _Val) noexcept(is_nothrow_move_constructible_v<_Se>) // strengthened - : _Last{_STD move(_Val)} {} + : _Last(_STD move(_Val)) {} template requires convertible_to constexpr move_sentinel(const move_sentinel<_Se2>& _Val) noexcept( is_nothrow_constructible_v<_Se, const _Se2&>) // strengthened - : _Last{_Val._Get_last()} {} + : _Last(_Val._Get_last()) {} template requires assignable_from<_Se&, const _Se2&> diff --git a/stl/inc/ranges b/stl/inc/ranges index 1a435dccc76..f99d906a71f 100644 --- a/stl/inc/ranges +++ b/stl/inc/ranges @@ -2393,12 +2393,10 @@ namespace ranges { #endif // _ITERATOR_DEBUG_LEVEL != 0 } - // clang-format off - constexpr _Iterator(_Iterator _It) - noexcept(is_nothrow_constructible_v, iterator_t<_Vw>>) // strengthened + constexpr _Iterator(_Iterator _It) noexcept( + is_nothrow_constructible_v, iterator_t<_Vw>>) // strengthened requires _Const && convertible_to, iterator_t<_Base>> - : _Current{_STD move(_It._Current)}, _Parent{_It._Parent} {} - // clang-format on + : _Current(_STD move(_It._Current)), _Parent(_It._Parent) {} _NODISCARD constexpr const iterator_t<_Base>& base() const& noexcept { return _Current; @@ -3707,7 +3705,7 @@ namespace ranges { 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} {} + : _Outer(_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 @@ -4033,7 +4031,7 @@ namespace ranges { _Variantish<_PatternIter, _InnerIter> _Inner_it{}; constexpr _Iterator(_Parent_t& _Parent_, iterator_t<_Base> _Outer_) - : _Parent{_STD addressof(_Parent_)}, _Outer_it{_STD move(_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)); @@ -4117,7 +4115,7 @@ namespace ranges { && convertible_to, _OuterIter> // && convertible_to>, _InnerIter> // && convertible_to, _PatternIter> // - : _Outer_it{_STD move(_It._Outer_it)}, _Parent{_It._Parent} { + : _Parent(_It._Parent), _Outer_it(_STD move(_It._Outer_it)) { switch (_It._Inner_it._Contains) { case _Variantish_state::_Holds_first: _Inner_it._Emplace_first(_STD move(_It._Inner_it._First)); @@ -4307,7 +4305,7 @@ namespace ranges { constexpr _Sentinel(_Sentinel _Se) noexcept( is_nothrow_constructible_v, sentinel_t<_Vw>>) // strengthened requires _Const && convertible_to, sentinel_t<_Base>> - : _Last{_STD move(_Se._Last)} {} + : _Last(_STD move(_Se._Last)) {} template requires sentinel_for, iterator_t<_Maybe_const<_OtherConst, _Vw>>> @@ -5488,13 +5486,17 @@ namespace ranges { #endif // _HAS_CXX23 template - concept _Has_tuple_element = // + concept _Has_tuple_element = +#if _HAS_CXX23 + _Tuple_like<_Tuple> && _Index < tuple_size_v<_Tuple>; +#else // ^^^ C++23 / C++20 vvv requires(_Tuple __t) { typename tuple_size<_Tuple>::type; requires _Index < tuple_size_v<_Tuple>; typename tuple_element_t<_Index, _Tuple>; { _STD get<_Index>(__t) } -> convertible_to&>; }; +#endif // C++20 template concept _Returnable_element = is_reference_v<_Tuple> || move_constructible>; @@ -5554,7 +5556,7 @@ namespace ranges { constexpr _Iterator(_Iterator _It) noexcept( is_nothrow_constructible_v, iterator_t<_Vw>>) // strengthened requires _Const && convertible_to, iterator_t<_Base>> - : _Current{_STD move(_It._Current)} {} + : _Current(_STD move(_It._Current)) {} _NODISCARD constexpr const iterator_t<_Base>& base() const& noexcept { return _Current; @@ -5917,6 +5919,338 @@ namespace ranges { } // namespace views #if _HAS_CXX23 + template + concept _Range_with_movable_references = input_range<_Rng> && move_constructible> + && move_constructible>; + + _EXPORT_STD template + requires _Range_with_movable_references<_Vw> + class enumerate_view : public view_interface> { + private: + /* [[no_unique_address]] */ _Vw _Range{}; + + template + class _Iterator { + private: + friend enumerate_view; + + using _Base_t = _Maybe_const<_Const, _Vw>; + using _Base_iterator = iterator_t<_Base_t>; + using _Reference_type = tuple, range_reference_t<_Base_t>>; + + /* [[no_unique_address]] */ _Base_iterator _Current{}; + range_difference_t<_Base_t> _Pos = 0; + + constexpr explicit _Iterator(_Base_iterator _Current_, range_difference_t<_Base_t> _Pos_) noexcept( + is_nothrow_move_constructible_v<_Base_iterator>) // strengthened + : _Current(_STD move(_Current_)), _Pos(_Pos_) {} + + public: + using iterator_category = input_iterator_tag; + using iterator_concept = conditional_t, random_access_iterator_tag, + conditional_t, bidirectional_iterator_tag, + conditional_t, forward_iterator_tag, input_iterator_tag>>>; + using difference_type = range_difference_t<_Base_t>; + using value_type = tuple>; + + // clang-format off + _Iterator() requires default_initializable<_Base_iterator> = default; + // clang-format on + + constexpr _Iterator(_Iterator _Other) noexcept( + is_nothrow_constructible_v<_Base_iterator, iterator_t<_Vw>>) // strengthened + requires _Const && convertible_to, _Base_iterator> + : _Current(_STD move(_Other._Current)), _Pos(_Other._Pos) {} + + _NODISCARD constexpr const _Base_iterator& base() const& noexcept { + return _Current; + } + + _NODISCARD constexpr _Base_iterator base() && noexcept( + is_nothrow_move_constructible_v<_Base_iterator>) /* strengthened */ { + return _STD move(_Current); + } + + _NODISCARD constexpr difference_type index() const noexcept { + return _Pos; + } + + _NODISCARD constexpr auto operator*() const noexcept( + noexcept(*_Current) && is_nothrow_copy_constructible_v>) /* strengthened */ { + return _Reference_type{_Pos, *_Current}; + } + + constexpr _Iterator& operator++() noexcept(noexcept(++_Current)) /* strengthened */ { + ++_Current; + ++_Pos; + return *this; + } + + constexpr void operator++(int) noexcept(noexcept(++_Current)) /* strengthened */ { + ++*this; + } + + constexpr _Iterator operator++(int) noexcept( + noexcept(++*this) && is_nothrow_copy_constructible_v<_Iterator>) // strengthened + requires forward_range<_Base_t> + { + auto _Tmp = *this; + ++*this; + return _Tmp; + } + + constexpr _Iterator& operator--() noexcept(noexcept(--_Current)) // strengthened + requires bidirectional_range<_Base_t> + { + --_Current; + --_Pos; + return *this; + } + + constexpr _Iterator operator--(int) noexcept( + noexcept(--*this) && is_nothrow_copy_constructible_v<_Iterator>) // strengthened + requires bidirectional_range<_Base_t> + { + auto _Tmp = *this; + --*this; + return _Tmp; + } + + constexpr _Iterator& operator+=(const difference_type _Off) noexcept( + noexcept(_Current += _Off)) // strengthened + requires random_access_range<_Base_t> + { + _Current += _Off; + _Pos += _Off; + return *this; + } + + constexpr _Iterator& operator-=(const difference_type _Off) noexcept( + noexcept(_Current -= _Off)) // strengthened + requires random_access_range<_Base_t> + { + _Current -= _Off; + _Pos -= _Off; + return *this; + } + + _NODISCARD constexpr auto operator[](const difference_type _Off) const noexcept( + noexcept(_Current[_Off]) && is_nothrow_copy_constructible_v>) // strengthened + requires random_access_range<_Base_t> + { + return _Reference_type{static_cast(_Pos + _Off), _Current[_Off]}; + } + + _NODISCARD_FRIEND constexpr bool operator==(const _Iterator& _Left, const _Iterator& _Right) noexcept { + return _Left._Pos == _Right._Pos; + } + + _NODISCARD_FRIEND constexpr strong_ordering operator<=>( + const _Iterator& _Left, const _Iterator& _Right) noexcept { + return _Left._Pos <=> _Right._Pos; + } + + _NODISCARD_FRIEND constexpr _Iterator operator+(const _Iterator& _It, const difference_type _Off) noexcept( + is_nothrow_copy_constructible_v<_Iterator>&& noexcept( + _STD declval<_Iterator&>() += _Off)) // strengthened + requires random_access_range<_Base_t> + { + auto _Tmp = _It; + _Tmp += _Off; + return _Tmp; + } + + _NODISCARD_FRIEND constexpr _Iterator operator+(const difference_type _Off, const _Iterator& _It) noexcept( + noexcept(_It + _Off)) // strengthened + requires random_access_range<_Base_t> + { + return _It + _Off; + } + + _NODISCARD_FRIEND constexpr _Iterator operator-(const _Iterator& _It, const difference_type _Off) noexcept( + is_nothrow_copy_constructible_v<_Iterator>&& noexcept( + _STD declval<_Iterator&>() -= _Off)) // strengthened + requires random_access_range<_Base_t> + { + auto _Tmp = _It; + _Tmp -= _Off; + return _Tmp; + } + + _NODISCARD_FRIEND constexpr difference_type operator-( + const _Iterator& _Left, const _Iterator& _Right) noexcept /* strengthened */ { + return _Left._Pos - _Right._Pos; + } + + _NODISCARD_FRIEND constexpr auto iter_move(const _Iterator& _It) noexcept( + noexcept(_RANGES iter_move(_It._Current)) + && is_nothrow_move_constructible_v>) { + return tuple>{ + _It._Pos, _RANGES iter_move(_It._Current)}; + } + }; + + template + class _Sentinel { + private: + friend enumerate_view; + + using _Base_t = _Maybe_const<_Const, _Vw>; + using _Base_sentinel = sentinel_t<_Base_t>; + + /* [[no_unique_address]] */ _Base_sentinel _End{}; + + constexpr explicit _Sentinel(_Base_sentinel _End_) noexcept( + is_nothrow_move_constructible_v<_Base_sentinel>) // strengthened + : _End(_STD move(_End_)) {} + + template + requires sentinel_for<_Base_sentinel, iterator_t<_Maybe_const<_OtherConst, _Vw>>> + _NODISCARD constexpr bool _Equal(const _Iterator<_OtherConst>& _It) const + noexcept(noexcept(_Fake_copy_init(_It._Current == _End))) { + return _It._Current == _End; + } + + template + requires sized_sentinel_for<_Base_sentinel, iterator_t<_Maybe_const<_OtherConst, _Vw>>> + _NODISCARD constexpr range_difference_t<_Maybe_const<_OtherConst, _Vw>> _Distance_from( + const _Iterator<_OtherConst>& _It) const noexcept(noexcept(_End - _It._Current)) { + return _End - _It._Current; + } + + public: + _Sentinel() = default; + + constexpr _Sentinel(_Sentinel _Other) noexcept( + is_nothrow_constructible_v<_Base_sentinel, sentinel_t<_Vw>>) // strengthened + requires _Const && convertible_to, _Base_sentinel> + : _End(_STD move(_Other._End)) {} + + _NODISCARD constexpr _Base_sentinel base() const + noexcept(is_nothrow_copy_constructible_v<_Base_sentinel>) /* strengthened */ { + return _End; + } + + template + requires sentinel_for<_Base_sentinel, iterator_t<_Maybe_const<_OtherConst, _Vw>>> + _NODISCARD_FRIEND constexpr bool operator==(const _Iterator<_OtherConst>& _It, const _Sentinel& _Se) // + noexcept(noexcept(_Se._Equal(_It))) /* strengthened */ { + return _Se._Equal(_It); + } + + template + requires sized_sentinel_for<_Base_sentinel, iterator_t<_Maybe_const<_OtherConst, _Vw>>> + _NODISCARD_FRIEND constexpr range_difference_t<_Maybe_const<_OtherConst, _Vw>> operator-( + const _Iterator<_OtherConst>& _It, const _Sentinel& _Se) // + noexcept(noexcept(_Se._Distance_from(_It))) /* strengthened */ { + return -_Se._Distance_from(_It); + } + + template + requires sized_sentinel_for<_Base_sentinel, iterator_t<_Maybe_const<_OtherConst, _Vw>>> + _NODISCARD_FRIEND constexpr range_difference_t<_Maybe_const<_OtherConst, _Vw>> operator-( + const _Sentinel& _Se, const _Iterator<_OtherConst>& _It) // + noexcept(noexcept(_Se._Distance_from(_It))) /* strengthened */ { + return _Se._Distance_from(_It); + } + }; + + template + static constexpr bool _Is_end_nothrow_v = is_nothrow_move_constructible_v> // + && noexcept(_RANGES end(_STD declval<_Rng&>())); + + template + requires common_range<_Rng> && sized_range<_Rng> + static constexpr bool _Is_end_nothrow_v<_Rng> = is_nothrow_move_constructible_v> // + && noexcept(_RANGES end(_STD declval<_Rng&>())) // + && noexcept(_RANGES distance(_STD declval<_Rng&>())); + + public: + // clang-format off + constexpr enumerate_view() requires default_initializable<_Vw> = default; + // clang-format on + + constexpr explicit enumerate_view(_Vw _Range_) noexcept(is_nothrow_move_constructible_v<_Vw>) // strengthened + : _Range(_STD move(_Range_)) {} + + _NODISCARD constexpr auto begin() noexcept( + noexcept(_RANGES begin(_Range)) && is_nothrow_move_constructible_v>) // strengthened + requires (!_Simple_view<_Vw>) + { + return _Iterator{_RANGES begin(_Range), 0}; + } + + _NODISCARD constexpr auto begin() const noexcept( + noexcept(_RANGES begin(_Range)) && is_nothrow_move_constructible_v>) // strengthened + requires _Range_with_movable_references + { + return _Iterator{_RANGES begin(_Range), 0}; + } + + _NODISCARD constexpr auto end() noexcept(_Is_end_nothrow_v<_Vw>) // strengthened + requires (!_Simple_view<_Vw>) + { + if constexpr (common_range<_Vw> && sized_range<_Vw>) { + return _Iterator{_RANGES end(_Range), _RANGES distance(_Range)}; + } else { + return _Sentinel{_RANGES end(_Range)}; + } + } + + _NODISCARD constexpr auto end() const noexcept(_Is_end_nothrow_v) // strengthened + requires _Range_with_movable_references + { + if constexpr (common_range && sized_range) { + return _Iterator{_RANGES end(_Range), _RANGES distance(_Range)}; + } else { + return _Sentinel{_RANGES end(_Range)}; + } + } + + _NODISCARD constexpr auto size() noexcept(noexcept(_RANGES size(_Range))) // strengthened + requires sized_range<_Vw> + { + return _RANGES size(_Range); + } + + _NODISCARD constexpr auto size() const noexcept(noexcept(_RANGES size(_Range))) // strengthened + requires sized_range + { + return _RANGES size(_Range); + } + + _NODISCARD constexpr _Vw base() const& noexcept(is_nothrow_copy_constructible_v<_Vw>) // strengthened + requires copy_constructible<_Vw> + { + return _Range; + } + + _NODISCARD constexpr _Vw base() && noexcept(is_nothrow_move_constructible_v<_Vw>) /* strengthened */ { + return _STD move(_Range); + } + }; + + template + enumerate_view(_Rng&&) -> enumerate_view>; + + template + inline constexpr bool enable_borrowed_range> = enable_borrowed_range<_Rng>; + + namespace views { + class _Enumerate_fn : public _Pipe::_Base<_Enumerate_fn> { + public: + template + _NODISCARD constexpr auto operator()(_Rng&& _Range) const + noexcept(noexcept(enumerate_view>{_STD forward<_Rng>(_Range)})) + requires requires { enumerate_view>{_STD forward<_Rng>(_Range)}; } + { + return enumerate_view>{_STD forward<_Rng>(_Range)}; + } + }; + + _EXPORT_STD inline constexpr _Enumerate_fn enumerate; + } // namespace views + template _NODISCARD constexpr _Size _Div_ceil(const _Size _Num, const _Size _Denom) noexcept { _Size _Result = _Num / _Denom; @@ -6571,8 +6905,8 @@ namespace ranges { _Iterator() = default; - constexpr _Iterator(_Iterator _Other) noexcept(is_nothrow_constructible_v<_Base_iterator, - typename _Iterator::_Base_iterator>) /* strengthened */ + constexpr _Iterator(_Iterator _Other) noexcept( + is_nothrow_constructible_v<_Base_iterator, iterator_t<_Vw>>) // strengthened requires _Const && convertible_to, _Base_iterator> : _Current(_STD move(_Other._Current)), _Count(_Other._Count) {} @@ -8388,7 +8722,8 @@ namespace ranges { template concept _Converts_and_common_constructible = _Ref_converts<_Rng, _Container> && common_range<_Rng> // - && _Cpp17_input_iterator> // + && requires { typename iterator_traits>::iterator_category; } + && derived_from>::iterator_category, input_iterator_tag> && constructible_from<_Container, iterator_t<_Rng>, iterator_t<_Rng>, _Types...>; template diff --git a/stl/inc/regex b/stl/inc/regex index 2b0e47f68e0..dc5c484cf54 100644 --- a/stl/inc/regex +++ b/stl/inc/regex @@ -627,6 +627,11 @@ public: return _Compare(_Ptr, _Traits::length(_Ptr)); } + void swap(sub_match& _Other) noexcept(_Is_nothrow_swappable<_BidIt>::value) { + this->_Mybase::swap(_Other); + _STD swap(matched, _Other.matched); + } + int _Compare(const value_type* const _Ptr, const _Size_type _Count) const { // compare *this to array [_Ptr, _Ptr + _Count) const _Mybase _Range(_Effective_range()); diff --git a/stl/inc/scoped_allocator b/stl/inc/scoped_allocator index fad675a9781..34aa4cbb870 100644 --- a/stl/inc/scoped_allocator +++ b/stl/inc/scoped_allocator @@ -41,7 +41,7 @@ decltype(auto) _Scoped_outermost(_Alloc& _Al) { // gets the outermost allocator } template -using _Scoped_outermost_t = remove_reference_t()))>; +using _Scoped_outermost_t = remove_reference_t()))>; template using _Scoped_outermost_traits = allocator_traits<_Scoped_outermost_t<_Alloc>>; @@ -230,17 +230,23 @@ public: _STD apply( [_Ptr, this](auto&&... _New_args) { _Scoped_outermost_traits::construct( - _Scoped_outermost(*this), _Ptr, _STD forward(_New_args)...); + _STD _Scoped_outermost(*this), _Ptr, _STD forward(_New_args)...); }, _STD uses_allocator_construction_args<_Ty>(inner_allocator(), _STD forward<_Types>(_Args)...)); #else // ^^^ _HAS_CXX20 / !_HAS_CXX20 vvv - _Uses_allocator_construct(_Ptr, _Scoped_outermost(*this), inner_allocator(), _STD forward<_Types>(_Args)...); + if constexpr (_Is_cv_pair<_Ty>) { + _STD _Uses_alloc_construct_pair( + _Ptr, _STD _Scoped_outermost(*this), inner_allocator(), _STD forward<_Types>(_Args)...); + } else { + _STD _Uses_alloc_construct_non_pair( + _Ptr, _STD _Scoped_outermost(*this), inner_allocator(), _STD forward<_Types>(_Args)...); + } #endif // ^^^ !_HAS_CXX20 ^^^ } template void destroy(_Ty* _Ptr) { // destroy object at _Ptr - _Scoped_outermost_traits::destroy(_Scoped_outermost(*this), _Ptr); + _Scoped_outermost_traits::destroy(_STD _Scoped_outermost(*this), _Ptr); } // select_on_container_copy_construction comes from _Scoped_base diff --git a/stl/inc/tuple b/stl/inc/tuple index 51bcd03fa9a..de4ab093443 100644 --- a/stl/inc/tuple +++ b/stl/inc/tuple @@ -179,6 +179,43 @@ struct _Alloc_unpack_tuple_t { explicit _Alloc_unpack_tuple_t() = default; }; // tag type to disambiguate construction (from an allocator and unpacking a tuple/pair) +#if _HAS_CXX23 && defined(__cpp_lib_concepts) +template >> +inline constexpr bool _Can_construct_values_from_tuple_like_v = false; + +template +inline constexpr bool _Can_construct_values_from_tuple_like_v, _Other, index_sequence<_Indices...>> = + conjunction_v(_STD declval<_Other>()))>...>; + +#ifdef __clang__ // TRANSITION, LLVM-59827 +template +concept _Can_construct_from_tuple_like = _Tuple_like<_TupleLike> && _Different_from<_TupleLike, _Tuple> + && (!_Is_subrange_v>) + && (tuple_size_v<_Tuple> == tuple_size_v>) + && _Can_construct_values_from_tuple_like_v<_Tuple, _TupleLike> + && (tuple_size_v<_Tuple> != 1 + || (!is_convertible_v<_TupleLike, tuple_element_t<0, _Tuple>> + && !is_constructible_v, _TupleLike>) ); +#endif // __clang__ + +template >> +struct _Three_way_comparison_result_with_tuple_like {}; + +template + requires +#ifndef __clang__ // TRANSITION, DevCom-10265237 + (sizeof...(_TTypes) == sizeof...(_Indices)) && +#endif // __clang__ + (requires { typename _Synth_three_way_result<_TTypes, tuple_element_t<_Indices, _UTuple>>; } && ...) +struct _Three_way_comparison_result_with_tuple_like, _UTuple, index_sequence<_Indices...>> { + using type = common_comparison_category_t<_Synth_three_way_result<_TTypes, tuple_element_t<_Indices, _UTuple>>...>; +}; + +template +using _Three_way_comparison_result_with_tuple_like_t = + typename _Three_way_comparison_result_with_tuple_like<_TTuple, _UTuple>::type; +#endif // _HAS_CXX23 && defined(__cpp_lib_concepts) + template <> class tuple<> { // empty tuple public: @@ -186,12 +223,24 @@ public: constexpr tuple(const tuple&) noexcept /* strengthened */ {} // TRANSITION, ABI: should be defaulted +#if _HAS_CXX23 && defined(__cpp_lib_concepts) + template <_Tuple_like _Other> + requires _Different_from<_Other, tuple> && (tuple_size_v> == 0) + constexpr tuple(_Other&&) noexcept /* strengthened */ {} +#endif // _HAS_CXX23 && defined(__cpp_lib_concepts) + template _CONSTEXPR20 tuple(allocator_arg_t, const _Alloc&) noexcept /* strengthened */ {} template _CONSTEXPR20 tuple(allocator_arg_t, const _Alloc&, const tuple&) noexcept /* strengthened */ {} +#if _HAS_CXX23 && defined(__cpp_lib_concepts) + template + requires _Different_from<_Other, tuple> && (tuple_size_v> == 0) + constexpr tuple(allocator_arg_t, const _Alloc&, _Other&&) noexcept /* strengthened */ {} +#endif // _HAS_CXX23 && defined(__cpp_lib_concepts) + template , int> = 0> constexpr tuple(_Tag) noexcept /* strengthened */ {} @@ -203,6 +252,20 @@ public: constexpr const tuple& operator=(const tuple&) const noexcept /* strengthened */ { return *this; } + +#ifdef __cpp_lib_concepts + template <_Tuple_like _Other> + requires _Different_from<_Other, tuple> && (tuple_size_v> == 0) + constexpr tuple& operator=(_Other&&) noexcept /* strengthened */ { + return *this; + } + + template <_Tuple_like _Other> + requires _Different_from<_Other, tuple> && (tuple_size_v> == 0) + constexpr const tuple& operator=(_Other&&) const noexcept /* strengthened */ { + return *this; + } +#endif // __cpp_lib_concepts #endif // _HAS_CXX23 _CONSTEXPR20 void swap(tuple&) noexcept {} @@ -223,6 +286,26 @@ public: return false; } #endif // ^^^ !defined(__cpp_lib_concepts) ^^^ + +#if _HAS_CXX23 && defined(__cpp_lib_concepts) + template <_Tuple_like _Other> +#ifndef __clang__ // TRANSITION, DevCom-10265322 + requires _Different_from<_Other, tuple> +#endif // __clang__ + _NODISCARD_FRIEND constexpr bool operator==(const tuple&, const _Other&) noexcept /* strengthened */ { + static_assert(tuple_size_v<_Other> == 0, "Cannot compare tuples of different sizes (N4928 [tuple.rel]/2)."); + return true; + } + + template <_Tuple_like _Other> + requires (tuple_size_v> == 0) +#ifndef __clang__ // TRANSITION, DevCom-10265322 + && _Different_from<_Other, tuple> +#endif // __clang__ + _NODISCARD_FRIEND constexpr strong_ordering operator<=>(const tuple&, const _Other&) noexcept /* strengthened */ { + return strong_ordering::equal; + } +#endif // _HAS_CXX23 && defined(__cpp_lib_concepts) }; template @@ -343,6 +426,29 @@ public: tuple(const pair<_First, _Second>&& _Right) noexcept( _Tuple_nothrow_constructible_v) // strengthened : tuple(_Unpack_tuple_t{}, _STD move(_Right)) {} + +#ifdef __cpp_lib_concepts + template > + static constexpr bool _Is_tuple_like_constructor_explicit_v = false; + + template <_Tuple_like _Other, size_t... _Indices> + static constexpr bool _Is_tuple_like_constructor_explicit_v<_Other, index_sequence<_Indices...>> = + negation_v(_STD declval<_Other>())), _This>, + is_convertible(_STD declval<_Other>())), _Rest>...>>; + +#ifdef __clang__ // TRANSITION, LLVM-59827 + template , int> = 0> +#else // ^^^ workaround / no workaround vvv + template <_Tuple_like _Other> + requires _Different_from<_Other, tuple> && (!_Is_subrange_v>) + && (1 + sizeof...(_Rest) == tuple_size_v>) + && _Can_construct_values_from_tuple_like_v + && (sizeof...(_Rest) != 0 || (!is_convertible_v<_Other, _This> && !is_constructible_v<_This, _Other>) ) +#endif // __clang__ + constexpr explicit(_Is_tuple_like_constructor_explicit_v<_Other>) tuple(_Other&& _Right) + : tuple(_Unpack_tuple_t{}, _STD forward<_Other>(_Right)) { + } +#endif // __cpp_lib_concepts #endif // _HAS_CXX23 template ) tuple(allocator_arg_t, const _Alloc& _Al, const pair<_First, _Second>&& _Right) : tuple(_Alloc_unpack_tuple_t{}, _Al, _STD move(_Right)) {} + +#ifdef __cpp_lib_concepts +#ifdef __clang__ // TRANSITION, LLVM-59827 + template , int> = 0> +#else // ^^^ workaround / no workaround vvv + template + requires _Different_from<_Other, tuple> && (!_Is_subrange_v>) + && (1 + sizeof...(_Rest) == tuple_size_v>) + && _Can_construct_values_from_tuple_like_v + && (sizeof...(_Rest) != 0 || (!is_convertible_v<_Other, _This> && !is_constructible_v<_This, _Other>) ) +#endif // __clang__ + constexpr explicit(_Is_tuple_like_constructor_explicit_v<_Other>) + tuple(allocator_arg_t, const _Alloc& _Al, _Other&& _Right) + : tuple(_Alloc_unpack_tuple_t{}, _Al, _STD forward<_Other>(_Right)) { + } +#endif // __cpp_lib_concepts #endif // _HAS_CXX23 tuple& operator=(const volatile tuple&) = delete; @@ -570,6 +692,49 @@ public: _Get_rest()._Myfirst._Val = _STD forward<_Second>(_Right.second); return *this; } + +#ifdef __cpp_lib_concepts + template > + static constexpr bool _Can_assign_values_from_tuple_like_v = false; + + template <_Tuple_like _Other, size_t... _Indices> + static constexpr bool _Can_assign_values_from_tuple_like_v> = + conjunction_v(_STD declval<_Other>()))>, + is_assignable<_Rest&, decltype(_STD get<_Indices + 1>(_STD declval<_Other>()))>...>; + + template <_Tuple_like _Other, size_t... _Indices> + static constexpr bool _Can_assign_values_from_tuple_like_v> = + conjunction_v(_STD declval<_Other>()))>, + is_assignable(_STD declval<_Other>()))>...>; + + template <_Tuple_like _Other, size_t... _Indices> + constexpr void _Assign_tuple_like(_Other&& _Right, index_sequence<_Indices...>) { + ((void) (_STD get<_Indices>(*this) = _STD get<_Indices>(_STD forward<_Other>(_Right))), ...); + } + + template <_Tuple_like _Other, size_t... _Indices> + constexpr void _Assign_tuple_like(_Other&& _Right, index_sequence<_Indices...>) const { + ((void) (_STD get<_Indices>(*this) = _STD get<_Indices>(_STD forward<_Other>(_Right))), ...); + } + + template <_Tuple_like _Other> + requires _Different_from<_Other, tuple> && (!_Is_subrange_v>) + && (1 + sizeof...(_Rest) == tuple_size_v>) + && _Can_assign_values_from_tuple_like_v + constexpr tuple& operator=(_Other&& _Right) { + _Assign_tuple_like(_STD forward<_Other>(_Right), make_index_sequence<1 + sizeof...(_Rest)>{}); + return *this; + } + + template <_Tuple_like _Other> + requires _Different_from<_Other, tuple> && (!_Is_subrange_v>) + && (1 + sizeof...(_Rest) == tuple_size_v>) + && _Can_assign_values_from_tuple_like_v + constexpr const tuple& operator=(_Other&& _Right) const { + _Assign_tuple_like(_STD forward<_Other>(_Right), make_index_sequence<1 + sizeof...(_Rest)>{}); + return *this; + } +#endif // __cpp_lib_concepts #endif // _HAS_CXX23 _CONSTEXPR20 void swap(tuple& _Right) noexcept( @@ -610,6 +775,56 @@ public: } return _Mybase::_Three_way_compare(_Right._Get_rest()); } + +#if _HAS_CXX23 +#if defined(__clang__) || defined(__EDG__) // TRANSITION, VSO-1753916 + template > + static constexpr bool _Can_equal_compare_with_tuple_like_v = false; + + template + static constexpr bool _Can_equal_compare_with_tuple_like_v<_Other, index_sequence<_Indices...>> = + (requires(const tuple& _Left, const _Other& _Right) { + { _STD get<_Indices>(_Left) == _STD get<_Indices>(_Right) } -> _Boolean_testable; + } && ...); +#endif // ^^^ no workaround ^^^ + + template + _NODISCARD constexpr bool _Equals_to_tuple_like(const _Other& _Right, index_sequence<_Indices...>) const { + return ((_STD get<_Indices>(*this) == _STD get<_Indices>(_Right)) && ...); + } + + template <_Tuple_like _Other> +#ifndef __clang__ // TRANSITION, DevCom-10265322 + requires _Different_from<_Other, tuple> +#endif // __clang__ + _NODISCARD_FRIEND constexpr bool operator==(const tuple& _Left, const _Other& _Right) { + static_assert(1 + sizeof...(_Rest) == tuple_size_v<_Other>, + "Cannot compare tuples of different sizes (N4928 [tuple.rel]/2)."); +#if defined(__clang__) || defined(__EDG__) // TRANSITION, VSO-1753916 + static_assert(_Can_equal_compare_with_tuple_like_v<_Other>, + "For all i, where 0 <= i < sizeof...(TTypes), get(t) == get(u) must be a valid expression (N4928 " + "[tuple.rel]/2)."); +#endif // ^^^ no workaround ^^^ + return _Left._Equals_to_tuple_like(_Right, make_index_sequence<1 + sizeof...(_Rest)>{}); + } + + template + _NODISCARD constexpr auto _Three_way_compare_with_tuple_like( + const _Other& _Right, index_sequence<_Indices...>) const { + _Three_way_comparison_result_with_tuple_like_t _Result = strong_ordering::equal; + (void) (((_Result = _Synth_three_way{}(_STD get<_Indices>(*this), _STD get<_Indices>(_Right))) == 0) && ...); + return _Result; + } + + template <_Tuple_like _Other> +#ifndef __clang__ // TRANSITION, DevCom-10265322 + requires _Different_from<_Other, tuple> +#endif // __clang__ + _NODISCARD_FRIEND constexpr auto operator<=>(const tuple& _Left, const _Other& _Right) + -> _Three_way_comparison_result_with_tuple_like_t { + return _Left._Three_way_compare_with_tuple_like(_Right, make_index_sequence<1 + sizeof...(_Rest)>{}); + } +#endif // _HAS_CXX23 #else // ^^^ defined(__cpp_lib_concepts) / !defined(__cpp_lib_concepts) vvv template _NODISCARD constexpr bool _Less(const tuple<_Other...>& _Right) const { @@ -667,7 +882,8 @@ tuple(allocator_arg_t, _Alloc, tuple<_Types...>) -> tuple<_Types...>; _EXPORT_STD template _NODISCARD constexpr bool operator==(const tuple<_Types1...>& _Left, const tuple<_Types2...>& _Right) { - static_assert(sizeof...(_Types1) == sizeof...(_Types2), "cannot compare tuples of different sizes"); + static_assert( + sizeof...(_Types1) == sizeof...(_Types2), "Cannot compare tuples of different sizes (N4928 [tuple.rel]/2)."); return _Left._Equals(_Right); } @@ -675,7 +891,6 @@ _NODISCARD constexpr bool operator==(const tuple<_Types1...>& _Left, const tuple _EXPORT_STD template _NODISCARD constexpr common_comparison_category_t<_Synth_three_way_result<_Types1, _Types2>...> operator<=>( const tuple<_Types1...>& _Left, const tuple<_Types2...>& _Right) { - static_assert(sizeof...(_Types1) == sizeof...(_Types2), "cannot compare tuples of different sizes"); return _Left._Three_way_compare(_Right); } #else // ^^^ defined(__cpp_lib_concepts) / !defined(__cpp_lib_concepts) vvv @@ -837,7 +1052,11 @@ struct _Tuple_cat2<_Ty, index_sequence<_Kx...>, index_sequence<_Ix...>, _Ix_next index_sequence<_Ix..., (_Ix_next + 0 * _Kx_next)...>, // repeat _Ix_next, ignoring the elements of _Kx_next _Ix_next + 1, _Rest...> {}; +#if _HAS_CXX23 && defined(__cpp_lib_concepts) +template <_Tuple_like... _Tuples> +#else // ^^^ C++23 / C++20 vvv template +#endif // C++20 using _Tuple_cat1 = _Tuple_cat2, index_sequence<>, index_sequence<>, 0, make_index_sequence>>...>; @@ -846,7 +1065,11 @@ constexpr _Ret _Tuple_cat(index_sequence<_Kx...>, index_sequence<_Ix...>, _Ty _A return _Ret{_STD get<_Kx>(_STD get<_Ix>(_STD move(_Arg)))...}; } +#if _HAS_CXX23 && defined(__cpp_lib_concepts) +_EXPORT_STD template <_Tuple_like... _Tuples> +#else // ^^^ C++23 / C++20 vvv _EXPORT_STD template +#endif // C++20 _NODISCARD constexpr typename _Tuple_cat1<_Tuples...>::_Ret tuple_cat(_Tuples&&... _Tpls) { // concatenate tuples using _Cat1 = _Tuple_cat1<_Tuples...>; using _Ret = typename _Cat1::_Ret; @@ -856,13 +1079,21 @@ _NODISCARD constexpr typename _Tuple_cat1<_Tuples...>::_Ret tuple_cat(_Tuples&&. } #if _HAS_CXX17 +#if _HAS_CXX23 && defined(__cpp_lib_concepts) +template +#else // ^^^ C++23 / C++20 vvv template +#endif // C++20 constexpr decltype(auto) _Apply_impl(_Callable&& _Obj, _Tuple&& _Tpl, index_sequence<_Indices...>) noexcept( noexcept(_STD invoke(_STD forward<_Callable>(_Obj), _STD get<_Indices>(_STD forward<_Tuple>(_Tpl))...))) { return _STD invoke(_STD forward<_Callable>(_Obj), _STD get<_Indices>(_STD forward<_Tuple>(_Tpl))...); } +#if _HAS_CXX23 && defined(__cpp_lib_concepts) +_EXPORT_STD template +#else // ^^^ C++23 / C++20 vvv _EXPORT_STD template +#endif // C++20 constexpr decltype(auto) apply(_Callable&& _Obj, _Tuple&& _Tpl) noexcept( noexcept(_Apply_impl(_STD forward<_Callable>(_Obj), _STD forward<_Tuple>(_Tpl), make_index_sequence>>{}))) { @@ -870,7 +1101,11 @@ constexpr decltype(auto) apply(_Callable&& _Obj, _Tuple&& _Tpl) noexcept( make_index_sequence>>{}); } +#if _HAS_CXX23 && defined(__cpp_lib_concepts) +template +#else // ^^^ C++23 / C++20 vvv template +#endif // C++20 constexpr _Ty _Make_from_tuple_impl(_Tuple&& _Tpl, index_sequence<_Indices...>) noexcept( is_nothrow_constructible_v<_Ty, decltype(_STD get<_Indices>(_STD forward<_Tuple>(_Tpl)))...>) { // construct _Ty from the elements of _Tpl @@ -879,7 +1114,11 @@ constexpr _Ty _Make_from_tuple_impl(_Tuple&& _Tpl, index_sequence<_Indices...>) return _Ty(_STD get<_Indices>(_STD forward<_Tuple>(_Tpl))...); } +#if _HAS_CXX23 && defined(__cpp_lib_concepts) +_EXPORT_STD template +#else // ^^^ C++23 / C++20 vvv _EXPORT_STD template +#endif // C++20 _NODISCARD constexpr _Ty make_from_tuple(_Tuple&& _Tpl) noexcept(noexcept(_Make_from_tuple_impl<_Ty>( _STD forward<_Tuple>(_Tpl), make_index_sequence>>{}))) /* strengthened */ { // construct _Ty from the elements of _Tpl @@ -891,19 +1130,52 @@ _NODISCARD constexpr _Ty make_from_tuple(_Tuple&& _Tpl) noexcept(noexcept(_Make_ template struct uses_allocator, _Alloc> : true_type {}; // true_type if container allocator enabled -#ifdef __cpp_lib_concepts -template class _TQual, template class _UQual> - requires requires { typename tuple, _UQual<_UTypes>>...>; } -struct basic_common_reference, tuple<_UTypes...>, _TQual, _UQual> { - using type = tuple, _UQual<_UTypes>>...>; +#if _HAS_CXX23 && defined(__cpp_lib_concepts) +template <_Tuple_like _TTuple, _Tuple_like _UTuple, template class _TQual, template class _UQual, + class _Indices = make_index_sequence>> +struct _Tuple_like_common_reference; + +template class _TQual, template class _UQual, + size_t... _Indices> + requires requires { + typename tuple>, + _UQual>>...>; + } +struct _Tuple_like_common_reference<_TTuple, _UTuple, _TQual, _UQual, index_sequence<_Indices...>> { + using type = tuple< + common_reference_t<_TQual>, _UQual>>...>; }; -template - requires requires { typename tuple...>; } -struct common_type, tuple<_UTypes...>> { - using type = tuple...>; +template <_Tuple_like _TTuple, _Tuple_like _UTuple, template class _TQual, template class _UQual> + requires (_Is_specialization_v<_TTuple, tuple> || _Is_specialization_v<_UTuple, tuple>) + && is_same_v<_TTuple, decay_t<_TTuple>> && is_same_v<_UTuple, decay_t<_UTuple>> + && (tuple_size_v<_TTuple> == tuple_size_v<_UTuple>) + && requires { typename _Tuple_like_common_reference<_TTuple, _UTuple, _TQual, _UQual>::type; } +struct basic_common_reference<_TTuple, _UTuple, _TQual, _UQual> { + using type = typename _Tuple_like_common_reference<_TTuple, _UTuple, _TQual, _UQual>::type; }; -#endif // __cpp_lib_concepts + +template <_Tuple_like _TTuple, _Tuple_like _UTuple, class _Indices = make_index_sequence>> +struct _Tuple_like_common_type; + +template + requires requires { + typename tuple< + common_type_t, tuple_element_t<_Indices, _UTuple>>...>; + } +struct _Tuple_like_common_type<_TTuple, _UTuple, index_sequence<_Indices...>> { + using type = tuple, tuple_element_t<_Indices, _UTuple>>...>; +}; + +template <_Tuple_like _TTuple, _Tuple_like _UTuple> + requires (_Is_specialization_v<_TTuple, tuple> || _Is_specialization_v<_UTuple, tuple>) + && is_same_v<_TTuple, decay_t<_TTuple>> && is_same_v<_UTuple, decay_t<_UTuple>> + && (tuple_size_v<_TTuple> == tuple_size_v<_UTuple>) + && requires { typename _Tuple_like_common_type<_TTuple, _UTuple>::type; } +struct common_type<_TTuple, _UTuple> { + using type = typename _Tuple_like_common_type<_TTuple, _UTuple>::type; +}; +#endif // _HAS_CXX23 && defined(__cpp_lib_concepts) #if _HAS_TR1_NAMESPACE namespace _DEPRECATE_TR1_NAMESPACE tr1 { diff --git a/stl/inc/type_traits b/stl/inc/type_traits index 103cb1fa5c9..463db6fd760 100644 --- a/stl/inc/type_traits +++ b/stl/inc/type_traits @@ -1554,7 +1554,8 @@ struct _Invoker1; template struct _Invoker1<_Callable, _Ty1, _Removed_cvref, true, false> - : conditional_t::_Class_type, remove_reference_t<_Ty1>>, + : conditional_t::_Class_type, _Remove_cvref_t<_Ty1>> + || is_base_of_v::_Class_type, _Remove_cvref_t<_Ty1>>, _Invoker_pmf_object, conditional_t<_Is_specialization_v<_Remove_cvref_t<_Ty1>, reference_wrapper>, _Invoker_pmf_refwrap, _Invoker_pmf_pointer>> {}; // pointer to member function @@ -1562,7 +1563,8 @@ struct _Invoker1<_Callable, _Ty1, _Removed_cvref, true, false> template struct _Invoker1<_Callable, _Ty1, _Removed_cvref, false, true> : conditional_t< - is_base_of_v::_Class_type, remove_reference_t<_Ty1>>, + is_same_v::_Class_type, _Remove_cvref_t<_Ty1>> + || is_base_of_v::_Class_type, _Remove_cvref_t<_Ty1>>, _Invoker_pmd_object, conditional_t<_Is_specialization_v<_Remove_cvref_t<_Ty1>, reference_wrapper>, _Invoker_pmd_refwrap, _Invoker_pmd_pointer>> {}; // pointer to member data diff --git a/stl/inc/utility b/stl/inc/utility index 35834b57111..1ad3d703bcf 100644 --- a/stl/inc/utility +++ b/stl/inc/utility @@ -524,7 +524,7 @@ _NODISCARD constexpr bool operator>=(const pair<_Ty1, _Ty2>& _Left, const pair<_ } #endif // ^^^ !defined(__cpp_lib_concepts) ^^^ -#ifdef __cpp_lib_concepts +#if _HAS_CXX23 && defined(__cpp_lib_concepts) template class _TQual, template class _UQual> requires requires { @@ -540,7 +540,7 @@ template struct common_type, pair<_Uty1, _Uty2>> { using type = pair, common_type_t<_Ty2, _Uty2>>; }; -#endif // __cpp_lib_concepts +#endif // _HAS_CXX23 && defined(__cpp_lib_concepts) template struct _Unrefwrap_helper { // leave unchanged if not a reference_wrapper diff --git a/stl/inc/xmemory b/stl/inc/xmemory index 8a0bffa8a5c..4ab17c0a8e2 100644 --- a/stl/inc/xmemory +++ b/stl/inc/xmemory @@ -2241,7 +2241,10 @@ template _INLINE_VAR constexpr bool _Is_deducible_as_pair = false; template -_INLINE_VAR constexpr bool _Is_deducible_as_pair<_Ty, decltype(_Deduce_as_pair(_STD declval<_Ty>()))> = true; +_INLINE_VAR constexpr bool _Is_deducible_as_pair<_Ty, decltype(_STD _Deduce_as_pair(_STD declval<_Ty>()))> = true; + +template +_INLINE_VAR constexpr bool _Is_cv_pair = _Is_specialization_v, pair>; template const _Ty& _Normally_bind(_Identity_t); // not defined @@ -2250,7 +2253,7 @@ template _Ty&& _Normally_bind(_Identity_t<_Ty&&>); // not defined template -using _Normally_bound_ref = decltype(_Normally_bind<_Ty>(_STD declval<_Uty>())); +using _Normally_bound_ref = decltype(_STD _Normally_bind<_Ty>(_STD declval<_Uty>())); template _INLINE_VAR constexpr bool _Is_normally_bindable = false; @@ -2259,11 +2262,11 @@ template _INLINE_VAR constexpr bool _Is_normally_bindable<_Ty, _Uty, void_t<_Normally_bound_ref<_Ty, _Uty>>> = true; #if _HAS_CXX20 -_EXPORT_STD template , int> = 0> +_EXPORT_STD template , int> = 0> _NODISCARD constexpr auto uses_allocator_construction_args(const _Alloc& _Al, _Types&&... _Args) noexcept { - if constexpr (!uses_allocator_v<_Ty, _Alloc>) { + if constexpr (!uses_allocator_v, _Alloc>) { static_assert(is_constructible_v<_Ty, _Types...>, - "If uses_allocator_v does not hold, T must be constructible from Types..."); + "If uses_allocator_v, Alloc> does not hold, T must be constructible from Types..."); (void) _Al; return _STD forward_as_tuple(_STD forward<_Types>(_Args)...); } else if constexpr (is_constructible_v<_Ty, allocator_arg_t, const _Alloc&, _Types...>) { @@ -2274,44 +2277,38 @@ _NODISCARD constexpr auto uses_allocator_construction_args(const _Alloc& _Al, _T } else { static_assert(_Always_false<_Ty>, "T must be constructible from either (allocator_arg_t, const Alloc&, Types...) " - "or (Types..., const Alloc&) if uses_allocator_v is true"); + "or (Types..., const Alloc&) if uses_allocator_v, Alloc> is true"); } } -_EXPORT_STD template , int> = 0> +_EXPORT_STD template , int> = 0> _NODISCARD constexpr auto uses_allocator_construction_args(const _Alloc& _Al) noexcept; -_EXPORT_STD template , int> = 0> +_EXPORT_STD template , int> = 0> _NODISCARD constexpr auto uses_allocator_construction_args(const _Alloc& _Al, _Uty1&& _Val1, _Uty2&& _Val2) noexcept; #if _HAS_CXX23 -_EXPORT_STD template , int> = 0> +_EXPORT_STD template , int> = 0> _NODISCARD constexpr auto uses_allocator_construction_args(const _Alloc& _Al, pair<_Uty1, _Uty2>& _Pair) noexcept; #endif // _HAS_CXX23 -_EXPORT_STD template , int> = 0> +_EXPORT_STD template , int> = 0> _NODISCARD constexpr auto uses_allocator_construction_args(const _Alloc& _Al, const pair<_Uty1, _Uty2>& _Pair) noexcept; -_EXPORT_STD template , int> = 0> +_EXPORT_STD template , int> = 0> _NODISCARD constexpr auto uses_allocator_construction_args(const _Alloc& _Al, pair<_Uty1, _Uty2>&& _Pair) noexcept; #if _HAS_CXX23 -_EXPORT_STD template , int> = 0> +_EXPORT_STD template , int> = 0> _NODISCARD constexpr auto uses_allocator_construction_args( const _Alloc& _Al, const pair<_Uty1, _Uty2>&& _Pair) noexcept; #endif // _HAS_CXX23 _EXPORT_STD template && !_Is_deducible_as_pair<_Uty&>, int> = 0> + enable_if_t<_Is_cv_pair<_Ty> && !_Is_deducible_as_pair<_Uty&>, int> = 0> _NODISCARD constexpr auto uses_allocator_construction_args(const _Alloc& _Al, _Uty&& _Ux) noexcept; -_EXPORT_STD template , int> = 0> +_EXPORT_STD template , int> = 0> _NODISCARD constexpr auto uses_allocator_construction_args( const _Alloc& _Al, piecewise_construct_t, _Tuple1&& _Tup1, _Tuple2&& _Tup2) noexcept { return _STD make_tuple(piecewise_construct, @@ -2329,7 +2326,7 @@ _NODISCARD constexpr auto uses_allocator_construction_args( _STD forward<_Tuple2>(_Tup2))); } -_EXPORT_STD template , int>> +_EXPORT_STD template , int>> _NODISCARD constexpr auto uses_allocator_construction_args(const _Alloc& _Al) noexcept { // equivalent to // return _STD uses_allocator_construction_args<_Ty>(_Al, piecewise_construct, tuple<>{}, tuple<>{}); @@ -2337,8 +2334,7 @@ _NODISCARD constexpr auto uses_allocator_construction_args(const _Alloc& _Al) no _STD uses_allocator_construction_args(_Al)); } -_EXPORT_STD template , int>> +_EXPORT_STD template , int>> _NODISCARD constexpr auto uses_allocator_construction_args(const _Alloc& _Al, _Uty1&& _Val1, _Uty2&& _Val2) noexcept { // equivalent to // return _STD uses_allocator_construction_args<_Ty>(_Al, piecewise_construct, @@ -2349,8 +2345,7 @@ _NODISCARD constexpr auto uses_allocator_construction_args(const _Alloc& _Al, _U } #if _HAS_CXX23 -_EXPORT_STD template , int>> +_EXPORT_STD template , int>> _NODISCARD constexpr auto uses_allocator_construction_args(const _Alloc& _Al, pair<_Uty1, _Uty2>& _Pair) noexcept { // equivalent to // return _STD uses_allocator_construction_args<_Ty>(_Al, piecewise_construct, @@ -2361,8 +2356,7 @@ _NODISCARD constexpr auto uses_allocator_construction_args(const _Alloc& _Al, pa } #endif // _HAS_CXX23 -_EXPORT_STD template , int>> +_EXPORT_STD template , int>> _NODISCARD constexpr auto uses_allocator_construction_args( const _Alloc& _Al, const pair<_Uty1, _Uty2>& _Pair) noexcept { // equivalent to @@ -2373,8 +2367,7 @@ _NODISCARD constexpr auto uses_allocator_construction_args( _STD uses_allocator_construction_args(_Al, _Pair.second)); } -_EXPORT_STD template , int>> +_EXPORT_STD template , int>> _NODISCARD constexpr auto uses_allocator_construction_args(const _Alloc& _Al, pair<_Uty1, _Uty2>&& _Pair) noexcept { // equivalent to // return _STD uses_allocator_construction_args<_Ty>(_Al, piecewise_construct, @@ -2385,8 +2378,7 @@ _NODISCARD constexpr auto uses_allocator_construction_args(const _Alloc& _Al, pa } #if _HAS_CXX23 -_EXPORT_STD template , int>> +_EXPORT_STD template , int>> _NODISCARD constexpr auto uses_allocator_construction_args( const _Alloc& _Al, const pair<_Uty1, _Uty2>&& _Pair) noexcept { // equivalent to @@ -2399,7 +2391,7 @@ _NODISCARD constexpr auto uses_allocator_construction_args( #endif // _HAS_CXX23 _EXPORT_STD template && !_Is_deducible_as_pair<_Uty&>, int>> + enable_if_t<_Is_cv_pair<_Ty> && !_Is_deducible_as_pair<_Uty&>, int>> _NODISCARD constexpr auto uses_allocator_construction_args(const _Alloc& _Al, _Uty&& _Ux) noexcept { struct _Pair_remaker { const _Alloc& _Al; diff --git a/stl/inc/xpolymorphic_allocator.h b/stl/inc/xpolymorphic_allocator.h index c30e5f36312..5957f4333d0 100644 --- a/stl/inc/xpolymorphic_allocator.h +++ b/stl/inc/xpolymorphic_allocator.h @@ -23,32 +23,31 @@ _STL_DISABLE_CLANG_WARNINGS _STD_BEGIN #if !_HAS_CXX20 -template , int> = 0> -void _Uses_allocator_construct(_Ty* const _Ptr, _Outer_alloc& _Outer, _Inner_alloc& _Inner, _Types&&... _Args) { +template +void _Uses_alloc_construct_non_pair(_Ty* const _Ptr, _Outer_alloc& _Outer, _Inner_alloc& _Inner, _Types&&... _Args) { // uses-allocator construction of *_Ptr by alloc _Outer propagating alloc _Inner, non-pair case - if constexpr (uses_allocator_v<_Ty, _Inner_alloc>) { + if constexpr (uses_allocator_v, _Inner_alloc>) { if constexpr (is_constructible_v<_Ty, allocator_arg_t, _Inner_alloc&, _Types...>) { allocator_traits<_Outer_alloc>::construct( _Outer, _Ptr, allocator_arg, _Inner, _STD forward<_Types>(_Args)...); } else { static_assert(is_constructible_v<_Ty, _Types..., _Inner_alloc&>, - "N4901 [allocator.uses.trait]/1 requires " - "is_constructible_v when uses_allocator_v is true and " + "N4928 [allocator.uses.trait]/1 requires " + "is_constructible_v when uses_allocator_v, Alloc> is true and " "is_constructible_v is false"); allocator_traits<_Outer_alloc>::construct(_Outer, _Ptr, _STD forward<_Types>(_Args)..., _Inner); } } else { static_assert(is_constructible_v<_Ty, _Types...>, - "N4901 [allocator.uses.trait]/1 requires " - "is_constructible_v when uses_allocator_v is false"); + "N4928 [allocator.uses.trait]/1 requires " + "is_constructible_v when uses_allocator_v, Alloc> is false"); allocator_traits<_Outer_alloc>::construct(_Outer, _Ptr, _STD forward<_Types>(_Args)...); } } template -decltype(auto) _Uses_allocator_piecewise(_Alloc& _Al, tuple<_Types...>&& _Tuple) { - if constexpr (uses_allocator_v<_Ty, _Alloc>) { +decltype(auto) _Uses_alloc_piecewise(_Alloc& _Al, tuple<_Types...>&& _Tuple) { + if constexpr (uses_allocator_v, _Alloc>) { if constexpr (is_constructible_v<_Ty, allocator_arg_t, _Alloc&, _Types...>) { return _STD tuple_cat(tuple(allocator_arg, _Al), _STD move(_Tuple)); } else { @@ -59,67 +58,69 @@ decltype(auto) _Uses_allocator_piecewise(_Alloc& _Al, tuple<_Types...>&& _Tuple) } } -template -void _Uses_allocator_construct_pair(pair<_Ty1, _Ty2>* const _Ptr, _Outer_alloc& _Outer, _Inner_alloc& _Inner, +template +void _Uses_alloc_construct_pair_piecewise(_CvPair* const _Ptr, _Outer_alloc& _Outer, _Inner_alloc& _Inner, tuple<_Types1...>&& _Val1, tuple<_Types2...>&& _Val2) { // uses-allocator construction of pair from _Val1 and _Val2 by alloc _Outer propagating alloc _Inner allocator_traits<_Outer_alloc>::construct(_Outer, _Ptr, piecewise_construct, - _Uses_allocator_piecewise<_Ty1>(_Inner, _STD move(_Val1)), - _Uses_allocator_piecewise<_Ty2>(_Inner, _STD move(_Val2))); + _STD _Uses_alloc_piecewise(_Inner, _STD move(_Val1)), + _STD _Uses_alloc_piecewise(_Inner, _STD move(_Val2))); } -template -void _Uses_allocator_construct(pair<_Ty1, _Ty2>* const _Ptr, _Outer_alloc& _Outer, _Inner_alloc& _Inner, - piecewise_construct_t, tuple<_Types1...> _Val1, tuple<_Types2...> _Val2) { +template +void _Uses_alloc_construct_pair(_CvPair* const _Ptr, _Outer_alloc& _Outer, _Inner_alloc& _Inner, piecewise_construct_t, + tuple<_Types1...> _Val1, tuple<_Types2...> _Val2) { // uses-allocator construction of pair by alloc _Outer propagating alloc _Inner, piecewise case - _Uses_allocator_construct_pair(_Ptr, _Outer, _Inner, _STD move(_Val1), _STD move(_Val2)); + _STD _Uses_alloc_construct_pair_piecewise(_Ptr, _Outer, _Inner, _STD move(_Val1), _STD move(_Val2)); } -template -void _Uses_allocator_construct(pair<_Ty1, _Ty2>* const _Ptr, _Outer_alloc& _Outer, _Inner_alloc& _Inner) { +template +void _Uses_alloc_construct_pair(_CvPair* const _Ptr, _Outer_alloc& _Outer, _Inner_alloc& _Inner) { // uses-allocator construction of pair by alloc _Outer propagating alloc _Inner, zero-argument case - _Uses_allocator_construct_pair(_Ptr, _Outer, _Inner, tuple<>{}, tuple<>{}); + _STD _Uses_alloc_construct_pair_piecewise(_Ptr, _Outer, _Inner, tuple<>{}, tuple<>{}); } -template -void _Uses_allocator_construct( - pair<_Ty1, _Ty2>* const _Ptr, _Outer_alloc& _Outer, _Inner_alloc& _Inner, _Uty&& _Arg1, _Vty&& _Arg2) { +template +void _Uses_alloc_construct_pair( + _CvPair* const _Ptr, _Outer_alloc& _Outer, _Inner_alloc& _Inner, _Uty&& _Arg1, _Vty&& _Arg2) { // uses-allocator construction of pair by alloc _Outer propagating alloc _Inner, two-argument case - _Uses_allocator_construct_pair(_Ptr, _Outer, _Inner, _STD forward_as_tuple(_STD forward<_Uty>(_Arg1)), + _STD _Uses_alloc_construct_pair_piecewise(_Ptr, _Outer, _Inner, _STD forward_as_tuple(_STD forward<_Uty>(_Arg1)), _STD forward_as_tuple(_STD forward<_Vty>(_Arg2))); } -template -void _Uses_allocator_construct( - pair<_Ty1, _Ty2>* const _Ptr, _Outer_alloc& _Outer, _Inner_alloc& _Inner, const pair<_Uty, _Vty>& _Pair) { +template +void _Uses_alloc_construct_pair( + _CvPair* const _Ptr, _Outer_alloc& _Outer, _Inner_alloc& _Inner, const pair<_Uty, _Vty>& _Pair) { // uses-allocator construction of pair by alloc _Outer propagating alloc _Inner, lvalue pair argument - _Uses_allocator_construct_pair( + _STD _Uses_alloc_construct_pair_piecewise( _Ptr, _Outer, _Inner, _STD forward_as_tuple(_Pair.first), _STD forward_as_tuple(_Pair.second)); } -template -void _Uses_allocator_construct( - pair<_Ty1, _Ty2>* const _Ptr, _Outer_alloc& _Outer, _Inner_alloc& _Inner, pair<_Uty, _Vty>&& _Pair) { +template +void _Uses_alloc_construct_pair( + _CvPair* const _Ptr, _Outer_alloc& _Outer, _Inner_alloc& _Inner, pair<_Uty, _Vty>&& _Pair) { // uses-allocator construction of pair by alloc _Outer propagating alloc _Inner, rvalue pair argument - _Uses_allocator_construct_pair(_Ptr, _Outer, _Inner, _STD forward_as_tuple(_STD forward<_Uty>(_Pair.first)), + _STD _Uses_alloc_construct_pair_piecewise(_Ptr, _Outer, _Inner, + _STD forward_as_tuple(_STD forward<_Uty>(_Pair.first)), _STD forward_as_tuple(_STD forward<_Vty>(_Pair.second))); } -template , int> = 0> -void _Uses_allocator_construct(pair<_Ty1, _Ty2>* const _Ptr, _Outer_alloc& _Outer, _Inner_alloc& _Inner, _Uty&& _Ux) { +void _Uses_alloc_construct_pair(_CvPair* const _Ptr, _Outer_alloc& _Outer, _Inner_alloc& _Inner, _Uty&& _Ux) { // uses-allocator construction of pair by alloc _Outer propagating alloc _Inner, non-pair argument - static_assert(_Is_normally_bindable, _Uty>, + static_assert(_Is_normally_bindable, _Uty>, "The argument must be bindable to a reference to the std::pair type."); - using _Pair_ref_t = _Normally_bound_ref, _Uty>; + using _Pair_ref_t = _Normally_bound_ref, _Uty>; _Pair_ref_t _Pair_ref = _STD forward<_Uty>(_Ux); - if constexpr (is_same_v<_Pair_ref_t, const pair<_Ty1, _Ty2>&>) { - _Uses_allocator_construct_pair( + if constexpr (is_lvalue_reference_v<_Pair_ref_t>) { + _STD _Uses_alloc_construct_pair_piecewise( _Ptr, _Outer, _Inner, _STD forward_as_tuple(_Pair_ref.first), _STD forward_as_tuple(_Pair_ref.second)); } else { - _Uses_allocator_construct_pair(_Ptr, _Outer, _Inner, _STD forward_as_tuple(_STD forward<_Ty1>(_Pair_ref.first)), - _STD forward_as_tuple(_STD forward<_Ty2>(_Pair_ref.second))); + _STD _Uses_alloc_construct_pair_piecewise(_Ptr, _Outer, _Inner, + _STD forward_as_tuple(_STD forward(_Pair_ref.first)), + _STD forward_as_tuple(_STD forward(_Pair_ref.second))); } } #endif // !_HAS_CXX20 @@ -132,14 +133,14 @@ namespace pmr { _NODISCARD_RAW_PTR_ALLOC __declspec(allocator) void* allocate(_CRT_GUARDOVERFLOW const size_t _Bytes, const size_t _Align = alignof(max_align_t)) { // allocate _Bytes bytes of memory with alignment _Align - _STL_ASSERT(_Is_pow_2(_Align), "memory_resource::allocate(): Alignment must be a power of two."); + _STL_ASSERT(_STD _Is_pow_2(_Align), "memory_resource::allocate(): Alignment must be a power of two."); void* _Ptr = do_allocate(_Bytes, _Align); return ::operator new(_Bytes, _Ptr); } void deallocate(void* const _Ptr, const size_t _Bytes, const size_t _Align = alignof(max_align_t)) { // deallocate _Ptr, which was returned from allocate(_Bytes, _Align) - _STL_ASSERT(_Is_pow_2(_Align), "memory_resource::deallocate(): Alignment must be a power of two."); + _STL_ASSERT(_STD _Is_pow_2(_Align), "memory_resource::deallocate(): Alignment must be a power of two."); return do_deallocate(_Ptr, _Bytes, _Align); } @@ -170,12 +171,29 @@ namespace pmr { _EXPORT_STD _NODISCARD inline memory_resource* get_default_resource() noexcept { #ifdef __cpp_aligned_new - return _Aligned_get_default_resource(); + return _STD pmr::_Aligned_get_default_resource(); #else // ^^^ __cpp_aligned_new / !__cpp_aligned_new vvv - return _Unaligned_get_default_resource(); + return _STD pmr::_Unaligned_get_default_resource(); #endif // __cpp_aligned_new } +#if _HAS_CXX20 + template + struct _NODISCARD _Deallocate_bytes_guard { + ~_Deallocate_bytes_guard() noexcept { + if (_Mem_res) { + _Mem_res->deallocate(_Pobj, sizeof(_Uty), alignof(_Uty)); + } + } + + _Deallocate_bytes_guard& operator=(const _Deallocate_bytes_guard&) = delete; + _Deallocate_bytes_guard& operator=(_Deallocate_bytes_guard&&) = delete; + + memory_resource* _Mem_res; + void* _Pobj; + }; +#endif // _HAS_CXX20 + #if _HAS_CXX20 && defined(__cpp_lib_byte) _EXPORT_STD template #else @@ -192,8 +210,8 @@ namespace pmr { /* implicit */ polymorphic_allocator(memory_resource* const _Resource_) noexcept // strengthened : _Resource{_Resource_} { // initialize with _Resource_ - _STL_ASSERT(_Resource, "Cannot initialize polymorphic_allocator with null resource (N4810 20.12.3.1 " - "[mem.poly.allocator.ctor]/2)"); + _STL_ASSERT(_Resource, + "Cannot initialize polymorphic_allocator with null resource (N4928 [mem.poly.allocator.ctor]/2)"); } polymorphic_allocator(const polymorphic_allocator&) = default; @@ -242,36 +260,39 @@ namespace pmr { template _NODISCARD_RAW_PTR_ALLOC __declspec(allocator) _Uty* new_object(_Types&&... _Args) { _Uty* const _Ptr = allocate_object<_Uty>(); - _TRY_BEGIN + + _Deallocate_bytes_guard<_Uty> _Guard{_Resource, _Ptr}; construct(_Ptr, _STD forward<_Types>(_Args)...); - _CATCH_ALL - deallocate_object(_Ptr); - _RERAISE; - _CATCH_END + _Guard._Mem_res = nullptr; + return _Ptr; } template void delete_object(_Uty* const _Ptr) noexcept /* strengthened */ { - _Destroy_in_place(*_Ptr); + _STD _Destroy_in_place(*_Ptr); deallocate_object(_Ptr); } #endif // _HAS_CXX20 template void construct(_Uty* const _Ptr, _Types&&... _Args) { - // propagate allocator *this if uses_allocator_v<_Uty, polymorphic_allocator> + // propagate allocator *this if uses_allocator_v, polymorphic_allocator> #if _HAS_CXX20 _STD uninitialized_construct_using_allocator(_Ptr, *this, _STD forward<_Types>(_Args)...); #else // ^^^ _HAS_CXX20 / !_HAS_CXX20 vvv allocator _Al{}; - _Uses_allocator_construct(_Ptr, _Al, *this, _STD forward<_Types>(_Args)...); + if constexpr (_Is_cv_pair<_Uty>) { + _STD _Uses_alloc_construct_pair(_Ptr, _Al, *this, _STD forward<_Types>(_Args)...); + } else { + _STD _Uses_alloc_construct_non_pair(_Ptr, _Al, *this, _STD forward<_Types>(_Args)...); + } #endif // ^^^ !_HAS_CXX20 ^^^ } template _CXX17_DEPRECATE_POLYMORPHIC_ALLOCATOR_DESTROY void destroy(_Uty* const _Ptr) noexcept /* strengthened */ { - _Destroy_in_place(*_Ptr); + _STD _Destroy_in_place(*_Ptr); } _NODISCARD polymorphic_allocator select_on_container_copy_construction() const noexcept /* strengthened */ { diff --git a/stl/inc/xutility b/stl/inc/xutility index d4df0ef4614..74782010400 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -1096,14 +1096,30 @@ struct _Is_allocator<_Ty, void_t -using _Guide_key_t = remove_const_t::value_type::first_type>; +using _Guide_key_t = +#if _HAS_CXX23 + remove_const_t::value_type>>; +#else // ^^^ C++23 / C++20 vvv + remove_const_t::value_type::first_type>; +#endif // C++20 template -using _Guide_val_t = typename iterator_traits<_Iter>::value_type::second_type; +using _Guide_val_t = +#if _HAS_CXX23 + tuple_element_t<1, typename iterator_traits<_Iter>::value_type>; +#else // ^^^ C++23 / C++20 vvv + typename iterator_traits<_Iter>::value_type::second_type; +#endif // C++20 template -using _Guide_pair_t = pair::value_type::first_type>, - typename iterator_traits<_Iter>::value_type::second_type>; +using _Guide_pair_t = +#if _HAS_CXX23 + pair::value_type>>, + tuple_element_t<1, typename iterator_traits<_Iter>::value_type>>; +#else // ^^^ C++23 / C++20 vvv + pair::value_type::first_type>, + typename iterator_traits<_Iter>::value_type::second_type>; +#endif // C++20 _EXPORT_STD template struct is_execution_policy : false_type {}; @@ -3603,17 +3619,6 @@ namespace ranges { }; } // namespace ranges -// These declarations must be visible to qualified name lookup for _STD get in _Pair_like below, even if hasn't -// yet been included. -_EXPORT_STD template -_NODISCARD constexpr tuple_element_t<_Index, tuple<_Types...>>& get(tuple<_Types...>& _Tuple) noexcept; -_EXPORT_STD template -_NODISCARD constexpr const tuple_element_t<_Index, tuple<_Types...>>& get(const tuple<_Types...>& _Tuple) noexcept; -_EXPORT_STD template -_NODISCARD constexpr tuple_element_t<_Index, tuple<_Types...>>&& get(tuple<_Types...>&& _Tuple) noexcept; -_EXPORT_STD template -_NODISCARD constexpr const tuple_element_t<_Index, tuple<_Types...>>&& get(const tuple<_Types...>&& _Tuple) noexcept; - namespace ranges { template concept _Uses_nonqualification_pointer_conversion = @@ -3624,6 +3629,7 @@ namespace ranges { concept _Convertible_to_non_slicing = convertible_to<_From, _To> && (!_Uses_nonqualification_pointer_conversion, decay_t<_To>>); +#if !_HAS_CXX23 template concept _Pair_like = (!is_reference_v<_Ty>) && requires(_Ty __t) { @@ -3634,9 +3640,14 @@ namespace ranges { { _STD get<0>(__t) } -> convertible_to&>; { _STD get<1>(__t) } -> convertible_to&>; }; +#endif // !_HAS_CXX23 template - concept _Pair_like_convertible_from = (!range<_Ty>) && _Pair_like<_Ty> && constructible_from<_Ty, _First, _Second> + concept _Pair_like_convertible_from = (!range<_Ty>) +#if _HAS_CXX23 + && (!is_reference_v<_Ty>) +#endif // _HAS_CXX23 + && _Pair_like<_Ty> && constructible_from<_Ty, _First, _Second> && _Convertible_to_non_slicing<_First, tuple_element_t<0, _Ty>> && convertible_to<_Second, tuple_element_t<1, _Ty>>; diff --git a/stl/inc/yvals_core.h b/stl/inc/yvals_core.h index 85bebe3ffbc..0837c68a0e4 100644 --- a/stl/inc/yvals_core.h +++ b/stl/inc/yvals_core.h @@ -324,8 +324,8 @@ // P1989R2 Range Constructor For string_view // P2077R3 Heterogeneous Erasure Overloads For Associative Containers // P2136R3 invoke_r() +// P2164R9 views::enumerate // P2165R4 Compatibility Between tuple, pair, And tuple-like Objects -// (changes to views::zip and pair only) // P2166R1 Prohibiting basic_string And basic_string_view Construction From nullptr // P2186R2 Removing Garbage Collection Support // P2273R3 constexpr unique_ptr @@ -1721,6 +1721,7 @@ _EMIT_STL_ERROR(STL1004, "C++98 unexpected() is incompatible with C++23 unexpect #define __cpp_lib_ranges_chunk 202202L #define __cpp_lib_ranges_chunk_by 202202L #define __cpp_lib_ranges_contains 202207L +#define __cpp_lib_ranges_enumerate 202302L #define __cpp_lib_ranges_find_last 202207L #define __cpp_lib_ranges_fold 202207L #define __cpp_lib_ranges_iota 202202L @@ -1738,7 +1739,12 @@ _EMIT_STL_ERROR(STL1004, "C++98 unexpected() is incompatible with C++23 unexpect #define __cpp_lib_string_contains 202011L #define __cpp_lib_string_resize_and_overwrite 202110L #define __cpp_lib_to_underlying 202102L -#define __cpp_lib_unreachable 202202L + +#ifdef __cpp_lib_concepts +#define __cpp_lib_tuple_like 202207L +#endif // __cpp_lib_concepts + +#define __cpp_lib_unreachable 202202L #endif // _HAS_CXX23 // macros with language mode sensitivity diff --git a/tests/libcxx/expected_results.txt b/tests/libcxx/expected_results.txt index 261c92e5d5c..cb9206752bf 100644 --- a/tests/libcxx/expected_results.txt +++ b/tests/libcxx/expected_results.txt @@ -82,6 +82,9 @@ std/utilities/utility/mem.res/mem.res.pool/mem.res.pool.mem/unsync_deallocate_ma # Too many constexpr operations std/utilities/charconv/charconv.to.chars/integral.pass.cpp FAIL +# libc++ tests strengthened assignment operators (not compatible with P2165R4: "Compatibility Between tuple, pair, And tuple-like Objects") +std/utilities/tuple/tuple.tuple/tuple.assign/const_pair.pass.cpp FAIL + # libc++ has not implemented P2505R5: "Monadic Functions for std::expected" std/language.support/support.limits/support.limits.general/expected.version.compile.pass.cpp FAIL diff --git a/tests/std/include/range_algorithm_support.hpp b/tests/std/include/range_algorithm_support.hpp index 36597c5160c..e6b629025b2 100644 --- a/tests/std/include/range_algorithm_support.hpp +++ b/tests/std/include/range_algorithm_support.hpp @@ -383,6 +383,37 @@ struct std::basic_common_reference<::test::proxy_reference, ::test: }; namespace test { + template + struct init_list_not_constructible_sentinel { + init_list_not_constructible_sentinel() = default; + init_list_not_constructible_sentinel(T*) {} + + template + init_list_not_constructible_sentinel(std::initializer_list) = delete; + }; + + template + struct init_list_not_constructible_iterator { + using difference_type = int; + using value_type = T; + + init_list_not_constructible_iterator() = default; + init_list_not_constructible_iterator(T*) {} + + template + init_list_not_constructible_iterator(std::initializer_list) = delete; + + T& operator*() const; // not defined + init_list_not_constructible_iterator& operator++(); // not defined + init_list_not_constructible_iterator operator++(int); // not defined + + bool operator==(init_list_not_constructible_sentinel) const; // not defined + }; + + static_assert(std::input_iterator>); + static_assert( + std::sentinel_for, init_list_not_constructible_iterator>); + template }, diff --git a/tests/std/test.lst b/tests/std/test.lst index 22e1b45d8f6..157fecb6688 100644 --- a/tests/std/test.lst +++ b/tests/std/test.lst @@ -551,7 +551,13 @@ tests\P1899R3_views_stride_death tests\P1951R1_default_arguments_pair_forward_ctor tests\P2136R3_invoke_r tests\P2162R2_std_visit_for_derived_classes_from_variant +tests\P2164R9_views_enumerate +tests\P2165R4_tuple_like_common_reference +tests\P2165R4_tuple_like_common_type +tests\P2165R4_tuple_like_operations tests\P2165R4_tuple_like_pair +tests\P2165R4_tuple_like_relational_operators +tests\P2165R4_tuple_like_tuple_members tests\P2231R1_complete_constexpr_optional_variant tests\P2273R3_constexpr_unique_ptr tests\P2278R4_basic_const_iterator diff --git a/tests/std/tests/Dev08_576265_list_remove/test.cpp b/tests/std/tests/Dev08_576265_list_remove/test.cpp index f941f74ebd2..2a4a7785932 100644 --- a/tests/std/tests/Dev08_576265_list_remove/test.cpp +++ b/tests/std/tests/Dev08_576265_list_remove/test.cpp @@ -9,6 +9,8 @@ struct Val { unsigned int canary; Val() : value(0), canary(0xDEADBEEF) {} Val(int val) : value(val), canary(0x600DF00D) {} + Val(const Val&) = default; + Val& operator=(const Val&) = default; ~Val() { canary = 0xDEADBEEF; } diff --git a/tests/std/tests/Dev09_173612_tr1_regex_leak/test.cpp b/tests/std/tests/Dev09_173612_tr1_regex_leak/test.cpp index 203cbb82438..f74e3eaefcf 100644 --- a/tests/std/tests/Dev09_173612_tr1_regex_leak/test.cpp +++ b/tests/std/tests/Dev09_173612_tr1_regex_leak/test.cpp @@ -1,15 +1,19 @@ // Copyright (c) Microsoft Corporation. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +#include #include #include #include +#include #include #include #include using namespace std; +#define STATIC_ASSERT(...) static_assert(__VA_ARGS__, #__VA_ARGS__) + #pragma warning(disable : 28251) // Inconsistent annotation for 'new': this instance has no annotations. const int N = 1000; @@ -166,6 +170,31 @@ void test(const char* s) { } } +// Also test LWG-3204: sub_match::swap only swaps the base class +void test_lwg3204() { + csub_match sm1{}; + sm1.first = "hello"; + sm1.second = "world"; + sm1.matched = true; + + csub_match sm2{}; + sm2.first = "fluffy"; + sm2.second = "cat"; + sm2.matched = false; + + sm1.swap(sm2); + + assert(strcmp(sm1.first, "fluffy") == 0); + assert(strcmp(sm1.second, "cat") == 0); + assert(!sm1.matched); + + assert(strcmp(sm2.first, "hello") == 0); + assert(strcmp(sm2.second, "world") == 0); + assert(sm2.matched); + + STATIC_ASSERT(noexcept(sm1.swap(sm2))); +} + int main() { // Perform any locale allocations before we begin the tests. @@ -207,4 +236,6 @@ int main() { test("Huck[[:alpha:]]+"); test("Tom|Sawyer|Huckleberry|Finn"); test("Twain"); + + test_lwg3204(); } diff --git a/tests/std/tests/Dev11_0437519_container_behavior/test.cpp b/tests/std/tests/Dev11_0437519_container_behavior/test.cpp index 8a6e1f238dd..9dcdd7d8c37 100644 --- a/tests/std/tests/Dev11_0437519_container_behavior/test.cpp +++ b/tests/std/tests/Dev11_0437519_container_behavior/test.cpp @@ -23,6 +23,8 @@ void assert_forward_list_resize_empty() { struct A { A(unsigned int value) : _value(value) {} + A(const A&) = default; + A& operator=(const A&) = default; ~A() { _value = 0; } diff --git a/tests/std/tests/GH_002488_promise_not_default_constructible_types/test.cpp b/tests/std/tests/GH_002488_promise_not_default_constructible_types/test.cpp index 35a7b92db0c..1aafc7bfa90 100644 --- a/tests/std/tests/GH_002488_promise_not_default_constructible_types/test.cpp +++ b/tests/std/tests/GH_002488_promise_not_default_constructible_types/test.cpp @@ -22,6 +22,7 @@ struct has_default { has_default(const has_default& v) : x(v.x) { ++has_default_objects; } + has_default& operator=(const has_default&) = default; ~has_default() { --has_default_objects; @@ -38,6 +39,7 @@ struct no_default { no_default(const no_default& v) : x(v.x) { ++no_default_objects; } + no_default& operator=(const no_default&) = default; ~no_default() { --no_default_objects; diff --git a/tests/std/tests/GH_002558_format_presetPadding/env.lst b/tests/std/tests/GH_002558_format_presetPadding/env.lst index cf58a6b66f7..f02e9c02448 100644 --- a/tests/std/tests/GH_002558_format_presetPadding/env.lst +++ b/tests/std/tests/GH_002558_format_presetPadding/env.lst @@ -19,8 +19,8 @@ PM_CL="/EHsc /MTd /D_ITERATOR_DEBUG_LEVEL=0 /std:c++latest /permissive- /fp:stri PM_CL="/EHsc /MTd /D_ITERATOR_DEBUG_LEVEL=1 /std:c++latest /permissive-" PM_CL="/EHsc /MTd /D_ITERATOR_DEBUG_LEVEL=2 /std:c++latest /permissive" PM_CL="/EHsc /MTd /D_ITERATOR_DEBUG_LEVEL=2 /std:c++latest /permissive- /analyze:only /analyze:autolog-" -PM_CL="/clr /MD /std:c++20 /d1clrcxxstd" -PM_CL="/clr /MDd /std:c++20 /d1clrcxxstd" +PM_CL="/clr /MD /std:c++20" +PM_CL="/clr /MDd /std:c++20" # PM_CL="/std:c++20 /permissive- /BE /c /EHsc /MD" # PM_CL="/std:c++latest /permissive- /BE /c /EHsc /MTd" # PM_COMPILER="clang-cl" PM_CL="-fno-ms-compatibility -fno-delayed-template-parsing -Wno-unqualified-std-cast-call /EHsc /std:c++20 /permissive- /MD" diff --git a/tests/std/tests/P0088R3_variant/env.lst b/tests/std/tests/P0088R3_variant/env.lst index 92e8de7e3ed..b2afc414f0e 100644 --- a/tests/std/tests/P0088R3_variant/env.lst +++ b/tests/std/tests/P0088R3_variant/env.lst @@ -26,7 +26,7 @@ PM_CL="/EHsc /MTd /D_ITERATOR_DEBUG_LEVEL=0 /std:c++latest /permissive- /fp:stri PM_CL="/EHsc /MTd /D_ITERATOR_DEBUG_LEVEL=1 /std:c++latest /permissive-" PM_CL="/EHsc /MTd /D_ITERATOR_DEBUG_LEVEL=2 /std:c++latest /permissive /DCONSTEXPR_NOTHROW /DTEST_PERMISSIVE" PM_CL="/EHsc /MTd /D_ITERATOR_DEBUG_LEVEL=2 /std:c++latest /permissive- /analyze:only /analyze:autolog-" -# With /clr /std:c++20 /d1clrcxxstd, extreme compiler memory consumption causes test timeouts. +# With /clr /std:c++20, extreme compiler memory consumption causes test timeouts. PM_CL="/clr /MD /std:c++17 /DCONSTEXPR_NOTHROW /DTEST_PERMISSIVE" PM_CL="/clr /MDd /std:c++17 /DCONSTEXPR_NOTHROW /DTEST_PERMISSIVE" PM_CL="/BE /c /EHsc /MD /std:c++latest /permissive-" diff --git a/tests/std/tests/P0220R1_any/test.cpp b/tests/std/tests/P0220R1_any/test.cpp index 5fccb41c847..cd69a914de5 100644 --- a/tests/std/tests/P0220R1_any/test.cpp +++ b/tests/std/tests/P0220R1_any/test.cpp @@ -1211,6 +1211,8 @@ namespace modifiers::emplace { struct Tracked { static int count; Tracked() {++count;} + Tracked(Tracked const&) noexcept {++count;} + Tracked& operator=(Tracked const&) = default; ~Tracked() { --count; } }; int Tracked::count = 0; @@ -2976,6 +2978,10 @@ namespace msvc { Tracked() { ++count; } + Tracked(Tracked const&) noexcept { + ++count; + } + Tracked& operator=(Tracked const&) = default; ~Tracked() { --count; } diff --git a/tests/std/tests/P0220R1_optional/test.cpp b/tests/std/tests/P0220R1_optional/test.cpp index 33644626f10..77d3497fde1 100644 --- a/tests/std/tests/P0220R1_optional/test.cpp +++ b/tests/std/tests/P0220R1_optional/test.cpp @@ -2372,6 +2372,8 @@ class Y static bool dtor_called; Y() = default; Y(int) { TEST_THROW(6);} + Y(const Y&) = default; + Y& operator=(const Y&) = default; ~Y() {dtor_called = true;} }; @@ -2659,6 +2661,8 @@ class X constexpr X(int i, bool& dtor_called) : i_(i), dtor_called_(&dtor_called) {} constexpr X(std::initializer_list il, bool& dtor_called) : i_(il.begin()[0]), j_(il.begin()[1]), dtor_called_(&dtor_called) {} + X(const X&) = default; + X& operator=(const X&) = default; TEST_CONSTEXPR_CXX20 ~X() {*dtor_called_ = true;} friend constexpr bool operator==(const X& x, const X& y) @@ -2688,6 +2692,8 @@ class Z Z(int i) : i_(i) {} Z(std::initializer_list il) : i_(il.begin()[0]), j_(il.begin()[1]) { TEST_THROW(6);} + Z(const Z&) = default; + Z& operator=(const Z&) = default; ~Z() {dtor_called = true;} friend bool operator==(const Z& x, const Z& y) @@ -5336,6 +5342,8 @@ class X public: static bool dtor_called; X() = default; + X(const X&) = default; + X& operator=(const X&) = default; ~X() {dtor_called = true;} }; @@ -5401,6 +5409,9 @@ using std::optional; struct X { static bool dtor_called; + X() = default; + X(const X&) = default; + X& operator=(const X&) = default; ~X() {dtor_called = true;} }; diff --git a/tests/std/tests/P0220R1_polymorphic_memory_resources/test.cpp b/tests/std/tests/P0220R1_polymorphic_memory_resources/test.cpp index c679bd7d672..0de48395da2 100644 --- a/tests/std/tests/P0220R1_polymorphic_memory_resources/test.cpp +++ b/tests/std/tests/P0220R1_polymorphic_memory_resources/test.cpp @@ -1499,21 +1499,21 @@ namespace { } // namespace containers namespace map_containers { - template - void pair_conversion_test() { - struct pair_conv { - operator std::pair() const { - return {}; - } - }; + struct pair_conv { + operator std::pair() const { + return {}; + } + }; - struct mem_pair_conv { - std::pair pair_{1, 42}; - operator const std::pair&() const { - return pair_; - } - }; + struct mem_pair_conv { + std::pair pair_{1, 42}; + operator const std::pair&() const { + return pair_; + } + }; + template + void pair_conversion_test() { T cont; cont.emplace(pair_conv{}); cont.emplace(mem_pair_conv{}); @@ -1525,6 +1525,26 @@ namespace { pair_conversion_test>(); pair_conversion_test>(); } + + // Test cv-qualified source type (LWG-3677) + void lwg3677_test() { + using PairType = std::pair; + + alignas(PairType) unsigned char buffer[sizeof(PairType)]; + const auto raw_ptr = reinterpret_cast(buffer); + + std::pmr::polymorphic_allocator al; + + al.construct(raw_ptr, pair_conv{}); + al.construct(static_cast(raw_ptr), pair_conv{}); + al.construct(static_cast(raw_ptr), pair_conv{}); + al.construct(static_cast(raw_ptr), pair_conv{}); + + al.construct(raw_ptr, mem_pair_conv{}); + al.construct(static_cast(raw_ptr), mem_pair_conv{}); + al.construct(static_cast(raw_ptr), mem_pair_conv{}); + al.construct(static_cast(raw_ptr), mem_pair_conv{}); + } } // namespace map_containers } // unnamed namespace @@ -1569,4 +1589,6 @@ int main() { containers::test(); map_containers::test(); + + map_containers::lwg3677_test(); } diff --git a/tests/std/tests/P0433R2_deduction_guides/test.cpp b/tests/std/tests/P0433R2_deduction_guides/test.cpp index 8b99de5f0ba..e943019850d 100644 --- a/tests/std/tests/P0433R2_deduction_guides/test.cpp +++ b/tests/std/tests/P0433R2_deduction_guides/test.cpp @@ -651,6 +651,20 @@ void test_map_or_multimap() { static_assert(is_same_v>); static_assert(is_same_v>>); static_assert(is_same_v, MyAlloc>>); + + { // Verify changes from P2165R4 + using TupleIter = tuple*; + static_assert(is_same_v>); + + using PairIter = pair*; + static_assert(is_same_v>); + + using ArrayIter = array*; + static_assert(is_same_v>); + + using SubrangeIter = ranges::subrange*; + static_assert(is_same_v>); + } #endif // _HAS_CXX23 && defined(__cpp_lib_concepts) } diff --git a/tests/std/tests/P0475R1_P0591R4_uses_allocator_construction/test.cpp b/tests/std/tests/P0475R1_P0591R4_uses_allocator_construction/test.cpp index 542948c01dc..351fa0edbb5 100644 --- a/tests/std/tests/P0475R1_P0591R4_uses_allocator_construction/test.cpp +++ b/tests/std/tests/P0475R1_P0591R4_uses_allocator_construction/test.cpp @@ -8,6 +8,7 @@ #include #include #include +#include using namespace std; @@ -228,9 +229,56 @@ void test_lwg_3527() { // COMPILE-ONLY [[maybe_unused]] auto t = uses_allocator_construction_args>(alloc, move(p)); } +template +class payloaded_allocator { +private: + int payload = 0; + +public: + payloaded_allocator() = default; + + constexpr explicit payloaded_allocator(int n) noexcept : payload{n} {} + + template + constexpr explicit payloaded_allocator(payloaded_allocator a) noexcept : payload{a.get_payload()} {} + + friend bool operator==(payloaded_allocator, payloaded_allocator) = default; + + template + friend constexpr bool operator==(payloaded_allocator x, payloaded_allocator y) noexcept { + return x.payload == y.payload; + } + + using value_type = T; + + constexpr T* allocate(size_t n) { + return allocator{}.allocate(n); + } + + constexpr void deallocate(T* p, size_t n) { + return allocator{}.deallocate(p, n); + } + + constexpr int get_payload() const noexcept { + return payload; + } +}; + +constexpr bool test_lwg3677() { + using my_allocator = payloaded_allocator; + using my_pair = pair>; + + constexpr int in_v = 42; + auto out_v = make_obj_using_allocator(my_allocator{in_v}).second.get_allocator().get_payload(); + return in_v == out_v; +} + int main() { test_P0475R1(); assert(test_P0591R4()); static_assert(test_P0591R4()); + + assert(test_lwg3677()); + static_assert(test_lwg3677()); } diff --git a/tests/std/tests/P0608R3_improved_variant_converting_constructor/test.cpp b/tests/std/tests/P0608R3_improved_variant_converting_constructor/test.cpp index b5f1f734c79..38e604d1b7c 100644 --- a/tests/std/tests/P0608R3_improved_variant_converting_constructor/test.cpp +++ b/tests/std/tests/P0608R3_improved_variant_converting_constructor/test.cpp @@ -21,7 +21,6 @@ struct double_double { }; struct convertible_bool { convertible_bool(bool x) : x_(x) {} - ~convertible_bool() = default; operator bool() const noexcept { return x_; diff --git a/tests/std/tests/P0645R10_text_formatting_legacy_text_encoding/env.lst b/tests/std/tests/P0645R10_text_formatting_legacy_text_encoding/env.lst index fd74dc9139d..fee12cbc26a 100644 --- a/tests/std/tests/P0645R10_text_formatting_legacy_text_encoding/env.lst +++ b/tests/std/tests/P0645R10_text_formatting_legacy_text_encoding/env.lst @@ -22,8 +22,8 @@ PM_CL="/EHsc /MTd /D_ITERATOR_DEBUG_LEVEL=1 /std:c++latest /permissive-" PM_CL="/EHsc /MTd /D_ITERATOR_DEBUG_LEVEL=2 /std:c++latest /permissive" PM_CL="/EHsc /MTd /D_ITERATOR_DEBUG_LEVEL=2 /std:c++latest /permissive- /analyze:only /analyze:autolog-" # TRANSITION, VSO-1664463 -# PM_CL="/clr /MD /std:c++20 /d1clrcxxstd" -# PM_CL="/clr /MDd /std:c++20 /d1clrcxxstd" +# PM_CL="/clr /MD /std:c++20" +# PM_CL="/clr /MDd /std:c++20" # PM_CL="/std:c++20 /permissive- /BE /c /EHsc /MD" # PM_CL="/std:c++latest /permissive- /BE /c /EHsc /MTd" # PM_COMPILER="clang-cl" PM_CL="-fno-ms-compatibility -fno-delayed-template-parsing -Wno-unqualified-std-cast-call /EHsc /std:c++20 /permissive- /MD" diff --git a/tests/std/tests/P0674R1_make_shared_for_arrays/test.cpp b/tests/std/tests/P0674R1_make_shared_for_arrays/test.cpp index dcc63a93d2f..b952a9a69f4 100644 --- a/tests/std/tests/P0674R1_make_shared_for_arrays/test.cpp +++ b/tests/std/tests/P0674R1_make_shared_for_arrays/test.cpp @@ -643,6 +643,10 @@ struct WeirdDeleter { delete ptr; } + WeirdDeleter() = default; + WeirdDeleter(const WeirdDeleter&) = default; + WeirdDeleter& operator=(const WeirdDeleter&) = default; + ~WeirdDeleter() noexcept(false) {} }; static_assert(!is_nothrow_destructible_v>); diff --git a/tests/std/tests/P0784R7_library_support_for_more_constexpr_containers/test.cpp b/tests/std/tests/P0784R7_library_support_for_more_constexpr_containers/test.cpp index 57c64806081..4f7aa4dcdad 100644 --- a/tests/std/tests/P0784R7_library_support_for_more_constexpr_containers/test.cpp +++ b/tests/std/tests/P0784R7_library_support_for_more_constexpr_containers/test.cpp @@ -263,8 +263,10 @@ template struct A { T value; - constexpr A() noexcept = default; - constexpr ~A() = default; + constexpr A() noexcept = default; + constexpr A(const A&) noexcept = default; + constexpr A& operator=(const A&) noexcept = default; + constexpr ~A() = default; }; template @@ -272,6 +274,8 @@ struct nontrivial_A { T value; constexpr nontrivial_A(T in = T{}) noexcept : value(in) {} + constexpr nontrivial_A(const nontrivial_A&) noexcept = default; + constexpr nontrivial_A& operator=(const nontrivial_A&) noexcept = default; constexpr ~nontrivial_A() {} }; diff --git a/tests/std/tests/P0896R4_ranges_iterator_machinery/test.cpp b/tests/std/tests/P0896R4_ranges_iterator_machinery/test.cpp index 09e34c98304..4335bf5cc40 100644 --- a/tests/std/tests/P0896R4_ranges_iterator_machinery/test.cpp +++ b/tests/std/tests/P0896R4_ranges_iterator_machinery/test.cpp @@ -11,12 +11,7 @@ #include #include -#define STATIC_ASSERT(...) static_assert(__VA_ARGS__, #__VA_ARGS__) - -namespace ranges = std::ranges; - -template -inline constexpr bool always_false = false; +#include template using reference_to = T&; @@ -3448,6 +3443,16 @@ namespace move_iterator_test { STATIC_ASSERT(!three_way_comparable>, move_sentinel>); + // GH-3014 ": list-initialization is misused" + void test_gh_3014() { // COMPILE-ONLY + using S = test::init_list_not_constructible_sentinel; + S s; + [[maybe_unused]] move_sentinel y{s}; // Check 'move_sentinel(S s)' + + move_sentinel s2; + [[maybe_unused]] move_sentinel z{s2}; // Check 'move_sentinel(const move_sentinel& s2)' + } + constexpr bool test() { // Validate iter_move int count = 0; diff --git a/tests/std/tests/P0896R4_views_elements/test.cpp b/tests/std/tests/P0896R4_views_elements/test.cpp index f19e4a09adc..1bff24a240a 100644 --- a/tests/std/tests/P0896R4_views_elements/test.cpp +++ b/tests/std/tests/P0896R4_views_elements/test.cpp @@ -394,6 +394,26 @@ constexpr void instantiation_test() { #endif // TEST_EVERYTHING } +// GH-3014 ": list-initialization is misused" +void test_gh_3014() { // COMPILE-ONLY + struct InRange { + P* begin() { + return nullptr; + } + + test::init_list_not_constructible_iterator

begin() const { + return nullptr; + } + + unreachable_sentinel_t end() const { + return {}; + } + }; + + auto r = InRange{} | views::elements<0>; + [[maybe_unused]] decltype(as_const(r).begin()) i = r.begin(); // Check 'iterator(iterator i)' +} + int main() { { // Validate copyable views constexpr span s{some_pairs}; diff --git a/tests/std/tests/P0896R4_views_join/test.cpp b/tests/std/tests/P0896R4_views_join/test.cpp index 7da95ce34bc..ba5949952d5 100644 --- a/tests/std/tests/P0896R4_views_join/test.cpp +++ b/tests/std/tests/P0896R4_views_join/test.cpp @@ -477,6 +477,13 @@ void test_non_trivially_destructible_type() { // COMPILE-ONLY using difference_type = int; using value_type = int; + // Provide some way to construct this type. + non_trivially_destructible_input_iterator(double, double) {} + + non_trivially_destructible_input_iterator(const non_trivially_destructible_input_iterator&) = default; + non_trivially_destructible_input_iterator& operator=( + const non_trivially_destructible_input_iterator&) = default; + ~non_trivially_destructible_input_iterator() {} // To test the correct specialization of _Defaultabox, this type must not be default constructible. @@ -503,6 +510,26 @@ void test_non_trivially_destructible_type() { // COMPILE-ONLY auto r2 = views::empty | views::transform([](Inner& r) { return r; }) | views::join; } +// GH-3014 ": list-initialization is misused" +void test_gh_3014() { // COMPILE-ONLY + struct InRange { + string* begin() { + return nullptr; + } + + test::init_list_not_constructible_iterator begin() const { + return nullptr; + } + + unreachable_sentinel_t end() const { + return {}; + } + }; + + auto r = InRange{} | views::join; + [[maybe_unused]] decltype(as_const(r).begin()) i = r.begin(); // Check 'iterator(iterator i)' +} + int main() { // Validate views constexpr string_view expected = "Hello World!"sv; diff --git a/tests/std/tests/P0896R4_views_transform/test.cpp b/tests/std/tests/P0896R4_views_transform/test.cpp index 887884c942d..e314e7e6a33 100644 --- a/tests/std/tests/P0896R4_views_transform/test.cpp +++ b/tests/std/tests/P0896R4_views_transform/test.cpp @@ -811,6 +811,26 @@ void test_gh_1709() { } } +// GH-3014 ": list-initialization is misused" +void test_gh_3014() { // COMPILE-ONLY + struct InRange { + int* begin() { + return nullptr; + } + + test::init_list_not_constructible_iterator begin() const { + return nullptr; + } + + unreachable_sentinel_t end() const { + return {}; + } + }; + + auto r = InRange{} | views::transform(identity{}); + [[maybe_unused]] decltype(as_const(r).begin()) i = r.begin(); // Check 'iterator(iterator i)' +} + int main() { { // Validate copyable views constexpr span s{some_ints}; diff --git a/tests/std/tests/P0912R5_coroutine/env.lst b/tests/std/tests/P0912R5_coroutine/env.lst index 29bdc94d056..753a686fb03 100644 --- a/tests/std/tests/P0912R5_coroutine/env.lst +++ b/tests/std/tests/P0912R5_coroutine/env.lst @@ -19,8 +19,8 @@ PM_CL="/EHsc /MD /std:c++latest /permissive" PM_CL="/EHsc /MD /std:c++latest /permissive-" PM_CL="/EHsc /MTd /std:c++latest /permissive- /Zc:preprocessor" PM_CL="/EHsc /MD /std:c++latest /permissive- /analyze:only /analyze:autolog-" -PM_CL="/clr /MD /std:c++20 /d1clrcxxstd" -PM_CL="/clr /MDd /std:c++20 /d1clrcxxstd" +PM_CL="/clr /MD /std:c++20" +PM_CL="/clr /MDd /std:c++20" PM_CL="/BE /c /EHsc /MD /std:c++20 /permissive-" PM_CL="/BE /c /EHsc /MTd /std:c++latest /permissive-" PM_COMPILER="clang-cl" PM_CL="-fno-ms-compatibility -fno-delayed-template-parsing -Wno-unqualified-std-cast-call /EHsc /MD /std:c++20 /permissive-" diff --git a/tests/std/tests/P1206R7_ranges_to_misc/test.cpp b/tests/std/tests/P1206R7_ranges_to_misc/test.cpp index 9540c0077cc..354e365f52a 100644 --- a/tests/std/tests/P1206R7_ranges_to_misc/test.cpp +++ b/tests/std/tests/P1206R7_ranges_to_misc/test.cpp @@ -137,6 +137,27 @@ constexpr bool test_nested_range() { return true; } +struct ContainerLike { + template + constexpr ContainerLike(Iter first, Iter last) : dist(static_cast(ranges::distance(first, last))) {} + + constexpr char* begin() { + return nullptr; + } + constexpr char* end() { + return nullptr; + } + + std::ptrdiff_t dist; +}; + +constexpr bool test_lwg3733() { + auto nul_termination = std::views::take_while([](char ch) { return ch != '\0'; }); + auto c = nul_termination("1729") | std::views::common | ranges::to(); + assert(c.dist == 4); + return true; +} + constexpr bool test_lwg3785() { std::vector vec{42, 1729}; @@ -171,6 +192,9 @@ int main() { static_assert(test_nested_range()); #endif // defined(__clang__) || defined(__EDG__) + test_lwg3733(); + static_assert(test_lwg3733()); + test_lwg3785(); static_assert(test_lwg3785()); } diff --git a/tests/std/tests/P1208R6_source_location/test.cpp b/tests/std/tests/P1208R6_source_location/test.cpp index 57eb3210ed5..8711f14e60a 100644 --- a/tests/std/tests/P1208R6_source_location/test.cpp +++ b/tests/std/tests/P1208R6_source_location/test.cpp @@ -135,9 +135,7 @@ constexpr void lambda_test() { const auto x2 = l2(); assert(x1.line() == __LINE__ - 4); assert(x2.line() == __LINE__ - 4); -#ifndef _M_CEE // TRANSITION, VSO-1665663 assert(x1.column() == 52); -#endif // !_M_CEE assert(x2.column() == 50); #if defined(__clang__) || defined(__EDG__) // TRANSITION, DevCom-10199227 and LLVM-58951 assert(x1.function_name() == "lambda_test"sv); diff --git a/tests/std/tests/P2136R3_invoke_r/test.cpp b/tests/std/tests/P2136R3_invoke_r/test.cpp index f8d7bac3192..e8beb0e9965 100644 --- a/tests/std/tests/P2136R3_invoke_r/test.cpp +++ b/tests/std/tests/P2136R3_invoke_r/test.cpp @@ -109,6 +109,25 @@ constexpr bool test_invoke_r() { return true; } +// LWG-3655: The INVOKE operation and union types +union Union { + int x; +}; +static_assert(is_invocable_v); +static_assert(is_invocable_v); +static_assert(is_invocable_v); +static_assert(is_invocable_v); + +static_assert(is_invocable_v); +static_assert(is_invocable_v); +static_assert(!is_invocable_v); +static_assert(!is_invocable_v); + +static_assert(is_invocable_v); +static_assert(is_invocable_v); +static_assert(is_invocable_v); +static_assert(is_invocable_v); + int main() { test_invoke_r(); STATIC_ASSERT(test_invoke_r()); diff --git a/tests/std/tests/P2164R9_views_enumerate/env.lst b/tests/std/tests/P2164R9_views_enumerate/env.lst new file mode 100644 index 00000000000..8ac7033b206 --- /dev/null +++ b/tests/std/tests/P2164R9_views_enumerate/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\strict_concepts_latest_matrix.lst diff --git a/tests/std/tests/P2164R9_views_enumerate/test.cpp b/tests/std/tests/P2164R9_views_enumerate/test.cpp new file mode 100644 index 00000000000..77f6c90c185 --- /dev/null +++ b/tests/std/tests/P2164R9_views_enumerate/test.cpp @@ -0,0 +1,684 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace std; + +template +concept CanViewEnumerate = requires(Rng&& r) { views::enumerate(forward(r)); }; + +struct ImmovableReference { + ImmovableReference(ImmovableReference&&) = delete; + operator int(); // not defined +}; + +struct IteratorWithImmovableReference { + using value_type = int; + using difference_type = ptrdiff_t; + + ImmovableReference operator*() const; // not defined + IteratorWithImmovableReference& operator++(); // not defined + void operator++(int); // not defined + bool operator==(default_sentinel_t) const; // not defined +}; + +STATIC_ASSERT(input_iterator); + +using RangeWithImmovableReference = ranges::subrange; +STATIC_ASSERT(ranges::input_range); + +STATIC_ASSERT(!CanViewEnumerate); + +template +constexpr bool test_one(Rng&& rng, Expected&& expected) { + using ranges::enumerate_view, ranges::forward_range, ranges::bidirectional_range, ranges::random_access_range, + ranges::sized_range, ranges::common_range, ranges::iterator_t, ranges::sentinel_t, ranges::const_iterator_t, + ranges::const_sentinel_t, ranges::range_difference_t, ranges::range_rvalue_reference_t, ranges::cbegin, + ranges::cend, ranges::begin, ranges::end; + + constexpr bool is_view = ranges::view>; + + using V = views::all_t; + using R = enumerate_view; + + STATIC_ASSERT(ranges::view); + STATIC_ASSERT(ranges::input_range); + STATIC_ASSERT(forward_range == forward_range); + STATIC_ASSERT(bidirectional_range == bidirectional_range); + STATIC_ASSERT(random_access_range == random_access_range); + STATIC_ASSERT(!ranges::contiguous_range); + + // Validate default-initializability + STATIC_ASSERT(default_initializable == default_initializable); + + // Validate borrowed_range + STATIC_ASSERT(ranges::borrowed_range == ranges::borrowed_range); + + // ... with lvalue argument + STATIC_ASSERT(CanViewEnumerate == (!is_view || copy_constructible) ); + if constexpr (CanViewEnumerate) { + constexpr bool is_noexcept = !is_view || is_nothrow_copy_constructible_v; + + STATIC_ASSERT(same_as); + STATIC_ASSERT(noexcept(views::enumerate(rng)) == is_noexcept); + + STATIC_ASSERT(same_as); + STATIC_ASSERT(noexcept(rng | views::enumerate) == is_noexcept); + } + + // ... with const lvalue argument + STATIC_ASSERT(CanViewEnumerate&> == (!is_view || copy_constructible) ); + if constexpr (CanViewEnumerate&>) { + using RC = enumerate_view&>>; + constexpr bool is_noexcept = !is_view || is_nothrow_copy_constructible_v; + + STATIC_ASSERT(same_as); + STATIC_ASSERT(noexcept(views::enumerate(as_const(rng))) == is_noexcept); + + STATIC_ASSERT(same_as); + STATIC_ASSERT(noexcept(as_const(rng) | views::enumerate) == is_noexcept); + } + + // ... with rvalue argument + STATIC_ASSERT(CanViewEnumerate> == (is_view || movable>) ); + if constexpr (CanViewEnumerate>) { + using RS = enumerate_view>>; + constexpr bool is_noexcept = is_nothrow_move_constructible_v; + + STATIC_ASSERT(same_as); + STATIC_ASSERT(noexcept(views::enumerate(move(rng))) == is_noexcept); + + STATIC_ASSERT(same_as); + STATIC_ASSERT(noexcept(move(rng) | views::enumerate) == is_noexcept); + } + + // ... with const rvalue argument + STATIC_ASSERT(CanViewEnumerate> == (is_view && copy_constructible) ); + if constexpr (CanViewEnumerate>) { + constexpr bool is_noexcept = is_nothrow_copy_constructible_v; + + STATIC_ASSERT(same_as); + STATIC_ASSERT(noexcept(views::enumerate(move(as_const(rng)))) == is_noexcept); + + STATIC_ASSERT(same_as); + STATIC_ASSERT(noexcept(move(as_const(rng)) | views::enumerate) == is_noexcept); + } + + // Validate deduction guide + same_as auto r = enumerate_view{forward(rng)}; + + // Validate enumerate_view::size + STATIC_ASSERT(CanMemberSize == sized_range); + if constexpr (CanMemberSize) { + same_as> auto s = r.size(); + assert(_To_unsigned_like(s) == ranges::size(expected)); + STATIC_ASSERT(noexcept(r.size()) == noexcept(ranges::size(rng))); // strengthened + } + + // Validate enumerate_view::size (const) + STATIC_ASSERT(CanMemberSize == sized_range); + if constexpr (CanMemberSize) { + same_as> auto s = as_const(r).size(); + assert(_To_unsigned_like(s) == ranges::size(expected)); + STATIC_ASSERT(noexcept(as_const(r).size()) == noexcept(ranges::size(as_const(rng)))); // strengthened + } + + const bool is_empty = ranges::empty(expected); + + // Validate view_interface::empty and operator bool + STATIC_ASSERT(CanMemberEmpty == (forward_range || sized_range) ); + STATIC_ASSERT(CanBool == CanEmpty); + if constexpr (CanMemberEmpty) { + assert(r.empty() == is_empty); + assert(static_cast(r) == !is_empty); + } + + // Validate view_interface::empty and operator bool (const) + STATIC_ASSERT(CanMemberEmpty == (forward_range || sized_range) ); + STATIC_ASSERT(CanBool == CanEmpty); + if constexpr (CanMemberEmpty) { + assert(as_const(r).empty() == is_empty); + assert(static_cast(as_const(r)) == !is_empty); + } + + // Validate content + assert(ranges::equal(r, expected)); + if (!forward_range) { // intentionally not if constexpr + return true; + } + + // Validate enumerate_view::begin + STATIC_ASSERT(CanMemberBegin); + { + const same_as> auto i = r.begin(); + if (!is_empty) { + assert(*i == *begin(expected)); + } + + if constexpr (copy_constructible) { + auto r2 = r; + const same_as> auto i2 = r2.begin(); + if (!is_empty) { + assert(*i2 == *i); + } + } + } + + // Validate enumerate_view::begin (const) + STATIC_ASSERT(CanMemberBegin == ranges::range); + if constexpr (CanMemberBegin) { + const same_as> auto ci = as_const(r).begin(); + if (!is_empty) { + assert(*ci == *begin(expected)); + } + + if constexpr (copy_constructible) { + const auto cr2 = r; + const same_as> auto ci2 = cr2.begin(); + if (!is_empty) { + assert(*ci2 == *ci); + } + } + } + + // Validate enumerate_view::end + STATIC_ASSERT(CanMemberEnd); + { + const same_as> auto s = r.end(); + assert((r.begin() == s) == is_empty); + + if constexpr (sentinel_for, iterator_t>) { + assert((as_const(r).begin() == s) == is_empty); + } + + STATIC_ASSERT(common_range == (common_range && sized_range) ); + if constexpr (common_range && sized_range && bidirectional_range) { + if (!is_empty) { + assert(*prev(s) == *prev(end(expected))); + } + + if constexpr (copy_constructible) { + auto r2 = r; + if (!is_empty) { + assert(*prev(r2.end()) == *prev(end(expected))); + } + } + } + } + + // Validate enumerate_view::end (const) + STATIC_ASSERT(CanMemberEnd == ranges::range); + if constexpr (CanMemberEnd) { + const same_as> auto cs = as_const(r).end(); + assert((as_const(r).begin() == cs) == is_empty); + + if constexpr (sentinel_for, iterator_t>) { + assert((r.begin() == cs) == is_empty); + } + + STATIC_ASSERT(common_range == (common_range && sized_range) ); + if constexpr (common_range && sized_range && bidirectional_range) { + if (!is_empty) { + assert(*prev(cs) == *prev(end(expected))); + } + + if constexpr (copy_constructible) { + const auto r2 = r; + if (!is_empty) { + assert(*prev(r2.end()) == *prev(end(expected))); + } + } + } + } + + // Validate view_interface::cbegin + STATIC_ASSERT(CanMemberCBegin); + STATIC_ASSERT(CanMemberCBegin == ranges::range); + { + const same_as> auto i = r.cbegin(); + if (!is_empty) { + assert(*i == *cbegin(expected)); + } + + if constexpr (copyable) { + auto r2 = r; + const same_as> auto i2 = r2.cbegin(); + if (!is_empty) { + assert(*i2 == *i); + } + } + + if constexpr (CanCBegin) { + const same_as> auto i3 = as_const(r).cbegin(); + if (!is_empty) { + assert(*i3 == *i); + } + } + } + + // Validate view_interface::cend + STATIC_ASSERT(CanMemberCEnd); + STATIC_ASSERT(CanMemberCEnd == ranges::range); + if (!is_empty) { + same_as> auto i = r.cend(); + if constexpr (common_range && sized_range && bidirectional_range) { + assert(*prev(i) == *prev(cend(expected))); + } + + if constexpr (CanCEnd) { + same_as> auto i2 = as_const(r).cend(); + if constexpr (common_range && sized_range && bidirectional_range) { + assert(*prev(i2) == *prev(cend(expected))); + } + } + } + + // Validate view_interface::data + STATIC_ASSERT(!CanData); + STATIC_ASSERT(!CanData); + + if (is_empty) { + return true; + } + + // Validate view_interface::operator[] + STATIC_ASSERT(CanIndex == random_access_range); + if constexpr (CanIndex) { + assert(r[0] == expected[0]); + } + + // Validate view_interface::operator[] (const) + STATIC_ASSERT(CanIndex == random_access_range); + if constexpr (CanIndex) { + assert(as_const(r)[0] == expected[0]); + } + + // Validate view_interface::front + STATIC_ASSERT(CanMemberFront == forward_range); + if constexpr (CanMemberFront) { + assert(r.front() == *begin(expected)); + } + + // Validate view_interface::front (const) + STATIC_ASSERT(CanMemberFront == forward_range); + if constexpr (CanMemberFront) { + assert(as_const(r).front() == *begin(expected)); + } + + // Validate view_interface::back + STATIC_ASSERT(CanMemberBack == (bidirectional_range && common_range && sized_range) ); + if constexpr (CanMemberBack) { + assert(r.back() == *prev(end(expected))); + } + + // Validate view_interface::back (const) + STATIC_ASSERT( + CanMemberBack == (bidirectional_range && common_range && sized_range) ); + if constexpr (CanMemberBack) { + assert(as_const(r).back() == *prev(end(expected))); + } + + { // Validate enumerate_view::iterator + // Check iterator_category + STATIC_ASSERT(same_as::iterator_category, input_iterator_tag>); + + if constexpr (forward_range) { + [[maybe_unused]] const iterator_t defaulted; + } + + same_as> auto i = r.begin(); + assert(i.index() == 0); + + { // Check comparisons + assert(i == i); + assert(!(i != i)); + assert(!(i < i)); + assert(i <= i); + assert(!(i > i)); + assert(i >= i); + assert(i <=> i == strong_ordering::equal); + + if constexpr (forward_range) { + auto i2 = ranges::next(i, 1); + assert(!(i == i2)); + assert(i != i2); + assert(i < i2); + assert(i <= i2); + assert(i2 > i); + assert(i2 >= i); + assert(i <=> i2 == strong_ordering::less); + assert(i2 <=> i == strong_ordering::greater); + } + } + + if constexpr (forward_range) { + assert(*i++ == expected[0]); + } else { + STATIC_ASSERT(is_void_v); + } + assert(*++i == expected[2]); + assert(i.index() == 2); + + if constexpr (bidirectional_range) { + assert(*i-- == expected[2]); + assert(*--i == expected[0]); + } + + if constexpr (random_access_range) { + i += 2; + assert(*i == expected[2]); + + i -= 2; + assert(*i == expected[0]); + + assert(i[2] == expected[2]); + + const auto i2 = i + 2; + assert(*i2 == expected[2]); + + const auto i3 = 2 + i; + assert(*i3 == expected[2]); + + const auto i4 = i3 - 2; + assert(*i4 == expected[0]); + + const same_as> auto diff1 = i2 - i; + assert(diff1 == 2); + + const same_as> auto diff2 = i - i2; + assert(diff2 == -2); + } + + if constexpr (sized_sentinel_for, iterator_t>) { + const auto i2 = r.begin(); + const auto sen = r.end(); + const auto size = ranges::ssize(expected); + + const same_as> auto diff3 = i2 - sen; + assert(diff3 == -size); + + const same_as> auto diff4 = sen - i2; + assert(diff4 == size); + } + + if constexpr (sized_sentinel_for, iterator_t>) { + const auto i2 = r.begin(); + const auto csen = as_const(r).end(); + const auto size = ranges::ssize(expected); + + const same_as> auto diff3 = i2 - csen; + assert(diff3 == -size); + + const same_as> auto diff4 = csen - i2; + assert(diff4 == size); + } + + using IterMoveResult = tuple, range_rvalue_reference_t>; + [[maybe_unused]] same_as decltype(auto) moved = ranges::iter_move(i); + STATIC_ASSERT(noexcept(ranges::iter_move(i)) + == (noexcept(ranges::iter_move(i.base())) + && is_nothrow_move_constructible_v>) ); + + [[maybe_unused]] same_as&> decltype(auto) i_base = as_const(i).base(); + STATIC_ASSERT(noexcept(as_const(i).base())); + + [[maybe_unused]] same_as> decltype(auto) i_base2 = move(i).base(); + STATIC_ASSERT(noexcept(move(i).base()) == is_nothrow_move_constructible_v>); // strengthened + } + + if constexpr (CanMemberBegin) { // Validate enumerate_view::iterator + // Check iterator_category + STATIC_ASSERT(same_as::iterator_category, input_iterator_tag>); + + constexpr bool constructible_from_nonconst = convertible_to, iterator_t> // + && convertible_to, sentinel_t>; + if constexpr (forward_range) { + [[maybe_unused]] const iterator_t const_defaulted; + } + + same_as> auto i = r.begin(); + same_as> auto ci = as_const(r).begin(); + assert(ci.index() == 0); + + { // Check comparisons + assert(ci == ci); + assert(!(ci != ci)); + assert(!(ci < ci)); + assert(ci <= ci); + assert(!(ci > ci)); + assert(ci >= ci); + assert(ci <=> ci == strong_ordering::equal); + + if constexpr (forward_range) { + auto ci2 = ranges::next(ci, 1); + assert(!(ci == ci2)); + assert(ci != ci2); + assert(ci < ci2); + assert(ci <= ci2); + assert(ci2 > ci); + assert(ci2 >= ci); + assert(ci <=> ci2 == strong_ordering::less); + assert(ci2 <=> ci == strong_ordering::greater); + } + + if constexpr (constructible_from_nonconst) { // Check cross comparisons + assert(ci == i); + assert(!(ci < i)); + assert(ci <= i); + assert(!(ci > i)); + assert(ci >= i); + assert(ci <=> i == strong_ordering::equal); + + if constexpr (forward_range) { + auto i2 = ranges::next(i, 1); + assert(ci != i2); + assert(ci < i2); + assert(ci <= i2); + assert(i2 > ci); + assert(i2 >= ci); + assert(ci <=> i2 == strong_ordering::less); + assert(i2 <=> ci == strong_ordering::greater); + } + } + } + + if constexpr (forward_range) { + assert(*ci++ == expected[0]); + } else { + STATIC_ASSERT(is_void_v); + } + assert(*++ci == expected[2]); + assert(ci.index() == 2); + + if constexpr (bidirectional_range) { + assert(*ci-- == expected[2]); + assert(*--ci == expected[0]); + } + + if constexpr (random_access_range) { + ci += 2; + assert(*ci == expected[2]); + + ci -= 2; + assert(*ci == expected[0]); + + assert(ci[2] == expected[2]); + + const auto ci2 = ci + 2; + assert(*ci2 == expected[2]); + + const auto ci3 = 2 + ci; + assert(*ci3 == expected[2]); + + const auto ci4 = ci3 - 2; + assert(*ci4 == expected[0]); + + const same_as> auto diff1 = ci2 - ci; + assert(diff1 == 2); + + const same_as> auto diff2 = ci - ci2; + assert(diff2 == -2); + } + + if constexpr (sized_sentinel_for, iterator_t>) { + const auto ci2 = as_const(r).begin(); + const auto sen = r.end(); + const auto size = ranges::ssize(expected); + + const same_as> auto diff3 = ci2 - sen; + assert(diff3 == -size); + + const same_as> auto diff4 = sen - ci2; + assert(diff4 == size); + } + + if constexpr (sized_sentinel_for, iterator_t>) { + const auto ci2 = as_const(r).begin(); + const auto csen = as_const(r).end(); + const auto size = ranges::ssize(expected); + + const same_as> auto diff3 = ci2 - csen; + assert(diff3 == -size); + + const same_as> auto diff4 = csen - ci2; + assert(diff4 == size); + } + + using IterMoveResult = tuple, range_rvalue_reference_t>; + [[maybe_unused]] same_as decltype(auto) moved = ranges::iter_move(ci); + STATIC_ASSERT(noexcept(ranges::iter_move(ci)) + == (noexcept(ranges::iter_move(ci.base())) + && is_nothrow_move_constructible_v>) ); + + [[maybe_unused]] same_as&> decltype(auto) ci_base = as_const(ci).base(); + STATIC_ASSERT(noexcept(as_const(ci).base())); + + [[maybe_unused]] same_as> decltype(auto) ci_base2 = move(ci).base(); + STATIC_ASSERT(noexcept(move(ci).base()) == is_nothrow_move_constructible_v>); + } + + // Validate enumerate_view::base() const& + STATIC_ASSERT(CanMemberBase == copy_constructible); + if constexpr (copy_constructible) { + same_as auto b1 = as_const(r).base(); + STATIC_ASSERT(noexcept(as_const(r).base()) == is_nothrow_copy_constructible_v); // strengthened + assert(*b1.begin() == get<1>(*begin(expected))); + } + + // Validate enumerate_view::base() && + [[maybe_unused]] same_as auto b2 = move(r).base(); + STATIC_ASSERT(noexcept(move(r).base()) == is_nothrow_move_constructible_v); // strengthened + assert(*b2.begin() == get<1>(*begin(expected))); + + return true; +} + +static constexpr int some_ints[] = {1, 22, 333, 4444, 55555, 666666}; +static constexpr tuple enumerate_result[] = { + {0, 1}, {1, 22}, {2, 333}, {3, 4444}, {4, 55555}, {5, 666666}}; + +struct instantiator { + template + static constexpr void call() { + R r{some_ints}; + test_one(r, enumerate_result); + } +}; + +template +using test_input_range = test::range; + +template +using test_range = + test::range}, + IsCommon, test::CanCompare{derived_from || IsCommon == test::Common::yes}, + test::ProxyRef{!derived_from}>; + +constexpr void instantiation_test() { +#ifdef TEST_EVERYTHING + test_in(); +#else // ^^^ test all input range permutations / test only "interesting" permutations vvv + using test::Common, test::Sized, test::ProxyRef; + + // When the base range is an input range, the view is sensitive to differencing + instantiator::call>(); + instantiator::call>(); + + // The view is sensitive to category, commonality, and size, but oblivious to proxyness and differencing + instantiator::call>(); + instantiator::call>(); + instantiator::call>(); + instantiator::call>(); + + instantiator::call>(); + instantiator::call>(); + instantiator::call>(); + instantiator::call>(); + + instantiator::call>(); + instantiator::call>(); + instantiator::call>(); + instantiator::call>(); + + instantiator::call>(); + instantiator::call>(); + instantiator::call>(); + instantiator::call>(); +#endif // TEST_EVERYTHING +} + +template > +using move_only_view = test::range}, + test::CanView::yes, test::Copyability::move_only>; + +int main() { + { // Validate views + // ... copyable + constexpr span s{some_ints}; + STATIC_ASSERT(test_one(s, enumerate_result)); + test_one(s, enumerate_result); + } + + { // ... move-only + test_one(move_only_view{some_ints}, enumerate_result); + test_one(move_only_view{some_ints}, enumerate_result); + test_one(move_only_view{some_ints}, enumerate_result); + test_one(move_only_view{some_ints}, enumerate_result); + test_one(move_only_view{some_ints}, enumerate_result); + test_one(move_only_view{some_ints}, enumerate_result); + test_one(move_only_view{some_ints}, enumerate_result); + test_one(move_only_view{some_ints}, enumerate_result); + } + + { // Validate non-views + STATIC_ASSERT(test_one(some_ints, enumerate_result)); + test_one(some_ints, enumerate_result); + + auto vec = some_ints | ranges::to(); + test_one(vec, enumerate_result); + + auto lst = some_ints | ranges::to(); + test_one(lst, enumerate_result); + } + + { // Validate empty range + STATIC_ASSERT(test_one(span{}, span>{})); + test_one(span{}, span>{}); + } + + STATIC_ASSERT((instantiation_test(), true)); + instantiation_test(); +} diff --git a/tests/std/tests/P2165R4_tuple_like_common_reference/env.lst b/tests/std/tests/P2165R4_tuple_like_common_reference/env.lst new file mode 100644 index 00000000000..8ac7033b206 --- /dev/null +++ b/tests/std/tests/P2165R4_tuple_like_common_reference/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\strict_concepts_latest_matrix.lst diff --git a/tests/std/tests/P2165R4_tuple_like_common_reference/test.compile.pass.cpp b/tests/std/tests/P2165R4_tuple_like_common_reference/test.compile.pass.cpp new file mode 100644 index 00000000000..b644d1d3550 --- /dev/null +++ b/tests/std/tests/P2165R4_tuple_like_common_reference/test.compile.pass.cpp @@ -0,0 +1,96 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include + +using namespace std; +using ranges::subrange; + +template +concept CanCommonReference = requires { typename common_reference::type; }; + +template + requires CanCommonReference +constexpr bool test_common_reference = + same_as, Expected> && same_as, Expected>; + +struct Sentinel { + bool operator==(const auto&) const; // not defined + operator unreachable_sentinel_t() const; // not defined +}; + +template <> +struct std::common_type { + using type = unreachable_sentinel_t; +}; + +template <> +struct std::common_type { + using type = unreachable_sentinel_t; +}; + +static_assert(test_common_reference); + +// Test common_reference +static_assert(test_common_reference, tuple<>, tuple<>>); +static_assert(test_common_reference, tuple, tuple>); +static_assert(test_common_reference, tuple, tuple>); +static_assert(test_common_reference, tuple, tuple>); +static_assert(test_common_reference, tuple, tuple>); + +// Test common_reference +static_assert(test_common_reference&, tuple<>&&, const tuple<>&>); +static_assert( + test_common_reference&, volatile tuple&, const volatile tuple&>); +static_assert(test_common_reference&, + const tuple, tuple>); + +// Test common_reference, tuple-like is pair +static_assert(test_common_reference, pair, tuple>); +static_assert(test_common_reference, pair, tuple>); +static_assert( + test_common_reference, pair, tuple>); +static_assert(test_common_reference, pair, tuple>); + +// Test common_reference, tuple-like is pair +static_assert(test_common_reference&, pair&, tuple>); +static_assert(test_common_reference&, const pair&, tuple>); +static_assert( + test_common_reference&, const pair&, tuple>); +static_assert(test_common_reference, const pair&, + tuple>); + +// Test common_reference, tuple-like is array +static_assert(test_common_reference, array, tuple<>>); +static_assert(test_common_reference, array, tuple>); +static_assert(test_common_reference, array, tuple>); +static_assert(test_common_reference, array, tuple>); +static_assert(test_common_reference, array, tuple>); + +// Test common_reference, tuple-like is array +static_assert(test_common_reference&, array, tuple<>>); +static_assert(test_common_reference&, array&, tuple>); +static_assert(test_common_reference&&, array&, tuple>); + +// Test common_reference, tuple-like is ranges::subrange +static_assert(test_common_reference, subrange, tuple>); +static_assert( + test_common_reference, subrange, tuple>); +static_assert(test_common_reference, subrange, + tuple>); +static_assert(test_common_reference, subrange, + tuple>); + +// Test common_reference, tuple-like is ranges::subrange +static_assert(test_common_reference&&, const subrange, tuple>); +static_assert( + test_common_reference&, subrange, tuple>); + +// Test invalid common_references +static_assert(!CanCommonReference, array>); +static_assert(!CanCommonReference, subrange>); +static_assert(!CanCommonReference, pair>); diff --git a/tests/std/tests/P2165R4_tuple_like_common_type/env.lst b/tests/std/tests/P2165R4_tuple_like_common_type/env.lst new file mode 100644 index 00000000000..18e2d7c71ec --- /dev/null +++ b/tests/std/tests/P2165R4_tuple_like_common_type/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\concepts_latest_matrix.lst diff --git a/tests/std/tests/P2165R4_tuple_like_common_type/test.compile.pass.cpp b/tests/std/tests/P2165R4_tuple_like_common_type/test.compile.pass.cpp new file mode 100644 index 00000000000..79eca27f324 --- /dev/null +++ b/tests/std/tests/P2165R4_tuple_like_common_type/test.compile.pass.cpp @@ -0,0 +1,88 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include + +using namespace std; +using ranges::subrange; + +template +concept CanCommonType = requires { typename common_type::type; }; + +template + requires CanCommonType +inline constexpr bool test_common_type = + same_as, Expected> && same_as, Expected>; + +struct Sentinel { + bool operator==(const auto&) const; // not defined + operator unreachable_sentinel_t() const; // not defined +}; + +template <> +struct std::common_type { + using type = unreachable_sentinel_t; +}; + +template <> +struct std::common_type { + using type = unreachable_sentinel_t; +}; + +static_assert(test_common_type); + +// Test common_type +static_assert(test_common_type, tuple<>, tuple<>>); +static_assert(test_common_type, tuple, tuple>); +static_assert(test_common_type, tuple, tuple>); +static_assert(test_common_type, tuple, tuple>); +static_assert(test_common_type, tuple, tuple>); + +// Test common_reference +static_assert(test_common_type&, tuple<>&&, tuple<>>); +static_assert(test_common_type&, const tuple&&, tuple>); +static_assert(test_common_type&, tuple, tuple>); +static_assert(test_common_type&, tuple, tuple>); + +// Test common_type, tuple-like is pair +static_assert(test_common_type, pair, tuple>); +static_assert(test_common_type, pair, tuple>); +static_assert(test_common_type, pair, tuple>); +static_assert(test_common_type, pair, tuple>); + +// Test common_type, tuple-like is pair +static_assert(test_common_type&&, volatile pair&, tuple>); +static_assert(test_common_type&&, const pair&&, tuple>); + +// Test common_type, tuple-like is array +static_assert(test_common_type, array, tuple<>>); +static_assert(test_common_type, array, tuple>); +static_assert(test_common_type, array, tuple>); +static_assert(test_common_type, array, tuple>); +static_assert(test_common_type, array, tuple>); + +// Test common_type, tuple-like is array +static_assert(test_common_type&&, volatile array&, tuple<>>); +static_assert(test_common_type&, volatile array&&, tuple>); + +// Test common_type, tuple-like is ranges::subrange +static_assert(test_common_type, subrange, tuple>); +static_assert(test_common_type, subrange, tuple>); +static_assert(test_common_type, subrange, + tuple>); +static_assert(test_common_type, subrange, + tuple>); + +// Test common_type, tuple-like is ranges::subrange +static_assert(test_common_type&, volatile subrange&&, tuple>); +static_assert(test_common_type&, const subrange&&, + tuple>); + +// Test invalid common_types +static_assert(!CanCommonType, array>); +static_assert(!CanCommonType, subrange>); +static_assert(!CanCommonType, pair>); diff --git a/tests/std/tests/P2165R4_tuple_like_operations/env.lst b/tests/std/tests/P2165R4_tuple_like_operations/env.lst new file mode 100644 index 00000000000..18e2d7c71ec --- /dev/null +++ b/tests/std/tests/P2165R4_tuple_like_operations/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\concepts_latest_matrix.lst diff --git a/tests/std/tests/P2165R4_tuple_like_operations/test.compile.pass.cpp b/tests/std/tests/P2165R4_tuple_like_operations/test.compile.pass.cpp new file mode 100644 index 00000000000..3f13d449cb6 --- /dev/null +++ b/tests/std/tests/P2165R4_tuple_like_operations/test.compile.pass.cpp @@ -0,0 +1,195 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; +using ranges::subrange; + +namespace test_apply { + struct TakeAnythingFn { + void operator()(auto&&...) const noexcept; // not defined + }; + + struct StrSentinel { + constexpr bool operator==(const char*) const; // not defined + }; + + template + concept CanApply = requires(T tuple_like) { apply(TakeAnythingFn{}, tuple_like); }; + + static_assert(CanApply>); + static_assert(CanApply>); + static_assert(CanApply>); + static_assert(CanApply>); + static_assert(CanApply>); + static_assert(CanApply>); + static_assert(CanApply>); + static_assert(CanApply>); + static_assert(CanApply>); + static_assert(CanApply>); + static_assert(!CanApply); + static_assert(!CanApply); + static_assert(!CanApply); + static_assert(!CanApply>); + + static constexpr int some_ints[] = {1, 2, 3}; + + constexpr bool test() { + { // Test apply with empty tuple-like types + true_type func; + assert(apply(func, tuple{})); + assert(apply(func, array{})); + } + + { // Test apply with one-sized tuple-like types + identity func; + assert(apply(func, tuple{7}) == 7); + assert(apply(func, array{7}) == 7); + } + + { // Test apply with pair-like types + minus func; + assert(apply(func, tuple{1, 1}) == 0); + assert(apply(func, pair{3, 3}) == 0); + assert(apply(func, array{5, 5}) == 0); + + constexpr subrange rng = some_ints; + assert(apply(func, rng) == -3); + } + + { // Test apply with big tuple-like types + auto func = [](auto&&... vals) { return (vals + ...); }; + assert(apply(func, tuple{1, 2, 3}) == 6); + assert(apply(func, array{4, 5, 6}) == 15); + } + + return true; + } +} // namespace test_apply + +namespace test_make_from_tuple { + template + concept CanMakeFromTuple = requires(Tuple tuple_like) { + { make_from_tuple(tuple_like) } -> same_as; + }; + + static_assert(CanMakeFromTuple>); + static_assert(CanMakeFromTuple>); + static_assert(CanMakeFromTuple>>); + static_assert(CanMakeFromTuple, pair>); + static_assert(CanMakeFromTuple>); + static_assert(CanMakeFromTuple, array>); + static_assert(CanMakeFromTuple, subrange>); + static_assert(CanMakeFromTuple, subrange>); + static_assert(!CanMakeFromTuple); + static_assert(!CanMakeFromTuple); + static_assert(!CanMakeFromTuple); + static_assert(!CanMakeFromTuple, int*>); + + constexpr bool test() { + { // Test make_from_tuple with empty tuple-like types + struct S { + constexpr bool operator==(const S&) const = default; + }; + + assert(make_from_tuple(tuple{}) == S{}); + assert(make_from_tuple(array{}) == S{}); + } + + { // Test make_from_tuple with one-sized tuple-like types + assert(make_from_tuple(tuple{7}) == 7); + assert(make_from_tuple(array{7}) == 7); + } + + { // Test make_from_tuple with pair-like types + struct S { + constexpr S(int* x_, int* y_) : x{x_}, y{y_} {} + constexpr bool operator==(const S&) const = default; + + int* x; + int* y; + }; + + int a = 0; + int b = 1; + S expected_val{&a, &b}; + + assert(make_from_tuple(tuple{&a, &b}) == expected_val); + assert(make_from_tuple(pair{&a, &b}) == expected_val); + assert(make_from_tuple(array{&a, &b}) == expected_val); + assert(make_from_tuple(subrange{&a, &b}) == expected_val); + } + + { // Test make_from_tuple with big tuple-like types + struct NoIncrement {}; + struct S { + constexpr S(NoIncrement, int x_, int y_, int z_) : x{x_}, y{y_}, z{z_} {} + constexpr S(int x_, int y_, int z_) : x{x_ + 1}, y{y_ + 1}, z{z_ + 1} {} + constexpr bool operator==(const S&) const = default; + + int x; + int y; + int z; + }; + + S expected_val{NoIncrement{}, 2, 3, 4}; + assert(make_from_tuple(tuple{1, 2, 3}) == expected_val); + assert(make_from_tuple(array{1, 2, 3}) == expected_val); + } + + return true; + } +} // namespace test_make_from_tuple + +namespace test_tuple_cat { + template + concept CanTupleCat = requires(Tuples... tpls) { tuple_cat(tpls...); }; + + template + concept CheckTupleCat = CanTupleCat && same_as()...)), Expected>; + + static_assert(CheckTupleCat, tuple<>, array>); + static_assert(CheckTupleCat, tuple, pair>); + static_assert(CheckTupleCat, array, subrange>); + static_assert(CheckTupleCat, array, pair>); + static_assert(CheckTupleCat, array, subrange>); + static_assert(!CanTupleCat); + static_assert(!CanTupleCat); + static_assert(!CanTupleCat>); + static_assert(!CanTupleCat>); + static_assert(!CanTupleCat, tuple, int>); + + constexpr bool test() { + // Test tuple_cat with empty tuple-like types + assert(tuple_cat(tuple{}, array{}) == tuple{}); + + // Test tuple_cat with one-sized tuple-like types + assert((tuple_cat(tuple{7}, array{8}) == tuple{7, 8})); + + { // Test tuple_cat with pair-like types + int a = 0; + int b = 1; + assert( + (tuple_cat(tuple{1, 2}, array{3, 4}, pair{5, 6}, subrange{&a, &b}) == tuple{1, 2, 3, 4, 5, 6, &a, &b})); + } + + // Test tuple_cat with big tuple-like types + assert((tuple_cat(tuple{1, 2, 3}, array{4, 5, 6}) == tuple{1, 2, 3, 4, 5, 6})); + + return true; + } +} // namespace test_tuple_cat + +static_assert(test_apply::test()); +static_assert(test_make_from_tuple::test()); +static_assert(test_tuple_cat::test()); diff --git a/tests/std/tests/P2165R4_tuple_like_relational_operators/env.lst b/tests/std/tests/P2165R4_tuple_like_relational_operators/env.lst new file mode 100644 index 00000000000..8ac7033b206 --- /dev/null +++ b/tests/std/tests/P2165R4_tuple_like_relational_operators/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\strict_concepts_latest_matrix.lst diff --git a/tests/std/tests/P2165R4_tuple_like_relational_operators/test.compile.pass.cpp b/tests/std/tests/P2165R4_tuple_like_relational_operators/test.compile.pass.cpp new file mode 100644 index 00000000000..52d7a2c3377 --- /dev/null +++ b/tests/std/tests/P2165R4_tuple_like_relational_operators/test.compile.pass.cpp @@ -0,0 +1,121 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include +#include +#include + +using namespace std; +using ranges::subrange; + +struct Incomparable {}; + +struct NeverCompare { + template + constexpr bool operator==(const NeverCompare&) const { + assert(false); + return true; + } + + template + constexpr auto operator<=>(const NeverCompare&) const { + assert(false); + return strong_ordering::equal; + } +}; + +template +concept verify_comparisons = equality_comparable_with && three_way_comparable_with; + +constexpr bool test() { + { // Check comparisons of empty tuple-like types + static_assert(verify_comparisons, array>); + static_assert(!verify_comparisons, array>); + + static_assert(tuple{} == array{}); + + constexpr same_as auto cmp = (tuple{} <=> array{}); + static_assert(is_eq(cmp)); + } + + { // Check comparisons of (tuple_size_v == 1) tuple-like types + static_assert(verify_comparisons, array>); + static_assert(!verify_comparisons, array>); + static_assert(tuple{5} == array{5}); + static_assert(tuple{6} != array{7}); + static_assert(is_eq(tuple{1} <=> array{1})); + static_assert(is_lt(tuple{1} <=> array{2})); + static_assert(is_gt(tuple{3} <=> array{2})); + } + + { // Check comparisons of (tuple_size_v == 2) tuple-like types + static_assert(verify_comparisons, array>); + static_assert(!verify_comparisons, array>); + static_assert(!verify_comparisons, array>); + static_assert(verify_comparisons, pair>); + static_assert(!verify_comparisons, pair>); + static_assert(!verify_comparisons, + subrange>); // subrange does not model equality_comparable + + static_assert(tuple{1, 2} == array{1, 2}); + static_assert(tuple{2, 1} != array{1, 2}); + static_assert(is_eq(tuple{1, 2} <=> array{1, 2})); + static_assert(is_lt(tuple{1, 1} <=> array{1, 2})); + static_assert(is_gt(tuple{2, 1} <=> array{1, 1})); + + static_assert(tuple{1, 2} == pair{1, 2}); + static_assert(tuple{2, 1} != pair{1, 2}); + static_assert(is_eq(tuple{1, 2} <=> pair{1, 2})); + static_assert(is_lt(tuple{1, 1} <=> pair{1, 2})); + static_assert(is_gt(tuple{2, 1} <=> pair{1, 1})); + + int a = 0; + int b = 1; + int c[2] = {2, 3}; + static_assert(tuple{&a, &b} == subrange{&a, &b}); + static_assert(tuple{&b, &a} != subrange{&a, &b}); + static_assert(is_eq(tuple{&a, &b} <=> pair{&a, &b})); + static_assert(is_lt(tuple{&c[0], &c[0]} <=> pair{&c[0], &c[1]})); + static_assert(is_gt(tuple{&c[1], &c[0]} <=> pair{&c[0], &c[1]})); + } + + { // Check comparisons of (tuple_size_v == 3) tuple-like types + static_assert(verify_comparisons, array>); + static_assert(!verify_comparisons, array>); + static_assert(tuple{1, 2, 3} == array{1, 2, 3}); + static_assert(tuple{6, 7, 8} != array{7, 8, 9}); + static_assert(is_eq(tuple{1, 2, 3} <=> array{1, 2, 3})); + static_assert(is_lt(tuple{1, 2, 3} <=> array{1, 2, 4})); + static_assert(is_gt(tuple{4, 3, 2} <=> array{3, 2, 1})); + } + + { // Check short circuit evaluation + static_assert(tuple{0, NeverCompare{}} != pair{1, NeverCompare{}}); + static_assert(is_lt(tuple{0, NeverCompare{}} <=> pair{1, NeverCompare{}})); + static_assert(is_gt(tuple{1, NeverCompare{}} <=> pair{0, NeverCompare{}})); + } + + { // Check result type of three-way comparison + struct NeedsToSynth3Way { + bool operator<(const NeedsToSynth3Way&) const; // not defined + }; + + static_assert(same_as array{0, 2})>); + static_assert(same_as array{NeedsToSynth3Way{}})>); + static_assert(same_as array{0, 2})>); + } + + { // Check incorrect three-way comparisons + static_assert(!three_way_comparable_with, array>); + static_assert(!three_way_comparable_with, subrange>); + static_assert(!three_way_comparable_with, pair>); + } + + return true; +} + +static_assert(test()); diff --git a/tests/std/tests/P2165R4_tuple_like_tuple_members/env.lst b/tests/std/tests/P2165R4_tuple_like_tuple_members/env.lst new file mode 100644 index 00000000000..18e2d7c71ec --- /dev/null +++ b/tests/std/tests/P2165R4_tuple_like_tuple_members/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\concepts_latest_matrix.lst diff --git a/tests/std/tests/P2165R4_tuple_like_tuple_members/test.cpp b/tests/std/tests/P2165R4_tuple_like_tuple_members/test.cpp new file mode 100644 index 00000000000..b9ba3f2c4f0 --- /dev/null +++ b/tests/std/tests/P2165R4_tuple_like_tuple_members/test.cpp @@ -0,0 +1,303 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +template