diff --git a/stl/inc/array b/stl/inc/array index 5a81518e666..f10f39837b1 100644 --- a/stl/inc/array +++ b/stl/inc/array @@ -437,11 +437,11 @@ public: } #endif // _HAS_TR1_NAMESPACE - void fill(const _Ty& _Value) { + _CONSTEXPR20 void fill(const _Ty& _Value) { _STD fill_n(_Elems, _Size, _Value); } - void swap(array& _Other) noexcept(_Is_nothrow_swappable<_Ty>::value) { + _CONSTEXPR20 void swap(array& _Other) noexcept(_Is_nothrow_swappable<_Ty>::value) { _Swap_ranges_unchecked(_Elems, _Elems + _Size, _Other._Elems); } @@ -618,9 +618,9 @@ public: _DEPRECATE_TR1_NAMESPACE void assign(const _Ty&) {} #endif // _HAS_TR1_NAMESPACE - void fill(const _Ty&) {} + _CONSTEXPR20 void fill(const _Ty&) {} - void swap(array&) noexcept {} + _CONSTEXPR20 void swap(array&) noexcept {} _NODISCARD _CONSTEXPR17 iterator begin() noexcept { return iterator{}; @@ -770,7 +770,7 @@ public: }; template ::value, int> = 0> -void swap(array<_Ty, _Size>& _Left, array<_Ty, _Size>& _Right) noexcept(noexcept(_Left.swap(_Right))) { +_CONSTEXPR20 void swap(array<_Ty, _Size>& _Left, array<_Ty, _Size>& _Right) noexcept(noexcept(_Left.swap(_Right))) { return _Left.swap(_Right); } diff --git a/stl/inc/functional b/stl/inc/functional index d4b561812e5..bf733c95a0b 100644 --- a/stl/inc/functional +++ b/stl/inc/functional @@ -1599,7 +1599,7 @@ struct _Global_delete { // CLASS TEMPLATE default_searcher template -pair<_FwdItHaystack, _FwdItHaystack> _Search_pair_unchecked(_FwdItHaystack _First1, _FwdItHaystack _Last1, +_CONSTEXPR20 pair<_FwdItHaystack, _FwdItHaystack> _Search_pair_unchecked(_FwdItHaystack _First1, _FwdItHaystack _Last1, _FwdItPat _First2, _FwdItPat _Last2, _Pred_eq& _Eq, forward_iterator_tag, forward_iterator_tag) { // find first [_First2, _Last2) satisfying _Eq, arbitrary iterators for (;; ++_First1) { // loop until match or end of a sequence @@ -1621,7 +1621,7 @@ pair<_FwdItHaystack, _FwdItHaystack> _Search_pair_unchecked(_FwdItHaystack _Firs } template -pair<_FwdItHaystack, _FwdItHaystack> _Search_pair_unchecked(_FwdItHaystack _First1, _FwdItHaystack _Last1, +_CONSTEXPR20 pair<_FwdItHaystack, _FwdItHaystack> _Search_pair_unchecked(_FwdItHaystack _First1, _FwdItHaystack _Last1, _FwdItPat _First2, _FwdItPat _Last2, _Pred_eq& _Eq, random_access_iterator_tag, random_access_iterator_tag) { // find first [_First2, _Last2) satisfying _Eq, random-access iterators _Iter_diff_t<_FwdItHaystack> _Count1 = _Last1 - _First1; @@ -1646,14 +1646,15 @@ pair<_FwdItHaystack, _FwdItHaystack> _Search_pair_unchecked(_FwdItHaystack _Firs template > class default_searcher { // functor to search haystacks for needles public: - default_searcher(_FwdItPat _First, _FwdItPat _Last, _Pred_eq _Eq = _Pred_eq()) + _CONSTEXPR20 default_searcher(_FwdItPat _First, _FwdItPat _Last, _Pred_eq _Eq = _Pred_eq()) : _Data{_One_then_variadic_args_t{}, _STD move(_Eq), pair<_FwdItPat, _FwdItPat>{_First, _Last}} { const auto& _Pat = _Data._Myval2; _Adl_verify_range(_Pat.first, _Pat.second); } template - _NODISCARD pair<_FwdItHaystack, _FwdItHaystack> operator()(_FwdItHaystack _First, _FwdItHaystack _Last) const { + _NODISCARD _CONSTEXPR20 pair<_FwdItHaystack, _FwdItHaystack> operator()( + _FwdItHaystack _First, _FwdItHaystack _Last) const { // search [_First, _Last) for the searcher's pattern _Adl_verify_range(_First, _Last); const auto& _Eq = _Data._Get_first(); diff --git a/stl/inc/iterator b/stl/inc/iterator index 889ef427618..38b1758a3f6 100644 --- a/stl/inc/iterator +++ b/stl/inc/iterator @@ -38,27 +38,28 @@ public: using difference_type = void; #endif // __cpp_lib_concepts - explicit back_insert_iterator(_Container& _Cont) noexcept /* strengthened */ : container(_STD addressof(_Cont)) {} + _CONSTEXPR20 explicit back_insert_iterator(_Container& _Cont) noexcept /* strengthened */ + : container(_STD addressof(_Cont)) {} - back_insert_iterator& operator=(const typename _Container::value_type& _Val) { + _CONSTEXPR20 back_insert_iterator& operator=(const typename _Container::value_type& _Val) { container->push_back(_Val); return *this; } - back_insert_iterator& operator=(typename _Container::value_type&& _Val) { + _CONSTEXPR20 back_insert_iterator& operator=(typename _Container::value_type&& _Val) { container->push_back(_STD move(_Val)); return *this; } - _NODISCARD back_insert_iterator& operator*() noexcept /* strengthened */ { + _NODISCARD _CONSTEXPR20 back_insert_iterator& operator*() noexcept /* strengthened */ { return *this; } - back_insert_iterator& operator++() noexcept /* strengthened */ { + _CONSTEXPR20 back_insert_iterator& operator++() noexcept /* strengthened */ { return *this; } - back_insert_iterator operator++(int) noexcept /* strengthened */ { + _CONSTEXPR20 back_insert_iterator operator++(int) noexcept /* strengthened */ { return *this; } @@ -68,7 +69,7 @@ protected: // FUNCTION TEMPLATE back_inserter template -_NODISCARD back_insert_iterator<_Container> back_inserter(_Container& _Cont) noexcept /* strengthened */ { +_NODISCARD _CONSTEXPR20 back_insert_iterator<_Container> back_inserter(_Container& _Cont) noexcept /* strengthened */ { // return a back_insert_iterator return back_insert_iterator<_Container>(_Cont); } @@ -92,27 +93,28 @@ public: using difference_type = void; #endif // __cpp_lib_concepts - explicit front_insert_iterator(_Container& _Cont) : container(_STD addressof(_Cont)) {} + _CONSTEXPR20 explicit front_insert_iterator(_Container& _Cont) : container(_STD addressof(_Cont)) {} - front_insert_iterator& operator=(const typename _Container::value_type& _Val) { // push value into container + _CONSTEXPR20 front_insert_iterator& operator=(const typename _Container::value_type& _Val) { + // push value into container container->push_front(_Val); return *this; } - front_insert_iterator& operator=(typename _Container::value_type&& _Val) { // push value into container + _CONSTEXPR20 front_insert_iterator& operator=(typename _Container::value_type&& _Val) { // push value into container container->push_front(_STD move(_Val)); return *this; } - _NODISCARD front_insert_iterator& operator*() { // pretend to return designated value + _NODISCARD _CONSTEXPR20 front_insert_iterator& operator*() { // pretend to return designated value return *this; } - front_insert_iterator& operator++() { // pretend to preincrement + _CONSTEXPR20 front_insert_iterator& operator++() { // pretend to preincrement return *this; } - front_insert_iterator operator++(int) { // pretend to postincrement + _CONSTEXPR20 front_insert_iterator operator++(int) { // pretend to postincrement return *this; } @@ -122,7 +124,7 @@ protected: // FUNCTION TEMPLATE front_inserter template -_NODISCARD front_insert_iterator<_Container> front_inserter(_Container& _Cont) { +_NODISCARD _CONSTEXPR20 front_insert_iterator<_Container> front_inserter(_Container& _Cont) { return front_insert_iterator<_Container>(_Cont); } @@ -146,32 +148,31 @@ public: using difference_type = void; #endif // __cpp_lib_concepts - insert_iterator(_Container& _Cont, typename _Container::iterator _Where) + _CONSTEXPR20 insert_iterator(_Container& _Cont, typename _Container::iterator _Where) : container(_STD addressof(_Cont)), iter(_Where) {} - insert_iterator& operator=( - const typename _Container::value_type& _Val) { // insert into container and increment stored iterator + _CONSTEXPR20 insert_iterator& operator=(const typename _Container::value_type& _Val) { + // insert into container and increment stored iterator iter = container->insert(iter, _Val); ++iter; return *this; } - insert_iterator& operator=(typename _Container::value_type&& _Val) { // push value into container - + _CONSTEXPR20 insert_iterator& operator=(typename _Container::value_type&& _Val) { // push value into container iter = container->insert(iter, _STD move(_Val)); ++iter; return *this; } - _NODISCARD insert_iterator& operator*() { // pretend to return designated value + _NODISCARD _CONSTEXPR20 insert_iterator& operator*() { // pretend to return designated value return *this; } - insert_iterator& operator++() { // pretend to preincrement + _CONSTEXPR20 insert_iterator& operator++() { // pretend to preincrement return *this; } - insert_iterator& operator++(int) { // pretend to postincrement + _CONSTEXPR20 insert_iterator& operator++(int) { // pretend to postincrement return *this; } @@ -182,7 +183,7 @@ protected: // FUNCTION TEMPLATE inserter template -_NODISCARD insert_iterator<_Container> inserter(_Container& _Cont, typename _Container::iterator _Where) { +_NODISCARD _CONSTEXPR20 insert_iterator<_Container> inserter(_Container& _Cont, typename _Container::iterator _Where) { return insert_iterator<_Container>(_Cont, _Where); } diff --git a/stl/inc/tuple b/stl/inc/tuple index 903c201d916..314ffe84008 100644 --- a/stl/inc/tuple +++ b/stl/inc/tuple @@ -163,20 +163,21 @@ struct _Tuple_val { // stores each value in a tuple constexpr _Tuple_val(_Other&& _Arg) : _Val(_STD forward<_Other>(_Arg)) {} template , int> = 0> - _Tuple_val(const _Alloc&, allocator_arg_t, _Other&&... _Arg) : _Val(_STD forward<_Other>(_Arg)...) {} + constexpr _Tuple_val(const _Alloc&, allocator_arg_t, _Other&&... _Arg) : _Val(_STD forward<_Other>(_Arg)...) {} template , is_constructible<_Ty, allocator_arg_t, const _Alloc&, _Other...>>, int> = 0> - _Tuple_val(const _Alloc& _Al, allocator_arg_t, _Other&&... _Arg) + constexpr _Tuple_val(const _Alloc& _Al, allocator_arg_t, _Other&&... _Arg) : _Val(allocator_arg, _Al, _STD forward<_Other>(_Arg)...) {} template , negation>>, int> = 0> - _Tuple_val(const _Alloc& _Al, allocator_arg_t, _Other&&... _Arg) : _Val(_STD forward<_Other>(_Arg)..., _Al) {} + constexpr _Tuple_val(const _Alloc& _Al, allocator_arg_t, _Other&&... _Arg) + : _Val(_STD forward<_Other>(_Arg)..., _Al) {} _Ty _Val; }; @@ -209,20 +210,20 @@ public: constexpr tuple(const tuple&) noexcept /* strengthened */ {} // TRANSITION, ABI: should be defaulted template - tuple(allocator_arg_t, const _Alloc&) noexcept /* strengthened */ {} + _CONSTEXPR20 tuple(allocator_arg_t, const _Alloc&) noexcept /* strengthened */ {} template - tuple(allocator_arg_t, const _Alloc&, const tuple&) noexcept /* strengthened */ {} + _CONSTEXPR20 tuple(allocator_arg_t, const _Alloc&, const tuple&) noexcept /* strengthened */ {} template , int> = 0> constexpr tuple(_Tag) noexcept /* strengthened */ {} template , int> = 0> - tuple(_Tag, const _Alloc&) noexcept /* strengthened */ {} + constexpr tuple(_Tag, const _Alloc&) noexcept /* strengthened */ {} constexpr tuple& operator=(const tuple&) = default; - void swap(tuple&) noexcept {} + _CONSTEXPR20 void swap(tuple&) noexcept {} constexpr bool _Equals(const tuple&) const noexcept { return true; @@ -253,16 +254,16 @@ public: template , int> = 0> - tuple(_Tag, const _Alloc& _Al, _This2&& _This_arg, _Rest2&&... _Rest_arg) + constexpr tuple(_Tag, const _Alloc& _Al, _This2&& _This_arg, _Rest2&&... _Rest_arg) : _Mybase(_Alloc_exact_args_t{}, _Al, _STD forward<_Rest2>(_Rest_arg)...), _Myfirst(_Al, allocator_arg, _STD forward<_This2>(_This_arg)) {} template , int> = 0> - tuple(_Tag, const _Alloc& _Al, _Tpl&& _Right, index_sequence<_Indices...>); + constexpr tuple(_Tag, const _Alloc& _Al, _Tpl&& _Right, index_sequence<_Indices...>); template , int> = 0> - tuple(_Tag, const _Alloc& _Al, _Tpl&& _Right) + constexpr tuple(_Tag, const _Alloc& _Al, _Tpl&& _Right) : tuple(_Alloc_unpack_tuple_t{}, _Al, _STD forward<_Tpl>(_Right), make_index_sequence>>{}) {} @@ -432,7 +433,7 @@ public: #if _HAS_CONDITIONAL_EXPLICIT template , is_default_constructible<_Rest>...>, int> = 0> - explicit( + _CONSTEXPR20 explicit( !conjunction_v<_Is_implicitly_default_constructible<_This2>, _Is_implicitly_default_constructible<_Rest>...>) tuple(allocator_arg_t, const _Alloc& _Al) : _Mybase(allocator_arg, _Al), _Myfirst(_Al, allocator_arg) {} @@ -441,31 +442,33 @@ public: enable_if_t, is_default_constructible<_Rest>..., _Is_implicitly_default_constructible<_This2>, _Is_implicitly_default_constructible<_Rest>...>, int> = 0> - tuple(allocator_arg_t, const _Alloc& _Al) : _Mybase(allocator_arg, _Al), _Myfirst(_Al, allocator_arg) {} + _CONSTEXPR20 tuple(allocator_arg_t, const _Alloc& _Al) + : _Mybase(allocator_arg, _Al), _Myfirst(_Al, allocator_arg) {} template , is_default_constructible<_Rest>..., negation, _Is_implicitly_default_constructible<_Rest>...>>>, int> = 0> - explicit tuple(allocator_arg_t, const _Alloc& _Al) : _Mybase(allocator_arg, _Al), _Myfirst(_Al, allocator_arg) {} + _CONSTEXPR20 explicit tuple(allocator_arg_t, const _Alloc& _Al) + : _Mybase(allocator_arg, _Al), _Myfirst(_Al, allocator_arg) {} #endif // ^^^ !_HAS_CONDITIONAL_EXPLICIT ^^^ #if _HAS_CONDITIONAL_EXPLICIT template , int> = 0> - explicit(_Tuple_conditional_explicit_v) + _CONSTEXPR20 explicit(_Tuple_conditional_explicit_v) tuple(allocator_arg_t, const _Alloc& _Al, const _This& _This_arg, const _Rest&... _Rest_arg) : tuple(_Alloc_exact_args_t{}, _Al, _This_arg, _Rest_arg...) {} #else // ^^^ _HAS_CONDITIONAL_EXPLICIT ^^^ / vvv !_HAS_CONDITIONAL_EXPLICIT vvv template ::value, int> = 0> - tuple(allocator_arg_t, const _Alloc& _Al, const _This& _This_arg, const _Rest&... _Rest_arg) + _CONSTEXPR20 tuple(allocator_arg_t, const _Alloc& _Al, const _This& _This_arg, const _Rest&... _Rest_arg) : tuple(_Alloc_exact_args_t{}, _Al, _This_arg, _Rest_arg...) {} template ::value, int> = 0> - explicit tuple(allocator_arg_t, const _Alloc& _Al, const _This& _This_arg, const _Rest&... _Rest_arg) + _CONSTEXPR20 explicit tuple(allocator_arg_t, const _Alloc& _Al, const _This& _This_arg, const _Rest&... _Rest_arg) : tuple(_Alloc_exact_args_t{}, _Al, _This_arg, _Rest_arg...) {} #endif // ^^^ !_HAS_CONDITIONAL_EXPLICIT ^^^ @@ -474,7 +477,7 @@ public: enable_if_t, _Tuple_constructible_val>, int> = 0> - explicit(_Tuple_conditional_explicit_v) + _CONSTEXPR20 explicit(_Tuple_conditional_explicit_v) tuple(allocator_arg_t, const _Alloc& _Al, _This2&& _This_arg, _Rest2&&... _Rest_arg) : tuple(_Alloc_exact_args_t{}, _Al, _STD forward<_This2>(_This_arg), _STD forward<_Rest2>(_Rest_arg)...) {} #else // ^^^ _HAS_CONDITIONAL_EXPLICIT ^^^ / vvv !_HAS_CONDITIONAL_EXPLICIT vvv @@ -482,23 +485,24 @@ public: enable_if_t< conjunction_v<_Tuple_perfect_val, _Tuple_implicit_val>, int> = 0> - tuple(allocator_arg_t, const _Alloc& _Al, _This2&& _This_arg, _Rest2&&... _Rest_arg) + _CONSTEXPR20 tuple(allocator_arg_t, const _Alloc& _Al, _This2&& _This_arg, _Rest2&&... _Rest_arg) : tuple(_Alloc_exact_args_t{}, _Al, _STD forward<_This2>(_This_arg), _STD forward<_Rest2>(_Rest_arg)...) {} template , _Tuple_explicit_val>, int> = 0> - explicit tuple(allocator_arg_t, const _Alloc& _Al, _This2&& _This_arg, _Rest2&&... _Rest_arg) + _CONSTEXPR20 explicit tuple(allocator_arg_t, const _Alloc& _Al, _This2&& _This_arg, _Rest2&&... _Rest_arg) : tuple(_Alloc_exact_args_t{}, _Al, _STD forward<_This2>(_This_arg), _STD forward<_Rest2>(_Rest_arg)...) {} #endif // ^^^ !_HAS_CONDITIONAL_EXPLICIT ^^^ template , int> = 0> - tuple(allocator_arg_t, const _Alloc& _Al, const tuple& _Right) : tuple(_Alloc_unpack_tuple_t{}, _Al, _Right) {} + _CONSTEXPR20 tuple(allocator_arg_t, const _Alloc& _Al, const tuple& _Right) + : tuple(_Alloc_unpack_tuple_t{}, _Al, _Right) {} template , int> = 0> - tuple(allocator_arg_t, const _Alloc& _Al, tuple&& _Right) + _CONSTEXPR20 tuple(allocator_arg_t, const _Alloc& _Al, tuple&& _Right) : tuple(_Alloc_unpack_tuple_t{}, _Al, _STD move(_Right)) {} #if _HAS_CONDITIONAL_EXPLICIT @@ -506,7 +510,7 @@ public: enable_if_t< conjunction_v<_Tuple_constructible_val, _Tuple_convert_copy_val>, int> = 0> - explicit(_Tuple_conditional_explicit_v) + _CONSTEXPR20 explicit(_Tuple_conditional_explicit_v) tuple(allocator_arg_t, const _Alloc& _Al, const tuple<_Other...>& _Right) : tuple(_Alloc_unpack_tuple_t{}, _Al, _Right) {} #else // ^^^ _HAS_CONDITIONAL_EXPLICIT ^^^ / vvv !_HAS_CONDITIONAL_EXPLICIT vvv @@ -514,14 +518,14 @@ public: enable_if_t< conjunction_v<_Tuple_implicit_val, _Tuple_convert_copy_val>, int> = 0> - tuple(allocator_arg_t, const _Alloc& _Al, const tuple<_Other...>& _Right) + _CONSTEXPR20 tuple(allocator_arg_t, const _Alloc& _Al, const tuple<_Other...>& _Right) : tuple(_Alloc_unpack_tuple_t{}, _Al, _Right) {} template , _Tuple_convert_copy_val>, int> = 0> - explicit tuple(allocator_arg_t, const _Alloc& _Al, const tuple<_Other...>& _Right) + _CONSTEXPR20 explicit tuple(allocator_arg_t, const _Alloc& _Al, const tuple<_Other...>& _Right) : tuple(_Alloc_unpack_tuple_t{}, _Al, _Right) {} #endif // ^^^ !_HAS_CONDITIONAL_EXPLICIT ^^^ @@ -530,56 +534,56 @@ public: enable_if_t< conjunction_v<_Tuple_constructible_val, _Tuple_convert_move_val>, int> = 0> - explicit(_Tuple_conditional_explicit_v) + _CONSTEXPR20 explicit(_Tuple_conditional_explicit_v) tuple(allocator_arg_t, const _Alloc& _Al, tuple<_Other...>&& _Right) : tuple(_Alloc_unpack_tuple_t{}, _Al, _STD move(_Right)) {} #else // ^^^ _HAS_CONDITIONAL_EXPLICIT ^^^ / vvv !_HAS_CONDITIONAL_EXPLICIT vvv template , _Tuple_convert_move_val>, int> = 0> - tuple(allocator_arg_t, const _Alloc& _Al, tuple<_Other...>&& _Right) + _CONSTEXPR20 tuple(allocator_arg_t, const _Alloc& _Al, tuple<_Other...>&& _Right) : tuple(_Alloc_unpack_tuple_t{}, _Al, _STD move(_Right)) {} template , _Tuple_convert_move_val>, int> = 0> - explicit tuple(allocator_arg_t, const _Alloc& _Al, tuple<_Other...>&& _Right) + _CONSTEXPR20 explicit tuple(allocator_arg_t, const _Alloc& _Al, tuple<_Other...>&& _Right) : tuple(_Alloc_unpack_tuple_t{}, _Al, _STD move(_Right)) {} #endif // ^^^ !_HAS_CONDITIONAL_EXPLICIT ^^^ #if _HAS_CONDITIONAL_EXPLICIT template , int> = 0> - explicit(_Tuple_conditional_explicit_v) + _CONSTEXPR20 explicit(_Tuple_conditional_explicit_v) tuple(allocator_arg_t, const _Alloc& _Al, const pair<_First, _Second>& _Right) : tuple(_Alloc_unpack_tuple_t{}, _Al, _Right) {} #else // ^^^ _HAS_CONDITIONAL_EXPLICIT ^^^ / vvv !_HAS_CONDITIONAL_EXPLICIT vvv template ::value, int> = 0> - tuple(allocator_arg_t, const _Alloc& _Al, const pair<_First, _Second>& _Right) + _CONSTEXPR20 tuple(allocator_arg_t, const _Alloc& _Al, const pair<_First, _Second>& _Right) : tuple(_Alloc_unpack_tuple_t{}, _Al, _Right) {} template ::value, int> = 0> - explicit tuple(allocator_arg_t, const _Alloc& _Al, const pair<_First, _Second>& _Right) + _CONSTEXPR20 explicit tuple(allocator_arg_t, const _Alloc& _Al, const pair<_First, _Second>& _Right) : tuple(_Alloc_unpack_tuple_t{}, _Al, _Right) {} #endif // ^^^ !_HAS_CONDITIONAL_EXPLICIT ^^^ #if _HAS_CONDITIONAL_EXPLICIT template , int> = 0> - explicit(_Tuple_conditional_explicit_v) + _CONSTEXPR20 explicit(_Tuple_conditional_explicit_v) tuple(allocator_arg_t, const _Alloc& _Al, pair<_First, _Second>&& _Right) : tuple(_Alloc_unpack_tuple_t{}, _Al, _STD move(_Right)) {} #else // ^^^ _HAS_CONDITIONAL_EXPLICIT ^^^ / vvv !_HAS_CONDITIONAL_EXPLICIT vvv template ::value, int> = 0> - tuple(allocator_arg_t, const _Alloc& _Al, pair<_First, _Second>&& _Right) + _CONSTEXPR20 tuple(allocator_arg_t, const _Alloc& _Al, pair<_First, _Second>&& _Right) : tuple(_Alloc_unpack_tuple_t{}, _Al, _STD move(_Right)) {} template ::value, int> = 0> - explicit tuple(allocator_arg_t, const _Alloc& _Al, pair<_First, _Second>&& _Right) + _CONSTEXPR20 explicit tuple(allocator_arg_t, const _Alloc& _Al, pair<_First, _Second>&& _Right) : tuple(_Alloc_unpack_tuple_t{}, _Al, _STD move(_Right)) {} #endif // ^^^ !_HAS_CONDITIONAL_EXPLICIT ^^^ @@ -589,7 +593,7 @@ public: enable_if_t, _Is_copy_assignable_no_precondition_check<_Rest>...>, int> = 0> - tuple& operator=(_Identity_t _Right) noexcept( + _CONSTEXPR20 tuple& operator=(_Identity_t _Right) noexcept( conjunction_v, is_nothrow_copy_assignable<_Rest>...>) /* strengthened */ { _Myfirst._Val = _Right._Myfirst._Val; _Get_rest() = _Right._Get_rest(); @@ -600,7 +604,7 @@ public: enable_if_t, _Is_move_assignable_no_precondition_check<_Rest>...>, int> = 0> - tuple& operator=(_Identity_t<_Myself&&> _Right) noexcept( + _CONSTEXPR20 tuple& operator=(_Identity_t<_Myself&&> _Right) noexcept( conjunction_v, is_nothrow_move_assignable<_Rest>...>) { _Myfirst._Val = _STD forward<_This>(_Right._Myfirst._Val); _Get_rest() = _STD forward<_Mybase>(_Right._Get_rest()); @@ -610,7 +614,7 @@ public: template >>, _Tuple_assignable_val>, int> = 0> - tuple& operator=(const tuple<_Other...>& _Right) noexcept( + _CONSTEXPR20 tuple& operator=(const tuple<_Other...>& _Right) noexcept( _Tuple_nothrow_assignable_v) /* strengthened */ { _Myfirst._Val = _Right._Myfirst._Val; _Get_rest() = _Right._Get_rest(); @@ -620,7 +624,7 @@ public: template >>, _Tuple_assignable_val>, int> = 0> - tuple& operator=(tuple<_Other...>&& _Right) noexcept( + _CONSTEXPR20 tuple& operator=(tuple<_Other...>&& _Right) noexcept( _Tuple_nothrow_assignable_v) /* strengthened */ { _Myfirst._Val = _STD forward::_This_type>(_Right._Myfirst._Val); _Get_rest() = _STD forward::_Mybase>(_Right._Get_rest()); @@ -629,7 +633,7 @@ public: template , int> = 0> - tuple& operator=(const pair<_First, _Second>& _Right) noexcept( + _CONSTEXPR20 tuple& operator=(const pair<_First, _Second>& _Right) noexcept( _Tuple_nothrow_assignable_v) /* strengthened */ { _Myfirst._Val = _Right.first; _Get_rest()._Myfirst._Val = _Right.second; @@ -637,19 +641,20 @@ public: } template , int> = 0> - tuple& operator=(pair<_First, _Second>&& _Right) noexcept( + _CONSTEXPR20 tuple& operator=(pair<_First, _Second>&& _Right) noexcept( _Tuple_nothrow_assignable_v) /* strengthened */ { _Myfirst._Val = _STD forward<_First>(_Right.first); _Get_rest()._Myfirst._Val = _STD forward<_Second>(_Right.second); return *this; } - void swap(tuple& _Right) noexcept(conjunction_v<_Is_nothrow_swappable<_This>, _Is_nothrow_swappable<_Rest>...>) { + _CONSTEXPR20 void swap(tuple& _Right) noexcept( + conjunction_v<_Is_nothrow_swappable<_This>, _Is_nothrow_swappable<_Rest>...>) { _Swap_adl(_Myfirst._Val, _Right._Myfirst._Val); _Mybase::swap(_Right._Get_rest()); } - _Mybase& _Get_rest() noexcept { // get reference to rest of elements + constexpr _Mybase& _Get_rest() noexcept { // get reference to rest of elements return *this; } @@ -746,7 +751,7 @@ _NODISCARD constexpr bool operator<=(const tuple<_Types1...>& _Left, const tuple } template ...>, int> = 0> -void swap(tuple<_Types...>& _Left, tuple<_Types...>& _Right) noexcept(noexcept(_Left.swap(_Right))) { +_CONSTEXPR20 void swap(tuple<_Types...>& _Left, tuple<_Types...>& _Right) noexcept(noexcept(_Left.swap(_Right))) { return _Left.swap(_Right); } @@ -827,7 +832,7 @@ constexpr tuple<_This, _Rest...>::tuple(_Tag, _Tpl&& _Right, index_sequence<_Ind template template , int>> -tuple<_This, _Rest...>::tuple(_Tag, const _Alloc& _Al, _Tpl&& _Right, index_sequence<_Indices...>) +constexpr tuple<_This, _Rest...>::tuple(_Tag, const _Alloc& _Al, _Tpl&& _Right, index_sequence<_Indices...>) : tuple(_Alloc_exact_args_t{}, _Al, _STD get<_Indices>(_STD forward<_Tpl>(_Right))...) {} // FUNCTION TEMPLATE make_tuple @@ -971,13 +976,14 @@ _NODISCARD constexpr _Ty make_from_tuple(_Tuple&& _Tpl) { // construct _Ty from // TEMPLATE CONSTRUCTOR pair::pair(tuple, tuple, sequence, sequence) template template -pair<_Ty1, _Ty2>::pair(_Tuple1& _Val1, _Tuple2& _Val2, index_sequence<_Indexes1...>, index_sequence<_Indexes2...>) +constexpr pair<_Ty1, _Ty2>::pair( + _Tuple1& _Val1, _Tuple2& _Val2, index_sequence<_Indexes1...>, index_sequence<_Indexes2...>) : first(_STD get<_Indexes1>(_STD move(_Val1))...), second(_STD get<_Indexes2>(_STD move(_Val2))...) {} // TEMPLATE CONSTRUCTOR pair::pair(piecewise_construct_t, tuple, tuple) template template -pair<_Ty1, _Ty2>::pair(piecewise_construct_t, tuple<_Types1...> _Val1, tuple<_Types2...> _Val2) +_CONSTEXPR20 pair<_Ty1, _Ty2>::pair(piecewise_construct_t, tuple<_Types1...> _Val1, tuple<_Types2...> _Val2) : pair(_Val1, _Val2, index_sequence_for<_Types1...>{}, index_sequence_for<_Types2...>{}) {} // STRUCT TEMPLATE uses_allocator diff --git a/stl/inc/utility b/stl/inc/utility index e605fba9e42..43b5e98b497 100644 --- a/stl/inc/utility +++ b/stl/inc/utility @@ -265,10 +265,10 @@ struct pair { // store a pair of values #endif // ^^^ !_HAS_CONDITIONAL_EXPLICIT ^^^ template - pair(_Tuple1& _Val1, _Tuple2& _Val2, index_sequence<_Indexes1...>, index_sequence<_Indexes2...>); + constexpr pair(_Tuple1& _Val1, _Tuple2& _Val2, index_sequence<_Indexes1...>, index_sequence<_Indexes2...>); template - pair(piecewise_construct_t, tuple<_Types1...> _Val1, tuple<_Types2...> _Val2); + _CONSTEXPR20 pair(piecewise_construct_t, tuple<_Types1...> _Val1, tuple<_Types2...> _Val2); pair& operator=(const volatile pair&) = delete; @@ -276,7 +276,7 @@ struct pair { // store a pair of values enable_if_t, _Is_copy_assignable_no_precondition_check>, int> = 0> - pair& operator=(_Identity_t _Right) noexcept( + _CONSTEXPR20 pair& operator=(_Identity_t _Right) noexcept( conjunction_v, is_nothrow_copy_assignable<_Ty2>>) /* strengthened */ { first = _Right.first; second = _Right.second; @@ -287,7 +287,7 @@ struct pair { // store a pair of values enable_if_t, _Is_move_assignable_no_precondition_check>, int> = 0> - pair& operator=(_Identity_t<_Myself&&> _Right) noexcept( + _CONSTEXPR20 pair& operator=(_Identity_t<_Myself&&> _Right) noexcept( conjunction_v, is_nothrow_move_assignable<_Ty2>>) /* strengthened */ { first = _STD forward<_Ty1>(_Right.first); second = _STD forward<_Ty2>(_Right.second); @@ -298,7 +298,8 @@ struct pair { // store a pair of values enable_if_t>>, is_assignable<_Ty1&, const _Other1&>, is_assignable<_Ty2&, const _Other2&>>, int> = 0> - pair& operator=(const pair<_Other1, _Other2>& _Right) noexcept(is_nothrow_assignable_v<_Ty1&, const _Other1&>&& + _CONSTEXPR20 pair& operator=(const pair<_Other1, _Other2>& _Right) noexcept( + is_nothrow_assignable_v<_Ty1&, const _Other1&>&& is_nothrow_assignable_v<_Ty2&, const _Other2&>) /* strengthened */ { first = _Right.first; second = _Right.second; @@ -309,14 +310,15 @@ struct pair { // store a pair of values enable_if_t>>, is_assignable<_Ty1&, _Other1>, is_assignable<_Ty2&, _Other2>>, int> = 0> - pair& operator=(pair<_Other1, _Other2>&& _Right) noexcept( + _CONSTEXPR20 pair& operator=(pair<_Other1, _Other2>&& _Right) noexcept( is_nothrow_assignable_v<_Ty1&, _Other1>&& is_nothrow_assignable_v<_Ty2&, _Other2>) /* strengthened */ { first = _STD forward<_Other1>(_Right.first); second = _STD forward<_Other2>(_Right.second); return *this; } - void swap(pair& _Right) noexcept(_Is_nothrow_swappable<_Ty1>::value&& _Is_nothrow_swappable<_Ty2>::value) { + _CONSTEXPR20 void swap(pair& _Right) noexcept( + _Is_nothrow_swappable<_Ty1>::value&& _Is_nothrow_swappable<_Ty2>::value) { if (this != _STD addressof(_Right)) { _Swap_adl(first, _Right.first); _Swap_adl(second, _Right.second); @@ -333,7 +335,7 @@ pair(_Ty1, _Ty2) -> pair<_Ty1, _Ty2>; #endif // _HAS_CXX17 template ::value && _Is_swappable<_Ty2>::value, int> = 0> -void swap(pair<_Ty1, _Ty2>& _Left, pair<_Ty1, _Ty2>& _Right) noexcept(noexcept(_Left.swap(_Right))) { +_CONSTEXPR20 void swap(pair<_Ty1, _Ty2>& _Left, pair<_Ty1, _Ty2>& _Right) noexcept(noexcept(_Left.swap(_Right))) { _Left.swap(_Right); } diff --git a/stl/inc/xstring b/stl/inc/xstring index 58afe15d048..8aaf1dbfd8e 100644 --- a/stl/inc/xstring +++ b/stl/inc/xstring @@ -24,6 +24,12 @@ _STL_DISABLE_CLANG_WARNINGS #pragma push_macro("new") #undef new +#ifdef __clang__ +#define _HAS_MEMCPY_MEMMOVE_INTRINSICS 1 +#else // ^^^ use __builtin_memcpy and __builtin_memmove ^^^ / vvv use workaround vvv +#define _HAS_MEMCPY_MEMMOVE_INTRINSICS 0 // TRANSITION, DevCom-1046483 (MSVC) and VSO-1129974 (EDG) +#endif // ^^^ use workaround ^^^ + _STD_BEGIN // STRUCT TEMPLATE _Char_traits (FROM ) template @@ -34,6 +40,90 @@ struct _Char_traits { // properties of a string or stream element using off_type = streamoff; using state_type = _Mbstatet; + // For copy/move, we can uniformly call memcpy/memmove (or their builtin versions) for all element types. + + static _CONSTEXPR20 _Elem* copy(_Out_writes_all_(_Count) _Elem* const _First1, + _In_reads_(_Count) const _Elem* const _First2, const size_t _Count) noexcept /* strengthened */ { + // copy [_First2, _First2 + _Count) to [_First1, ...) +#if _HAS_MEMCPY_MEMMOVE_INTRINSICS + __builtin_memcpy(_First1, _First2, _Count * sizeof(_Elem)); +#else // ^^^ _HAS_MEMCPY_MEMMOVE_INTRINSICS ^^^ / vvv !_HAS_MEMCPY_MEMMOVE_INTRINSICS vvv +#ifdef __cpp_lib_is_constant_evaluated + if (_STD is_constant_evaluated()) { + // pre: [_First1, _First1 + _Count) and [_First2, _First2 + _Count) do not overlap; see LWG-3085 + for (size_t _Idx = 0; _Idx < _Count; ++_Idx) { + _First1[_Idx] = _First2[_Idx]; + } + + return _First1; + } +#endif // __cpp_lib_is_constant_evaluated + + _CSTD memcpy(_First1, _First2, _Count * sizeof(_Elem)); +#endif // ^^^ !_HAS_MEMCPY_MEMMOVE_INTRINSICS ^^^ + + return _First1; + } + + _Pre_satisfies_(_Dest_size >= _Count) static _Elem* _Copy_s(_Out_writes_all_(_Dest_size) _Elem* const _First1, + const size_t _Dest_size, _In_reads_(_Count) const _Elem* const _First2, + const size_t _Count) noexcept { // copy [_First2, _First2 + _Count) to [_First1, _First1 + _Dest_size) + _STL_VERIFY(_Count <= _Dest_size, "invalid argument"); + return copy(_First1, _First2, _Count); + } + + static _CONSTEXPR20 _Elem* move(_Out_writes_all_(_Count) _Elem* const _First1, + _In_reads_(_Count) const _Elem* const _First2, const size_t _Count) noexcept /* strengthened */ { + // copy [_First2, _First2 + _Count) to [_First1, ...), allowing overlap +#if _HAS_MEMCPY_MEMMOVE_INTRINSICS + __builtin_memmove(_First1, _First2, _Count * sizeof(_Elem)); +#else // ^^^ _HAS_MEMCPY_MEMMOVE_INTRINSICS ^^^ / vvv !_HAS_MEMCPY_MEMMOVE_INTRINSICS vvv +#ifdef __cpp_lib_is_constant_evaluated + if (_STD is_constant_evaluated()) { + // dest: [_First1, _First1 + _Count) + // src: [_First2, _First2 + _Count) + // We need to handle overlapping ranges. + // If _First1 is in the src range, we need a backward loop. + // Otherwise, the forward loop works (even if the back of dest overlaps the front of src). + + if (_First1 == _First2) { + return _First1; // Self-assignment; either loop would work, but returning immediately is faster. + } + + // Usually, we would compare pointers with less-than, even though they could belong to different arrays. + // However, we're not allowed to do that during constant evaluation, so we need a linear scan for equality. + bool _Loop_forward = true; + + for (const _Elem* _Src = _First2; _Src != _First2 + _Count; ++_Src) { + if (_First1 == _Src) { + _Loop_forward = false; + break; + } + } + + if (_Loop_forward) { + for (size_t _Idx = 0; _Idx < _Count; ++_Idx) { + _First1[_Idx] = _First2[_Idx]; + } + } else { + for (size_t _Idx = 0; _Idx < _Count; ++_Idx) { + _First1[_Count - 1 - _Idx] = _First2[_Count - 1 - _Idx]; + } + } + + return _First1; + } +#endif // __cpp_lib_is_constant_evaluated + + _CSTD memmove(_First1, _First2, _Count * sizeof(_Elem)); +#endif // ^^^ !_HAS_MEMCPY_MEMMOVE_INTRINSICS ^^^ + + return _First1; + } + + // For compare/length/find/assign, we can't uniformly call CRT functions (or their builtin versions). + // 8-bit: memcmp/strlen/memchr/memset; 16-bit: wmemcmp/wcslen/wmemchr/wmemset; 32-bit: nonexistent + _NODISCARD static _CONSTEXPR17 int compare(_In_reads_(_Count) const _Elem* _First1, _In_reads_(_Count) const _Elem* _First2, size_t _Count) noexcept /* strengthened */ { // compare [_First1, _First1 + _Count) with [_First2, ...) @@ -57,19 +147,6 @@ struct _Char_traits { // properties of a string or stream element return _Count; } - static _Elem* copy(_Out_writes_all_(_Count) _Elem* const _First1, _In_reads_(_Count) const _Elem* _First2, - size_t _Count) noexcept /* strengthened */ { - // copy [_First2, _First2 + _Count) to [_First1, ...) - return static_cast<_Elem*>(_CSTD memcpy(_First1, _First2, _Count * sizeof(_Elem))); - } - - _Pre_satisfies_(_Dest_size >= _Count) static _Elem* _Copy_s(_Out_writes_all_(_Dest_size) _Elem* const _First1, - const size_t _Dest_size, _In_reads_(_Count) const _Elem* const _First2, - const size_t _Count) noexcept { // copy [_First2, _First2 + _Count) to [_First1, _First1 + _Dest_size) - _STL_VERIFY(_Count <= _Dest_size, "invalid argument"); - return copy(_First1, _First2, _Count); - } - _NODISCARD static _CONSTEXPR17 const _Elem* find( _In_reads_(_Count) const _Elem* _First, size_t _Count, const _Elem& _Ch) noexcept /* strengthened */ { // look for _Ch in [_First, _First + _Count) @@ -82,17 +159,11 @@ struct _Char_traits { // properties of a string or stream element return nullptr; } - static _Elem* move(_Out_writes_all_(_Count) _Elem* const _First1, _In_reads_(_Count) const _Elem* _First2, - size_t _Count) noexcept /* strengthened */ { - // copy [_First2, _First2 + _Count) to [_First1, ...), allowing overlap - return static_cast<_Elem*>(_CSTD memmove(_First1, _First2, _Count * sizeof(_Elem))); - } - - static _Elem* assign(_Out_writes_all_(_Count) _Elem* const _First, size_t _Count, const _Elem _Ch) noexcept + static _CONSTEXPR20 _Elem* assign( + _Out_writes_all_(_Count) _Elem* const _First, size_t _Count, const _Elem _Ch) noexcept /* strengthened */ { // assign _Count * _Ch to [_First, ...) - _Elem* _Next = _First; - for (; 0 < _Count; --_Count, ++_Next) { + for (_Elem* _Next = _First; _Count > 0; --_Count, ++_Next) { *_Next = _Ch; } @@ -134,13 +205,22 @@ struct _Char_traits { // properties of a string or stream element // STRUCT TEMPLATE _WChar_traits template -struct _WChar_traits { // char_traits for the char16_t-likes: char16_t, wchar_t, unsigned short +struct _WChar_traits : private _Char_traits<_Elem, unsigned short> { + // char_traits for the char16_t-likes: char16_t, wchar_t, unsigned short +private: + using _Primary_char_traits = _Char_traits<_Elem, unsigned short>; + +public: using char_type = _Elem; using int_type = unsigned short; using pos_type = streampos; using off_type = streamoff; using state_type = mbstate_t; + using _Primary_char_traits::_Copy_s; + using _Primary_char_traits::copy; + using _Primary_char_traits::move; + _NODISCARD static _CONSTEXPR17 int compare(_In_reads_(_Count) const _Elem* const _First1, _In_reads_(_Count) const _Elem* const _First2, const size_t _Count) noexcept /* strengthened */ { // compare [_First1, _First1 + _Count) with [_First2, ...) @@ -148,7 +228,7 @@ struct _WChar_traits { // char_traits for the char16_t-likes: char16_t, wchar_t, if constexpr (is_same_v<_Elem, wchar_t>) { return __builtin_wmemcmp(_First1, _First2, _Count); } else { - return _Char_traits<_Elem, unsigned short>::compare(_First1, _First2, _Count); + return _Primary_char_traits::compare(_First1, _First2, _Count); } #else // _HAS_CXX17 return _CSTD wmemcmp( @@ -162,28 +242,13 @@ struct _WChar_traits { // char_traits for the char16_t-likes: char16_t, wchar_t, if constexpr (is_same_v<_Elem, wchar_t>) { return __builtin_wcslen(_First); } else { - return _Char_traits<_Elem, unsigned short>::length(_First); + return _Primary_char_traits::length(_First); } #else // _HAS_CXX17 return _CSTD wcslen(reinterpret_cast(_First)); #endif // _HAS_CXX17 } - static _Elem* copy(_Out_writes_all_(_Count) _Elem* const _First1, _In_reads_(_Count) const _Elem* const _First2, - const size_t _Count) noexcept /* strengthened */ { - // copy [_First2, _First2 + _Count) to [_First1, ...) - return reinterpret_cast<_Elem*>( - _CSTD wmemcpy(reinterpret_cast(_First1), reinterpret_cast(_First2), _Count)); - } - - _Pre_satisfies_(_Size_in_words >= _Count) static _Elem* _Copy_s(_Out_writes_all_(_Size_in_words) - _Elem* const _First1, - const size_t _Size_in_words, _In_reads_(_Count) const _Elem* const _First2, - const size_t _Count) noexcept { // copy [_First2, _First2 + _Count) to [_First1, ...) - _STL_VERIFY(_Count <= _Size_in_words, "invalid argument"); - return copy(_First1, _First2, _Count); - } - _NODISCARD static _CONSTEXPR17 const _Elem* find( _In_reads_(_Count) const _Elem* _First, const size_t _Count, const _Elem& _Ch) noexcept /* strengthened */ { // look for _Ch in [_First, _First + _Count) @@ -191,23 +256,23 @@ struct _WChar_traits { // char_traits for the char16_t-likes: char16_t, wchar_t, if constexpr (is_same_v<_Elem, wchar_t>) { return __builtin_wmemchr(_First, _Ch, _Count); } else { - return _Char_traits<_Elem, unsigned short>::find(_First, _Count, _Ch); + return _Primary_char_traits::find(_First, _Count, _Ch); } #else // _HAS_CXX17 return reinterpret_cast(_CSTD wmemchr(reinterpret_cast(_First), _Ch, _Count)); #endif // _HAS_CXX17 } - static _Elem* move(_Out_writes_all_(_Count) _Elem* const _First1, _In_reads_(_Count) const _Elem* const _First2, - const size_t _Count) noexcept /* strengthened */ { - // copy [_First2, _First2 + _Count) to [_First1, ...) - return reinterpret_cast<_Elem*>( - _CSTD wmemmove(reinterpret_cast(_First1), reinterpret_cast(_First2), _Count)); - } - - static _Elem* assign(_Out_writes_all_(_Count) _Elem* const _First, size_t _Count, _Elem _Ch) noexcept + static _CONSTEXPR20 _Elem* assign( + _Out_writes_all_(_Count) _Elem* const _First, size_t _Count, const _Elem _Ch) noexcept /* strengthened */ { // assign _Count * _Ch to [_First, ...) +#ifdef __cpp_lib_is_constant_evaluated + if (_STD is_constant_evaluated()) { + return _Primary_char_traits::assign(_First, _Count, _Ch); + } +#endif // __cpp_lib_is_constant_evaluated + return reinterpret_cast<_Elem*>(_CSTD wmemset(reinterpret_cast(_First), _Ch, _Count)); } @@ -278,13 +343,22 @@ struct char_traits : _WChar_traits {}; // STRUCT TEMPLATE _Narrow_char_traits template -struct _Narrow_char_traits { // Implement char_traits for narrow character types char and char8_t +struct _Narrow_char_traits : private _Char_traits<_Elem, _Int_type> { + // Implement char_traits for narrow character types char and char8_t +private: + using _Primary_char_traits = _Char_traits<_Elem, _Int_type>; + +public: using char_type = _Elem; using int_type = _Int_type; using pos_type = streampos; using off_type = streamoff; using state_type = mbstate_t; + using _Primary_char_traits::_Copy_s; + using _Primary_char_traits::copy; + using _Primary_char_traits::move; + _NODISCARD static _CONSTEXPR17 int compare(_In_reads_(_Count) const _Elem* const _First1, _In_reads_(_Count) const _Elem* const _First2, const size_t _Count) noexcept /* strengthened */ { // compare [_First1, _First1 + _Count) with [_First2, ...) @@ -310,7 +384,7 @@ struct _Narrow_char_traits { // Implement char_traits for narrow character types #if _HAS_U8_INTRINSICS return __builtin_u8strlen(_First); #else // ^^^ use u8 intrinsics / no u8 intrinsics vvv - return _Char_traits<_Elem, _Int_type>::length(_First); + return _Primary_char_traits::length(_First); #endif // _HAS_U8_INTRINSICS } else #endif // __cpp_char8_t @@ -322,20 +396,6 @@ struct _Narrow_char_traits { // Implement char_traits for narrow character types #endif // _HAS_CXX17 } - static _Elem* copy(_Out_writes_(_Count) _Elem* const _First1, _In_reads_(_Count) const _Elem* const _First2, - const size_t _Count) noexcept /* strengthened */ { - // copy [_First2, _First2 + _Count) to [_First1, ...) - return static_cast<_Elem*>(_CSTD memcpy(_First1, _First2, _Count)); - } - - _Pre_satisfies_(_Size_in_bytes >= _Count) static _Elem* _Copy_s(_Out_writes_all_(_Size_in_bytes) - _Elem* const _First1, - const size_t _Size_in_bytes, _In_reads_(_Count) const _Elem* const _First2, const size_t _Count) noexcept { - // copy [_First2, _First2 + _Count) to [_First1, ...) - _STL_VERIFY(_Count <= _Size_in_bytes, "invalid argument"); - return copy(_First1, _First2, _Count); - } - _NODISCARD static _CONSTEXPR17 const _Elem* find(_In_reads_(_Count) const _Elem* const _First, const size_t _Count, const _Elem& _Ch) noexcept /* strengthened */ { // look for _Ch in [_First, _First + _Count) @@ -345,7 +405,7 @@ struct _Narrow_char_traits { // Implement char_traits for narrow character types #if _HAS_U8_INTRINSICS return __builtin_u8memchr(_First, _Ch, _Count); #else // ^^^ use u8 intrinsics / no u8 intrinsics vvv - return _Char_traits<_Elem, _Int_type>::find(_First, _Count, _Ch); + return _Primary_char_traits::find(_First, _Count, _Ch); #endif // _HAS_U8_INTRINSICS } else #endif // __cpp_char8_t @@ -357,15 +417,16 @@ struct _Narrow_char_traits { // Implement char_traits for narrow character types #endif // _HAS_CXX17 } - static _Elem* move(_Out_writes_all_(_Count) _Elem* const _First1, _In_reads_(_Count) const _Elem* const _First2, - const size_t _Count) noexcept /* strengthened */ { - // copy [_First2, _First2 + _Count) to [_First1, ...) - return static_cast<_Elem*>(_CSTD memmove(_First1, _First2, _Count)); - } - - static _Elem* assign(_Out_writes_all_(_Count) _Elem* const _First, const size_t _Count, const _Elem _Ch) noexcept + static _CONSTEXPR20 _Elem* assign( + _Out_writes_all_(_Count) _Elem* const _First, size_t _Count, const _Elem _Ch) noexcept /* strengthened */ { // assign _Count * _Ch to [_First, ...) +#ifdef __cpp_lib_is_constant_evaluated + if (_STD is_constant_evaluated()) { + return _Primary_char_traits::assign(_First, _Count, _Ch); + } +#endif // __cpp_lib_is_constant_evaluated + return static_cast<_Elem*>(_CSTD memset(_First, _Ch, _Count)); } @@ -403,6 +464,7 @@ struct _Narrow_char_traits { // Implement char_traits for narrow character types }; #undef _HAS_U8_INTRINSICS +#undef _HAS_MEMCPY_MEMMOVE_INTRINSICS // STRUCT char_traits (FROM ) template <> @@ -1301,7 +1363,8 @@ public: *this = _Tmp; } - constexpr size_type copy(_Out_writes_(_Count) _Elem* const _Ptr, size_type _Count, const size_type _Off = 0) const { + _CONSTEXPR20 size_type copy( + _Out_writes_(_Count) _Elem* const _Ptr, size_type _Count, const size_type _Off = 0) const { // copy [_Off, _Off + Count) to [_Ptr, _Ptr + _Count) _Check_offset(_Off); _Count = _Clamp_suffix_size(_Off, _Count); diff --git a/stl/inc/yvals_core.h b/stl/inc/yvals_core.h index c760ab29804..3b581162cc8 100644 --- a/stl/inc/yvals_core.h +++ b/stl/inc/yvals_core.h @@ -175,6 +175,7 @@ // P1006R1 constexpr For pointer_traits::pointer_to() // P1023R0 constexpr For std::array Comparisons // P1024R3 Enhancing span Usability +// P1032R1 Miscellaneous constexpr // P1085R2 Removing span Comparisons // P1115R3 erase()/erase_if() Return size_type // P1207R4 Movability Of Single-Pass Iterators @@ -1153,10 +1154,15 @@ #define __cpp_lib_concepts 201907L #endif // defined(__cpp_concepts) && __cpp_concepts > 201507L -#define __cpp_lib_constexpr_algorithms 201806L -#define __cpp_lib_constexpr_complex 201711L -#define __cpp_lib_constexpr_memory 201811L -#define __cpp_lib_constexpr_numeric 201911L +#define __cpp_lib_constexpr_algorithms 201806L +#define __cpp_lib_constexpr_complex 201711L +#define __cpp_lib_constexpr_functional 201811L +#define __cpp_lib_constexpr_iterator 201811L +#define __cpp_lib_constexpr_memory 201811L +#define __cpp_lib_constexpr_numeric 201911L +#define __cpp_lib_constexpr_string_view 201811L +#define __cpp_lib_constexpr_tuple 201811L +#define __cpp_lib_constexpr_utility 201811L #ifdef __cpp_impl_destroying_delete #define __cpp_lib_destroying_delete 201806L @@ -1187,7 +1193,7 @@ #endif // _HAS_CXX20 #if _HAS_CXX20 -#define __cpp_lib_array_constexpr 201806L // P1023R0 constexpr For std::array Comparisons +#define __cpp_lib_array_constexpr 201811L // P1032R1 Miscellaneous constexpr #elif _HAS_CXX17 // ^^^ _HAS_CXX20 / _HAS_CXX17 vvv #define __cpp_lib_array_constexpr 201803L #endif // _HAS_CXX17 diff --git a/tests/libcxx/expected_results.txt b/tests/libcxx/expected_results.txt index 9d79b863401..beea762b739 100644 --- a/tests/libcxx/expected_results.txt +++ b/tests/libcxx/expected_results.txt @@ -54,6 +54,7 @@ std/language.support/support.limits/support.limits.general/istream.version.pass. std/language.support/support.limits/support.limits.general/limits.version.pass.cpp FAIL std/language.support/support.limits/support.limits.general/locale.version.pass.cpp FAIL std/language.support/support.limits/support.limits.general/ostream.version.pass.cpp FAIL +std/language.support/support.limits/support.limits.general/string_view.version.pass.cpp FAIL # libc++ doesn't yet implement P1956R1, so it expects the old names `ispow2`, `ceil2`, `floor2`, and `log2p1` std/numerics/bit/bit.pow.two/ceil2.pass.cpp FAIL @@ -481,29 +482,6 @@ std/language.support/support.limits/support.limits.general/functional.version.pa std/language.support/support.limits/support.limits.general/iterator.version.pass.cpp FAIL std/language.support/support.limits/support.limits.general/memory.version.pass.cpp FAIL -# C++20 P1032R1 "Miscellaneous constexpr" -std/language.support/support.limits/support.limits.general/array.version.pass.cpp FAIL -std/language.support/support.limits/support.limits.general/functional.version.pass.cpp FAIL -std/language.support/support.limits/support.limits.general/iterator.version.pass.cpp FAIL -std/language.support/support.limits/support.limits.general/string_view.version.pass.cpp FAIL -std/language.support/support.limits/support.limits.general/tuple.version.pass.cpp FAIL -std/language.support/support.limits/support.limits.general/utility.version.pass.cpp FAIL -std/strings/char.traits/char.traits.specializations/char.traits.specializations.char/assign3.pass.cpp FAIL -std/strings/char.traits/char.traits.specializations/char.traits.specializations.char/copy.pass.cpp FAIL -std/strings/char.traits/char.traits.specializations/char.traits.specializations.char/move.pass.cpp FAIL -std/strings/char.traits/char.traits.specializations/char.traits.specializations.char16_t/assign3.pass.cpp FAIL -std/strings/char.traits/char.traits.specializations/char.traits.specializations.char16_t/copy.pass.cpp FAIL -std/strings/char.traits/char.traits.specializations/char.traits.specializations.char16_t/move.pass.cpp FAIL -std/strings/char.traits/char.traits.specializations/char.traits.specializations.char32_t/assign3.pass.cpp FAIL -std/strings/char.traits/char.traits.specializations/char.traits.specializations.char32_t/copy.pass.cpp FAIL -std/strings/char.traits/char.traits.specializations/char.traits.specializations.char32_t/move.pass.cpp FAIL -std/strings/char.traits/char.traits.specializations/char.traits.specializations.char8_t/assign3.pass.cpp FAIL -std/strings/char.traits/char.traits.specializations/char.traits.specializations.char8_t/copy.pass.cpp FAIL -std/strings/char.traits/char.traits.specializations/char.traits.specializations.char8_t/move.pass.cpp FAIL -std/strings/char.traits/char.traits.specializations/char.traits.specializations.wchar.t/assign3.pass.cpp FAIL -std/strings/char.traits/char.traits.specializations/char.traits.specializations.wchar.t/copy.pass.cpp FAIL -std/strings/char.traits/char.traits.specializations/char.traits.specializations.wchar.t/move.pass.cpp FAIL - # C++20 P1135R6 "The C++20 Synchronization Library" std/atomics/atomics.types.operations/atomics.types.operations.wait/atomic_wait.pass.cpp FAIL std/thread/thread.barrier/arrive.pass.cpp FAIL @@ -700,6 +678,15 @@ std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.asgn/move.pass.cpp # Test bug after LWG-3257 "Missing feature testing macro update from P0858" was accepted. std/language.support/support.limits/support.limits.general/string.version.pass.cpp FAIL +# libc++ expects an old value for `__cpp_lib_array_constexpr` (`201603L`). We've implemented P0858R0, P1023R0, and P1032R1, increasing the value to `201811L`. +std/language.support/support.limits/support.limits.general/array.version.pass.cpp FAIL + +# libc++ expects the old macro `__cpp_lib_constexpr_misc`. After P1902R1, it should expect `__cpp_lib_constexpr_tuple` to have the value `201811L`. +std/language.support/support.limits/support.limits.general/tuple.version.pass.cpp FAIL + +# libc++ expects the old macro `__cpp_lib_constexpr_misc`. After P1902R1, it should expect `__cpp_lib_constexpr_utility` to have the value `201811L`. +std/language.support/support.limits/support.limits.general/utility.version.pass.cpp FAIL + # Not yet analyzed, likely bogus tests. Appears to be timing assumptions. std/thread/futures/futures.async/async.pass.cpp SKIPPED std/thread/futures/futures.shared_future/get.pass.cpp SKIPPED diff --git a/tests/libcxx/skipped_tests.txt b/tests/libcxx/skipped_tests.txt index 1e43a4bda54..0912d0ae78f 100644 --- a/tests/libcxx/skipped_tests.txt +++ b/tests/libcxx/skipped_tests.txt @@ -54,6 +54,7 @@ language.support\support.limits\support.limits.general\istream.version.pass.cpp language.support\support.limits\support.limits.general\limits.version.pass.cpp language.support\support.limits\support.limits.general\locale.version.pass.cpp language.support\support.limits\support.limits.general\ostream.version.pass.cpp +language.support\support.limits\support.limits.general\string_view.version.pass.cpp # libc++ doesn't yet implement P1956R1, so it expects the old names `ispow2`, `ceil2`, `floor2`, and `log2p1` numerics\bit\bit.pow.two\ceil2.pass.cpp @@ -481,29 +482,6 @@ language.support\support.limits\support.limits.general\functional.version.pass.c language.support\support.limits\support.limits.general\iterator.version.pass.cpp language.support\support.limits\support.limits.general\memory.version.pass.cpp -# C++20 P1032R1 "Miscellaneous constexpr" -language.support\support.limits\support.limits.general\array.version.pass.cpp -language.support\support.limits\support.limits.general\functional.version.pass.cpp -language.support\support.limits\support.limits.general\iterator.version.pass.cpp -language.support\support.limits\support.limits.general\string_view.version.pass.cpp -language.support\support.limits\support.limits.general\tuple.version.pass.cpp -language.support\support.limits\support.limits.general\utility.version.pass.cpp -strings\char.traits\char.traits.specializations\char.traits.specializations.char\assign3.pass.cpp -strings\char.traits\char.traits.specializations\char.traits.specializations.char\copy.pass.cpp -strings\char.traits\char.traits.specializations\char.traits.specializations.char\move.pass.cpp -strings\char.traits\char.traits.specializations\char.traits.specializations.char16_t\assign3.pass.cpp -strings\char.traits\char.traits.specializations\char.traits.specializations.char16_t\copy.pass.cpp -strings\char.traits\char.traits.specializations\char.traits.specializations.char16_t\move.pass.cpp -strings\char.traits\char.traits.specializations\char.traits.specializations.char32_t\assign3.pass.cpp -strings\char.traits\char.traits.specializations\char.traits.specializations.char32_t\copy.pass.cpp -strings\char.traits\char.traits.specializations\char.traits.specializations.char32_t\move.pass.cpp -strings\char.traits\char.traits.specializations\char.traits.specializations.char8_t\assign3.pass.cpp -strings\char.traits\char.traits.specializations\char.traits.specializations.char8_t\copy.pass.cpp -strings\char.traits\char.traits.specializations\char.traits.specializations.char8_t\move.pass.cpp -strings\char.traits\char.traits.specializations\char.traits.specializations.wchar.t\assign3.pass.cpp -strings\char.traits\char.traits.specializations\char.traits.specializations.wchar.t\copy.pass.cpp -strings\char.traits\char.traits.specializations\char.traits.specializations.wchar.t\move.pass.cpp - # C++20 P1135R6 "The C++20 Synchronization Library" atomics\atomics.types.operations\atomics.types.operations.wait\atomic_wait.pass.cpp thread\thread.barrier\arrive.pass.cpp @@ -700,6 +678,15 @@ utilities\smartptr\unique.ptr\unique.ptr.class\unique.ptr.asgn\move.pass.cpp # Test bug after LWG-3257 "Missing feature testing macro update from P0858" was accepted. language.support\support.limits\support.limits.general\string.version.pass.cpp +# libc++ expects an old value for `__cpp_lib_array_constexpr` (`201603L`). We've implemented P0858R0, P1023R0, and P1032R1, increasing the value to `201811L`. +language.support\support.limits\support.limits.general\array.version.pass.cpp + +# libc++ expects the old macro `__cpp_lib_constexpr_misc`. After P1902R1, it should expect `__cpp_lib_constexpr_tuple` to have the value `201811L`. +language.support\support.limits\support.limits.general\tuple.version.pass.cpp + +# libc++ expects the old macro `__cpp_lib_constexpr_misc`. After P1902R1, it should expect `__cpp_lib_constexpr_utility` to have the value `201811L`. +language.support\support.limits\support.limits.general\utility.version.pass.cpp + # Not yet analyzed, likely bogus tests. Appears to be timing assumptions. thread\futures\futures.async\async.pass.cpp thread\futures\futures.shared_future\get.pass.cpp diff --git a/tests/std/test.lst b/tests/std/test.lst index 88fafc09c47..22dcdf0b815 100644 --- a/tests/std/test.lst +++ b/tests/std/test.lst @@ -258,6 +258,7 @@ tests\P0898R3_identity tests\P0919R3_heterogeneous_unordered_lookup tests\P0966R1_string_reserve_should_not_shrink tests\P1023R0_constexpr_for_array_comparisons +tests\P1032R1_miscellaneous_constexpr tests\P1135R6_atomic_flag_test tests\P1165R1_consistently_propagating_stateful_allocators tests\P1423R3_char8_t_remediation diff --git a/tests/std/tests/Dev11_0343056_pair_tuple_ctor_sfinae/test.cpp b/tests/std/tests/Dev11_0343056_pair_tuple_ctor_sfinae/test.cpp index e6c4cd92efd..7f29c9e1519 100644 --- a/tests/std/tests/Dev11_0343056_pair_tuple_ctor_sfinae/test.cpp +++ b/tests/std/tests/Dev11_0343056_pair_tuple_ctor_sfinae/test.cpp @@ -142,12 +142,14 @@ void test_alloc() { // template tuple(allocator_arg_t, const Alloc& a); tuple t1(allocator_arg, al); + (void) t1; // template tuple(allocator_arg_t, const Alloc& a, const Types&...); tuple t2(allocator_arg, al, 0); // template tuple(allocator_arg_t, const Alloc& a, const UTypes&&...); tuple t3(allocator_arg, al, nullptr); + (void) t3; // template tuple(allocator_arg_t, const Alloc& a, const tuple&); tuple t4(allocator_arg, al, t2); diff --git a/tests/std/tests/P0220R1_string_view/test.cpp b/tests/std/tests/P0220R1_string_view/test.cpp index 60b0cef4ae3..07d122bc42d 100644 --- a/tests/std/tests/P0220R1_string_view/test.cpp +++ b/tests/std/tests/P0220R1_string_view/test.cpp @@ -1034,11 +1034,11 @@ static_assert(test_case_iterators()); static_assert(test_case_prefix()); static_assert(test_case_suffix()); static_assert(test_case_swap()); -static_assert(test_case_copy()); static_assert(test_case_Copy_s()); static_assert(test_case_substr()); static_assert(test_case_compare()); #if _HAS_CXX20 +static_assert(test_case_copy()); static_assert(test_case_starts_with_ends_with()); #endif // _HAS_CXX20 static_assert(test_case_operators()); diff --git a/tests/std/tests/P1032R1_miscellaneous_constexpr/env.lst b/tests/std/tests/P1032R1_miscellaneous_constexpr/env.lst new file mode 100644 index 00000000000..642f530ffad --- /dev/null +++ b/tests/std/tests/P1032R1_miscellaneous_constexpr/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\usual_latest_matrix.lst diff --git a/tests/std/tests/P1032R1_miscellaneous_constexpr/test.cpp b/tests/std/tests/P1032R1_miscellaneous_constexpr/test.cpp new file mode 100644 index 00000000000..7ba268e9604 --- /dev/null +++ b/tests/std/tests/P1032R1_miscellaneous_constexpr/test.cpp @@ -0,0 +1,499 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +struct constexpr_container { + using value_type = int; + using iterator = array::iterator; + + array buffer{}; + size_t selected = 0; + + // Test back_insert_iterator + constexpr void push_back(const value_type i) { + buffer[selected++] = i; + } + + // Test front_insert_iterator + constexpr void push_front(const value_type i) { + buffer[selected++] = i; + } + + // Test insert_iterator + constexpr iterator insert(iterator where, const value_type i) { + *where = i; + return where; + } + + // Fake begin to ensure that we insert at the correct position for insert_iterator + constexpr iterator begin() { + return next(buffer.begin()); + } +}; + +constexpr bool run_tests() { + // test pair piecewise constructor + { + const tuple t1{1, 2, 0.5, 1.5}; + const tuple t2{2.5, 3}; + const pair, tuple> meow{piecewise_construct, t1, t2}; + assert(meow.first == t1); + assert(meow.second == t2); + } + + // test pair assignment operator + { + pair input{1, 2}; + pair copyAssignment{}; + copyAssignment = input; + assert(copyAssignment.first == 1); + assert(copyAssignment.second == 2); + + pair moveAssignment{}; + moveAssignment = move(input); + assert(moveAssignment.first == 1); + assert(moveAssignment.second == 2); + + pair copyAssignmentConvertible{}; + copyAssignmentConvertible = copyAssignment; + assert(copyAssignmentConvertible.first == 1.0); + assert(copyAssignmentConvertible.second == 2.0); + + pair moveAssignmentConvertible{}; + moveAssignmentConvertible = move(moveAssignment); + assert(moveAssignmentConvertible.first == 1.0); + assert(moveAssignmentConvertible.second == 2.0); + } + + // test pair swap + { + pair pair1{1, 2}; + pair pair2{3, 4}; + + swap(pair1, pair2); + assert(pair1.first == 3 && pair1.second == 4 && pair2.first == 1 && pair2.second == 2); + + pair1.swap(pair2); + assert(pair1.first == 1 && pair1.second == 2 && pair2.first == 3 && pair2.second == 4); + } + + // test empty tuple + { + allocator alloc; + tuple<> tuple_alloc{allocator_arg, alloc}; + tuple<> tuple_alloc_copy{allocator_arg, alloc, tuple_alloc}; + tuple<> tuple_alloc_move{allocator_arg, alloc, move(tuple_alloc)}; + + tuple_alloc_copy = tuple_alloc; + tuple_alloc_move = move(tuple_alloc); + + swap(tuple_alloc, tuple_alloc_copy); + tuple_alloc.swap(tuple_alloc_copy); + } + + // test tuple + { + allocator alloc; + tuple conversionInput{static_cast(1), 2}; + const tuple constConversionInput{static_cast(3), 4}; + pair conversionInputPair{static_cast(5), 6}; + const pair constConversionInputPair{static_cast(7), 8}; + + tuple tuple_alloc{allocator_arg, alloc}; + assert(get<0>(tuple_alloc) == 0); + assert(get<1>(tuple_alloc) == 0.0); + + tuple tuple_alloc_non_forwarding_value{allocator_arg, alloc, {}, {}}; + assert(get<0>(tuple_alloc_non_forwarding_value) == 0); + assert(get<1>(tuple_alloc_non_forwarding_value) == 0.0); + + tuple tuple_alloc_value{allocator_arg, alloc, 9, 9.5}; + assert(get<0>(tuple_alloc_value) == 9); + assert(get<1>(tuple_alloc_value) == 9.5); + + tuple tuple_alloc_copy{allocator_arg, alloc, tuple_alloc}; + assert(get<0>(tuple_alloc_copy) == 0); + assert(get<1>(tuple_alloc_copy) == 0.0); + + tuple tuple_alloc_move{allocator_arg, alloc, move(tuple_alloc)}; + assert(get<0>(tuple_alloc_move) == 0); + assert(get<1>(tuple_alloc_move) == 0.0); + + tuple tuple_alloc_conversion{allocator_arg, alloc, static_cast(11), 22}; + assert(get<0>(tuple_alloc_conversion) == 11); + assert(get<1>(tuple_alloc_conversion) == 22.0); + + tuple tuple_alloc_conversion_tuple{allocator_arg, alloc, move(conversionInput)}; + assert(get<0>(tuple_alloc_conversion_tuple) == 1); + assert(get<1>(tuple_alloc_conversion_tuple) == 2.0); + + tuple tuple_alloc_conversion_const_tuple{allocator_arg, alloc, constConversionInput}; + assert(get<0>(tuple_alloc_conversion_const_tuple) == 3); + assert(get<1>(tuple_alloc_conversion_const_tuple) == 4.0); + + tuple tuple_alloc_conversion_pair{allocator_arg, alloc, move(conversionInputPair)}; + assert(get<0>(tuple_alloc_conversion_pair) == 5); + assert(get<1>(tuple_alloc_conversion_pair) == 6.0); + + tuple tuple_alloc_conversion_const_pair{allocator_arg, alloc, constConversionInputPair}; + assert(get<0>(tuple_alloc_conversion_const_pair) == 7); + assert(get<1>(tuple_alloc_conversion_const_pair) == 8.0); + + tuple tuple_assign{}; + + tuple_assign = tuple_alloc_value; + assert(get<0>(tuple_assign) == 9); + assert(get<1>(tuple_assign) == 9.5); + + tuple_assign = move(tuple_alloc); + assert(get<0>(tuple_assign) == 0); + assert(get<1>(tuple_assign) == 0.0); + + tuple_assign = move(conversionInput); + assert(get<0>(tuple_assign) == 1); + assert(get<1>(tuple_assign) == 2.0); + + tuple_assign = constConversionInput; + assert(get<0>(tuple_assign) == 3); + assert(get<1>(tuple_assign) == 4.0); + + tuple_assign = move(conversionInputPair); + assert(get<0>(tuple_assign) == 5); + assert(get<1>(tuple_assign) == 6.0); + + tuple_assign = constConversionInputPair; + assert(get<0>(tuple_assign) == 7); + assert(get<1>(tuple_assign) == 8.0); + + tuple x{10, 20.5}; + tuple y{30, 40.5}; + + swap(x, y); + assert(get<0>(x) == 30 && get<1>(x) == 40.5 && get<0>(y) == 10 && get<1>(y) == 20.5); + + x.swap(y); + assert(get<0>(x) == 10 && get<1>(x) == 20.5 && get<0>(y) == 30 && get<1>(y) == 40.5); + } + + // test array swap + { + array array1{{1, 2}}; + array array2{{3, 4}}; + + swap(array1, array2); + assert(array1[0] == 3 && array1[1] == 4 && array2[0] == 1 && array2[1] == 2); + + array1.swap(array2); + assert(array1[0] == 1 && array1[1] == 2 && array2[0] == 3 && array2[1] == 4); + + array array_empty1 = {}; + array array_empty2 = {}; + + swap(array_empty1, array_empty2); + array_empty1.swap(array_empty2); + } + + // test array::fill + { + array meow = {}; + meow.fill(1); + assert(meow[0] == 1 && meow[1] == 1); + + array empty = {}; + empty.fill(1); + } + + // test back_inserter/back_insert_iterator + { + constexpr_container input; + const int toBeCopied = 5; + auto tested = back_inserter(input); + + *tested++ = 42; + *++tested = 1729; + *tested++ = 1234; + tested = 4; + tested = toBeCopied; + + assert(input.buffer[0] == 42 && input.buffer[1] == 1729 && input.buffer[2] == 1234 && input.buffer[3] == 4 + && input.buffer[4] == 5 && input.buffer[5] == 0); + } + + // test front_inserter/front_insert_iterator + { + constexpr_container input; + const int toBeCopied = 5; + auto tested = front_inserter(input); + + *tested++ = 42; + *++tested = 1729; + *tested++ = 1234; + tested = 4; + tested = toBeCopied; + + assert(input.buffer[0] == 42 && input.buffer[1] == 1729 && input.buffer[2] == 1234 && input.buffer[3] == 4 + && input.buffer[4] == 5 && input.buffer[5] == 0); + } + + // test inserter/insert_iterator + { + constexpr_container input; + const int toBeCopied = 5; + auto tested = inserter(input, input.begin()); + + *tested++ = 42; + *++tested = 1729; + *tested++ = 1234; + tested = 4; + tested = toBeCopied; + + assert(input.buffer[0] == 0 && input.buffer[1] == 42 && input.buffer[2] == 1729 && input.buffer[3] == 1234 + && input.buffer[4] == 4 && input.buffer[5] == 5); + } + + // test default_searcher + { + string_view in = "This is some string"; + string_view needle = "some"; + default_searcher meow{needle.begin(), needle.end()}; + auto [first, last] = meow(in.begin(), in.end()); + assert(first - in.begin() == 8); + assert(last - first == static_cast(needle.size())); + } + + // test char_traits move/copy/assign and basic_string_view::copy + { + using Elem = char; + using Traits = char_traits; + + const Elem src[20]{"cute fluffy KITTENS"}; + Elem buf[20]{"hungry evil ZOMBIES"}; + assert(buf == "hungry evil ZOMBIES"sv); + + assert(Traits::copy(buf, src, 12) == buf); + assert(buf == "cute fluffy ZOMBIES"sv); + + assert(Traits::assign(buf, 4, '1') == buf); + assert(buf == "1111 fluffy ZOMBIES"sv); + + assert(Traits::move(buf, src, 19) == buf); // different arrays + assert(buf == "cute fluffy KITTENS"sv); + + assert(Traits::move(buf, buf, 19) == buf); // self-assignment + assert(buf == "cute fluffy KITTENS"sv); + + assert(Traits::move(buf + 5, buf + 12, 6) == buf + 5); // non-overlapping + assert(buf == "cute KITTEN KITTENS"sv); + + const auto sv = "..........abc......"sv; + assert(sv.copy(buf, 4, 10) == 4); + assert(buf == "abc. KITTEN KITTENS"sv); + + assert(sv.copy(buf, 19) == 19); + assert(buf == "..........abc......"sv); + + assert(Traits::move(buf + 8, buf + 10, 2) == buf + 8); // adjacent, dest before src + assert(buf == "........ababc......"sv); + + assert(Traits::move(buf + 13, buf + 9, 4) == buf + 13); // adjacent, dest after src + assert(buf == "........ababcbabc.."sv); + + assert(Traits::move(buf + 4, buf + 8, 10) == buf + 4); // overlapping, dest before src + assert(buf == "....ababcbabc.abc.."sv); + + assert(Traits::move(buf + 5, buf + 3, 11) == buf + 5); // overlapping, dest after src + assert(buf == "....a.ababcbabc.c.."sv); + } + + { + using Elem = char16_t; + using Traits = char_traits; + + const Elem src[20]{u"cute fluffy KITTENS"}; + Elem buf[20]{u"hungry evil ZOMBIES"}; + assert(buf == u"hungry evil ZOMBIES"sv); + + assert(Traits::copy(buf, src, 12) == buf); + assert(buf == u"cute fluffy ZOMBIES"sv); + + assert(Traits::assign(buf, 4, u'1') == buf); + assert(buf == u"1111 fluffy ZOMBIES"sv); + + assert(Traits::move(buf, src, 19) == buf); // different arrays + assert(buf == u"cute fluffy KITTENS"sv); + + assert(Traits::move(buf, buf, 19) == buf); // self-assignment + assert(buf == u"cute fluffy KITTENS"sv); + + assert(Traits::move(buf + 5, buf + 12, 6) == buf + 5); // non-overlapping + assert(buf == u"cute KITTEN KITTENS"sv); + + const auto sv = u"..........abc......"sv; + assert(sv.copy(buf, 4, 10) == 4); + assert(buf == u"abc. KITTEN KITTENS"sv); + + assert(sv.copy(buf, 19) == 19); + assert(buf == u"..........abc......"sv); + + assert(Traits::move(buf + 8, buf + 10, 2) == buf + 8); // adjacent, dest before src + assert(buf == u"........ababc......"sv); + + assert(Traits::move(buf + 13, buf + 9, 4) == buf + 13); // adjacent, dest after src + assert(buf == u"........ababcbabc.."sv); + + assert(Traits::move(buf + 4, buf + 8, 10) == buf + 4); // overlapping, dest before src + assert(buf == u"....ababcbabc.abc.."sv); + + assert(Traits::move(buf + 5, buf + 3, 11) == buf + 5); // overlapping, dest after src + assert(buf == u"....a.ababcbabc.c.."sv); + } + + { + using Elem = char32_t; + using Traits = char_traits; + + const Elem src[20]{U"cute fluffy KITTENS"}; + Elem buf[20]{U"hungry evil ZOMBIES"}; + assert(buf == U"hungry evil ZOMBIES"sv); + + assert(Traits::copy(buf, src, 12) == buf); + assert(buf == U"cute fluffy ZOMBIES"sv); + + assert(Traits::assign(buf, 4, U'1') == buf); + assert(buf == U"1111 fluffy ZOMBIES"sv); + + assert(Traits::move(buf, src, 19) == buf); // different arrays + assert(buf == U"cute fluffy KITTENS"sv); + + assert(Traits::move(buf, buf, 19) == buf); // self-assignment + assert(buf == U"cute fluffy KITTENS"sv); + + assert(Traits::move(buf + 5, buf + 12, 6) == buf + 5); // non-overlapping + assert(buf == U"cute KITTEN KITTENS"sv); + + const auto sv = U"..........abc......"sv; + assert(sv.copy(buf, 4, 10) == 4); + assert(buf == U"abc. KITTEN KITTENS"sv); + + assert(sv.copy(buf, 19) == 19); + assert(buf == U"..........abc......"sv); + + assert(Traits::move(buf + 8, buf + 10, 2) == buf + 8); // adjacent, dest before src + assert(buf == U"........ababc......"sv); + + assert(Traits::move(buf + 13, buf + 9, 4) == buf + 13); // adjacent, dest after src + assert(buf == U"........ababcbabc.."sv); + + assert(Traits::move(buf + 4, buf + 8, 10) == buf + 4); // overlapping, dest before src + assert(buf == U"....ababcbabc.abc.."sv); + + assert(Traits::move(buf + 5, buf + 3, 11) == buf + 5); // overlapping, dest after src + assert(buf == U"....a.ababcbabc.c.."sv); + } + + { + using Elem = wchar_t; + using Traits = char_traits; + + const Elem src[20]{L"cute fluffy KITTENS"}; + Elem buf[20]{L"hungry evil ZOMBIES"}; + assert(buf == L"hungry evil ZOMBIES"sv); + + assert(Traits::copy(buf, src, 12) == buf); + assert(buf == L"cute fluffy ZOMBIES"sv); + + assert(Traits::assign(buf, 4, L'1') == buf); + assert(buf == L"1111 fluffy ZOMBIES"sv); + + assert(Traits::move(buf, src, 19) == buf); // different arrays + assert(buf == L"cute fluffy KITTENS"sv); + + assert(Traits::move(buf, buf, 19) == buf); // self-assignment + assert(buf == L"cute fluffy KITTENS"sv); + + assert(Traits::move(buf + 5, buf + 12, 6) == buf + 5); // non-overlapping + assert(buf == L"cute KITTEN KITTENS"sv); + + const auto sv = L"..........abc......"sv; + assert(sv.copy(buf, 4, 10) == 4); + assert(buf == L"abc. KITTEN KITTENS"sv); + + assert(sv.copy(buf, 19) == 19); + assert(buf == L"..........abc......"sv); + + assert(Traits::move(buf + 8, buf + 10, 2) == buf + 8); // adjacent, dest before src + assert(buf == L"........ababc......"sv); + + assert(Traits::move(buf + 13, buf + 9, 4) == buf + 13); // adjacent, dest after src + assert(buf == L"........ababcbabc.."sv); + + assert(Traits::move(buf + 4, buf + 8, 10) == buf + 4); // overlapping, dest before src + assert(buf == L"....ababcbabc.abc.."sv); + + assert(Traits::move(buf + 5, buf + 3, 11) == buf + 5); // overlapping, dest after src + assert(buf == L"....a.ababcbabc.c.."sv); + } + +#ifdef __cpp_lib_char8_t + { + using Elem = char8_t; + using Traits = char_traits; + + const Elem src[20]{u8"cute fluffy KITTENS"}; + Elem buf[20]{u8"hungry evil ZOMBIES"}; + assert(buf == u8"hungry evil ZOMBIES"sv); + + assert(Traits::copy(buf, src, 12) == buf); + assert(buf == u8"cute fluffy ZOMBIES"sv); + + assert(Traits::assign(buf, 4, u8'1') == buf); + assert(buf == u8"1111 fluffy ZOMBIES"sv); + + assert(Traits::move(buf, src, 19) == buf); // different arrays + assert(buf == u8"cute fluffy KITTENS"sv); + + assert(Traits::move(buf, buf, 19) == buf); // self-assignment + assert(buf == u8"cute fluffy KITTENS"sv); + + assert(Traits::move(buf + 5, buf + 12, 6) == buf + 5); // non-overlapping + assert(buf == u8"cute KITTEN KITTENS"sv); + + const auto sv = u8"..........abc......"sv; + assert(sv.copy(buf, 4, 10) == 4); + assert(buf == u8"abc. KITTEN KITTENS"sv); + + assert(sv.copy(buf, 19) == 19); + assert(buf == u8"..........abc......"sv); + + assert(Traits::move(buf + 8, buf + 10, 2) == buf + 8); // adjacent, dest before src + assert(buf == u8"........ababc......"sv); + + assert(Traits::move(buf + 13, buf + 9, 4) == buf + 13); // adjacent, dest after src + assert(buf == u8"........ababcbabc.."sv); + + assert(Traits::move(buf + 4, buf + 8, 10) == buf + 4); // overlapping, dest before src + assert(buf == u8"....ababcbabc.abc.."sv); + + assert(Traits::move(buf + 5, buf + 3, 11) == buf + 5); // overlapping, dest after src + assert(buf == u8"....a.ababcbabc.c.."sv); + } +#endif // __cpp_lib_char8_t + + return true; +} + +int main() { + static_assert(run_tests()); + assert(run_tests()); +} diff --git a/tests/std/tests/VSO_0000000_instantiate_iterators_misc/test.cpp b/tests/std/tests/VSO_0000000_instantiate_iterators_misc/test.cpp index 8eabd0e936e..4536d8c0fb5 100644 --- a/tests/std/tests/VSO_0000000_instantiate_iterators_misc/test.cpp +++ b/tests/std/tests/VSO_0000000_instantiate_iterators_misc/test.cpp @@ -1484,6 +1484,7 @@ void tuple_test() { tuple<> empty_tuple1(allocator_arg, allocator()); tuple<> empty_tuple2(allocator_arg, allocator(), empty_tuple1); + (void) empty_tuple2; tuple tup1{}; tuple tup2(tup1); diff --git a/tests/std/tests/VSO_0157762_feature_test_macros/test.cpp b/tests/std/tests/VSO_0157762_feature_test_macros/test.cpp index 378511931d1..df60d451449 100644 --- a/tests/std/tests/VSO_0157762_feature_test_macros/test.cpp +++ b/tests/std/tests/VSO_0157762_feature_test_macros/test.cpp @@ -56,10 +56,10 @@ STATIC_ASSERT(__cpp_lib_apply == 201603L); #if _HAS_CXX20 #ifndef __cpp_lib_array_constexpr #error __cpp_lib_array_constexpr is not defined -#elif __cpp_lib_array_constexpr != 201806L -#error __cpp_lib_array_constexpr is not 201806L +#elif __cpp_lib_array_constexpr != 201811L +#error __cpp_lib_array_constexpr is not 201811L #else -STATIC_ASSERT(__cpp_lib_array_constexpr == 201806L); +STATIC_ASSERT(__cpp_lib_array_constexpr == 201811L); #endif #elif _HAS_CXX17 #ifndef __cpp_lib_array_constexpr @@ -355,6 +355,34 @@ STATIC_ASSERT(__cpp_lib_constexpr_complex == 201711L); #endif #endif +#if _HAS_CXX20 +#ifndef __cpp_lib_constexpr_functional +#error __cpp_lib_constexpr_functional is not defined +#elif __cpp_lib_constexpr_functional != 201811L +#error __cpp_lib_constexpr_functional is not 201811L +#else +STATIC_ASSERT(__cpp_lib_constexpr_functional == 201811L); +#endif +#else +#ifdef __cpp_lib_constexpr_functional +#error __cpp_lib_constexpr_functional is defined +#endif +#endif + +#if _HAS_CXX20 +#ifndef __cpp_lib_constexpr_iterator +#error __cpp_lib_constexpr_iterator is not defined +#elif __cpp_lib_constexpr_iterator != 201811L +#error __cpp_lib_constexpr_iterator is not 201811L +#else +STATIC_ASSERT(__cpp_lib_constexpr_iterator == 201811L); +#endif +#else +#ifdef __cpp_lib_constexpr_iterator +#error __cpp_lib_constexpr_iterator is defined +#endif +#endif + #if _HAS_CXX20 #ifndef __cpp_lib_constexpr_memory #error __cpp_lib_constexpr_memory is not defined @@ -383,6 +411,48 @@ STATIC_ASSERT(__cpp_lib_constexpr_numeric == 201911L); #endif #endif +#if _HAS_CXX20 +#ifndef __cpp_lib_constexpr_string_view +#error __cpp_lib_constexpr_string_view is not defined +#elif __cpp_lib_constexpr_string_view != 201811L +#error __cpp_lib_constexpr_string_view is not 201811L +#else +STATIC_ASSERT(__cpp_lib_constexpr_string_view == 201811L); +#endif +#else +#ifdef __cpp_lib_constexpr_string_view +#error __cpp_lib_constexpr_string_view is defined +#endif +#endif + +#if _HAS_CXX20 +#ifndef __cpp_lib_constexpr_tuple +#error __cpp_lib_constexpr_tuple is not defined +#elif __cpp_lib_constexpr_tuple != 201811L +#error __cpp_lib_constexpr_tuple is not 201811L +#else +STATIC_ASSERT(__cpp_lib_constexpr_tuple == 201811L); +#endif +#else +#ifdef __cpp_lib_constexpr_tuple +#error __cpp_lib_constexpr_tuple is defined +#endif +#endif + +#if _HAS_CXX20 +#ifndef __cpp_lib_constexpr_utility +#error __cpp_lib_constexpr_utility is not defined +#elif __cpp_lib_constexpr_utility != 201811L +#error __cpp_lib_constexpr_utility is not 201811L +#else +STATIC_ASSERT(__cpp_lib_constexpr_utility == 201811L); +#endif +#else +#ifdef __cpp_lib_constexpr_utility +#error __cpp_lib_constexpr_utility is defined +#endif +#endif + #if _HAS_CXX20 && defined(__cpp_impl_destroying_delete) // TRANSITION, EDG and VS 2019 16.7p1 #ifndef __cpp_lib_destroying_delete #error __cpp_lib_destroying_delete is not defined