From e4f98aaf5c8ba0e2041880758b75d6b42545ded3 Mon Sep 17 00:00:00 2001 From: Adam Bucior <35536269+AdamBucior@users.noreply.github.com> Date: Fri, 7 Aug 2020 15:37:31 +0200 Subject: [PATCH 01/17] Use memset in a bit more cases --- stl/inc/algorithm | 8 +++-- stl/inc/memory | 8 +++-- stl/inc/xmemory | 8 +++-- stl/inc/xutility | 33 ++++++++++++------- .../tests/P0896R4_ranges_alg_fill/test.cpp | 7 ++++ .../tests/P0896R4_ranges_alg_fill_n/test.cpp | 7 ++++ .../tests/VSO_0180469_fill_family/test.cpp | 30 +++++++++++++++++ 7 files changed, 84 insertions(+), 17 deletions(-) diff --git a/stl/inc/algorithm b/stl/inc/algorithm index c2c80b44701..ce0b3b97849 100644 --- a/stl/inc/algorithm +++ b/stl/inc/algorithm @@ -3993,7 +3993,9 @@ namespace ranges { #endif // __cpp_lib_is_constant_evaluated { const auto _Distance = static_cast(_ULast - _UFirst); - _CSTD memset(_UFirst, static_cast(_Value), _Distance); + using _DestTy = _Iter_value_t; + // first cast _Value to _DestTy in case _DestTy is bool + _CSTD memset(_UFirst, static_cast(static_cast<_DestTy>(_Value)), _Distance); _UFirst += _Distance; _Seek_wrapped(_First, _UFirst); return _First; @@ -4032,7 +4034,9 @@ namespace ranges { if (!_STD is_constant_evaluated()) #endif // __cpp_lib_is_constant_evaluated { - _CSTD memset(_UFirst, static_cast(_Value), static_cast(_Count)); + using _DestTy = _Iter_value_t; + // first cast _Value to _DestTy in case _DestTy is bool + _CSTD memset(_UFirst, static_cast(static_cast<_DestTy>(_Value)), static_cast(_Count)); _UFirst += _Count; _Seek_wrapped(_First, _UFirst); // no need to move since _UFirst is a pointer return _First; diff --git a/stl/inc/memory b/stl/inc/memory index 67b1cc410d3..c610dcaef78 100644 --- a/stl/inc/memory +++ b/stl/inc/memory @@ -134,7 +134,9 @@ _NoThrowFwdIt uninitialized_fill_n(_NoThrowFwdIt _First, const _Diff _Count_raw, if (0 < _Count) { auto _UFirst = _Get_unwrapped_n(_First, _Count); if constexpr (_Fill_memset_is_safe<_Unwrapped_n_t, _Tval>) { - _CSTD memset(_UFirst, static_cast(_Val), _Count); + using _DestTy = _Iter_value_t<_Unwrapped_n_t>; + // first cast _Val to _DestTy in case _DestTy is bool + _CSTD memset(_UFirst, static_cast(static_cast<_DestTy>(_Val)), _Count); _UFirst += _Count; } else { _Uninitialized_backout<_Unwrapped_n_t> _Backout{_UFirst}; @@ -167,7 +169,9 @@ template _NoThrowFwdIt _Uninitialized_fill_n_unchecked1( const _NoThrowFwdIt _First, const _Diff _Count, const _Tval& _Val, true_type) { // copy _Count copies of _Val to raw _First, memset optimization - _CSTD memset(_First, static_cast(_Val), _Count); + using _DestTy = _Iter_value_t<_NoThrowFwdIt>; + // first cast _Val to _DestTy in case _DestTy is bool + _CSTD memset(_First, static_cast(static_cast<_DestTy>(_Val)), _Count); return _First + _Count; } diff --git a/stl/inc/xmemory b/stl/inc/xmemory index abb94ba7ac0..28662fb4ee3 100644 --- a/stl/inc/xmemory +++ b/stl/inc/xmemory @@ -1756,7 +1756,9 @@ void uninitialized_fill(const _NoThrowFwdIt _First, const _NoThrowFwdIt _Last, c auto _UFirst = _Get_unwrapped(_First); const auto _ULast = _Get_unwrapped(_Last); if constexpr (_Fill_memset_is_safe<_Unwrapped_t, _Tval>) { - _CSTD memset(_UFirst, static_cast(_Val), static_cast(_ULast - _UFirst)); + using _DestTy = _Iter_value_t<_Unwrapped_t>; + // first cast _Val to _DestTy in case _DestTy is bool + _CSTD memset(_UFirst, static_cast(static_cast<_DestTy>(_Val)), static_cast(_ULast - _UFirst)); } else { _Uninitialized_backout<_Unwrapped_t> _Backout{_UFirst}; while (_Backout._Last != _ULast) { @@ -1783,7 +1785,9 @@ template void _Uninitialized_fill_unchecked( const _NoThrowFwdIt _First, const _NoThrowFwdIt _Last, const _Tval& _Val, true_type) { // copy _Val throughout raw [_First, _Last), memset optimization - _CSTD memset(_First, static_cast(_Val), static_cast(_Last - _First)); + using _DestTy = _Iter_value_t<_NoThrowFwdIt>; + // first cast _Val to _DestTy in case _DestTy is bool + _CSTD memset(_First, static_cast(static_cast<_DestTy>(_Val)), static_cast(_Last - _First)); } template diff --git a/stl/inc/xutility b/stl/inc/xutility index 9c82bb27c55..0b1748cf535 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -4732,20 +4732,21 @@ struct _Is_character : true_type {}; // UTF-8 code units are sort-of ch #endif // __cpp_char8_t template -struct _Is_character_or_byte : _Is_character<_Ty>::type {}; +struct _Is_character_or_byte_or_bool : _Is_character<_Ty>::type {}; #ifdef __cpp_lib_byte template <> -struct _Is_character_or_byte : true_type {}; +struct _Is_character_or_byte_or_bool : true_type {}; #endif // __cpp_lib_byte +template <> +struct _Is_character_or_byte_or_bool : true_type {}; + // _Fill_memset_is_safe determines if _FwdIt and _Ty are eligible for memset optimization in fill template > -_INLINE_VAR constexpr bool _Fill_memset_is_safe = conjunction_v< - disjunction>, - _Is_character_or_byte<_Unwrap_enum_t<_Iter_value_t<_FwdIt>>>>, - conjunction>, is_same>>>>, - is_assignable<_Iter_ref_t<_FwdIt>, const _Ty&>>; +_INLINE_VAR constexpr bool _Fill_memset_is_safe = + conjunction_v, _Is_character_or_byte_or_bool<_Unwrap_enum_t<_Iter_value_t<_FwdIt>>>, + is_assignable<_Iter_ref_t<_FwdIt>, const _Ty&>>; template _INLINE_VAR constexpr bool _Fill_memset_is_safe<_FwdIt, _Ty, false> = false; @@ -4765,7 +4766,10 @@ _CONSTEXPR20 void fill(const _FwdIt _First, const _FwdIt _Last, const _Ty& _Val) if (!_STD is_constant_evaluated()) #endif // __cpp_lib_is_constant_evaluated { - _CSTD memset(_UFirst, static_cast(_Val), static_cast(_ULast - _UFirst)); + using _DestTy = _Iter_value_t; + // first cast _Val to _DestTy in case _DestTy is bool + _CSTD memset(_UFirst, static_cast(static_cast<_DestTy>(_Val)), + static_cast(_ULast - _UFirst)); return; } } @@ -4787,7 +4791,9 @@ void _Fill_unchecked1(_FwdIt _First, _FwdIt _Last, const _Ty& _Val, false_type) template void _Fill_unchecked1(_FwdIt _First, _FwdIt _Last, const _Ty& _Val, true_type) { // copy _Val through [_First, _Last), memset optimization - _CSTD memset(_First, static_cast(_Val), static_cast(_Last - _First)); + using _DestTy = _Iter_value_t<_FwdIt>; + // first cast _Val to _DestTy in case _DestTy is bool + _CSTD memset(_First, static_cast(static_cast<_DestTy>(_Val)), static_cast(_Last - _First)); } template @@ -4826,7 +4832,10 @@ _CONSTEXPR20 _OutIt fill_n(_OutIt _Dest, const _Diff _Count_raw, const _Ty& _Val if (!_STD is_constant_evaluated()) #endif // __cpp_lib_is_constant_evaluated { - _CSTD memset(_UDest, static_cast(_Val), static_cast(_Count)); + using _DestTy = _Iter_value_t; + // first cast _Val to _DestTy in case _DestTy is bool + _CSTD memset( + _UDest, static_cast(static_cast<_DestTy>(_Val)), static_cast(_Count)); _UDest += _Count; _Seek_wrapped(_Dest, _UDest); return _Dest; @@ -4857,7 +4866,9 @@ _OutIt _Fill_n_unchecked2(_OutIt _Dest, _Diff _Count, const _Ty& _Val, false_typ template _OutIt _Fill_n_unchecked2(_OutIt _Dest, _Diff _Count, const _Ty& _Val, true_type) { // copy _Val _Count times through [_Dest, ...), memset optimization - _CSTD memset(_Dest, static_cast(_Val), static_cast(_Count)); + using _DestTy = _Iter_value_t<_OutIt>; + // first cast _Val to _DestTy in case _DestTy is bool + _CSTD memset(_Dest, static_cast(static_cast<_DestTy>(_Val)), static_cast(_Count)); return _Dest + _Count; } diff --git a/tests/std/tests/P0896R4_ranges_alg_fill/test.cpp b/tests/std/tests/P0896R4_ranges_alg_fill/test.cpp index 916ac5f73f7..6ed2eee049f 100644 --- a/tests/std/tests/P0896R4_ranges_alg_fill/test.cpp +++ b/tests/std/tests/P0896R4_ranges_alg_fill/test.cpp @@ -31,6 +31,13 @@ struct instantiator { } assert(result == ranges::end(output)); } + { // Validate int is properly converted to bool + bool output[] = {false, true, false}; + fill(ranges::begin(output), ranges::end(output), 5); + for (bool elem : output) { + assert(elem == true); + } + } } }; diff --git a/tests/std/tests/P0896R4_ranges_alg_fill_n/test.cpp b/tests/std/tests/P0896R4_ranges_alg_fill_n/test.cpp index ff51fa9f6b2..efdbaf48465 100644 --- a/tests/std/tests/P0896R4_ranges_alg_fill_n/test.cpp +++ b/tests/std/tests/P0896R4_ranges_alg_fill_n/test.cpp @@ -36,6 +36,13 @@ struct instantiator { assert(ranges::equal(output, expected_output)); assert(result == ranges::begin(output)); } + { // Validate int is properly converted to bool + bool output[] = { false, true, false }; + fill_n(ranges::begin(output), ranges::distance(output), 5); + for (bool elem : output) { + assert(elem == true); + } + } } }; diff --git a/tests/std/tests/VSO_0180469_fill_family/test.cpp b/tests/std/tests/VSO_0180469_fill_family/test.cpp index 164e0318043..88a510dc616 100644 --- a/tests/std/tests/VSO_0180469_fill_family/test.cpp +++ b/tests/std/tests/VSO_0180469_fill_family/test.cpp @@ -136,4 +136,34 @@ int main() { test_uninitialized_fill( [](count_copies* buff, size_t n, const count_copies& src) { uninitialized_fill_n(buff, n, src); }); + + // Validate int is properly converted to bool + { + bool output[] = {false, true, false}; + fill(output, output + 3, 5); + for (bool elem : output) { + assert(elem == true); + } + } + { + bool output[] = {false, true, false}; + fill_n(output, 3, 5); + for (bool elem : output) { + assert(elem == true); + } + } + { + bool output[] = {false, true, false}; + uninitialized_fill(output, output + 3, 5); + for (bool elem : output) { + assert(elem == true); + } + } + { + bool output[] = {false, true, false}; + uninitialized_fill_n(output, 3, 5); + for (bool elem : output) { + assert(elem == true); + } + } } From a112a8715078745a03cfac6ff10b2eea884e577d Mon Sep 17 00:00:00 2001 From: Adam Bucior <35536269+AdamBucior@users.noreply.github.com> Date: Fri, 7 Aug 2020 16:09:37 +0200 Subject: [PATCH 02/17] clang-format --- stl/inc/algorithm | 3 ++- stl/inc/xmemory | 3 ++- tests/std/tests/P0896R4_ranges_alg_fill_n/test.cpp | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/stl/inc/algorithm b/stl/inc/algorithm index ce0b3b97849..34ae5417ca1 100644 --- a/stl/inc/algorithm +++ b/stl/inc/algorithm @@ -4036,7 +4036,8 @@ namespace ranges { { using _DestTy = _Iter_value_t; // first cast _Value to _DestTy in case _DestTy is bool - _CSTD memset(_UFirst, static_cast(static_cast<_DestTy>(_Value)), static_cast(_Count)); + _CSTD memset(_UFirst, static_cast(static_cast<_DestTy>(_Value)), + static_cast(_Count)); _UFirst += _Count; _Seek_wrapped(_First, _UFirst); // no need to move since _UFirst is a pointer return _First; diff --git a/stl/inc/xmemory b/stl/inc/xmemory index 28662fb4ee3..920205a37d0 100644 --- a/stl/inc/xmemory +++ b/stl/inc/xmemory @@ -1758,7 +1758,8 @@ void uninitialized_fill(const _NoThrowFwdIt _First, const _NoThrowFwdIt _Last, c if constexpr (_Fill_memset_is_safe<_Unwrapped_t, _Tval>) { using _DestTy = _Iter_value_t<_Unwrapped_t>; // first cast _Val to _DestTy in case _DestTy is bool - _CSTD memset(_UFirst, static_cast(static_cast<_DestTy>(_Val)), static_cast(_ULast - _UFirst)); + _CSTD memset( + _UFirst, static_cast(static_cast<_DestTy>(_Val)), static_cast(_ULast - _UFirst)); } else { _Uninitialized_backout<_Unwrapped_t> _Backout{_UFirst}; while (_Backout._Last != _ULast) { diff --git a/tests/std/tests/P0896R4_ranges_alg_fill_n/test.cpp b/tests/std/tests/P0896R4_ranges_alg_fill_n/test.cpp index efdbaf48465..8f48639030d 100644 --- a/tests/std/tests/P0896R4_ranges_alg_fill_n/test.cpp +++ b/tests/std/tests/P0896R4_ranges_alg_fill_n/test.cpp @@ -37,7 +37,7 @@ struct instantiator { assert(result == ranges::begin(output)); } { // Validate int is properly converted to bool - bool output[] = { false, true, false }; + bool output[] = {false, true, false}; fill_n(ranges::begin(output), ranges::distance(output), 5); for (bool elem : output) { assert(elem == true); From 4e95254ba83c1a6743d6d1592adfe0a9908fdc0e Mon Sep 17 00:00:00 2001 From: Adam Bucior <35536269+AdamBucior@users.noreply.github.com> Date: Fri, 7 Aug 2020 19:09:18 +0200 Subject: [PATCH 03/17] Use memcmp with bool --- stl/inc/xutility | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/stl/inc/xutility b/stl/inc/xutility index 0b1748cf535..4a9f99584c4 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -4903,14 +4903,13 @@ _FwdIt fill_n(_ExPo&&, _FwdIt _Dest, _Diff _Count_raw, const _Ty& _Val) noexcept // Integral types are eligible for memcmp in very specific cases. // * They must be the same size. (`int == long` is eligible; `int == long long` isn't.) -// * They can't be bool. (Not even `bool == bool`; we're concerned about representations other than 0 and 1.) // * They can't be volatile. // * Finally, the usual arithmetic conversions must preserve bit patterns. (This is true for `int == unsigned int`, // but false for `short == unsigned short`.) template && !is_volatile_v<_Elem1> // - && _Is_nonbool_integral<_Elem2> && !is_volatile_v<_Elem2>> + && is_integral_v<_Elem1> && !is_volatile_v<_Elem1> // + && is_integral_v<_Elem2> && !is_volatile_v<_Elem2>> _INLINE_VAR constexpr bool _Can_memcmp_elements = static_cast<_Elem1>(-1) == static_cast<_Elem2>(-1); #ifdef __cpp_lib_byte From df25b6b6e8530cbeb724760248b7030e2486606a Mon Sep 17 00:00:00 2001 From: Adam Bucior <35536269+AdamBucior@users.noreply.github.com> Date: Sat, 8 Aug 2020 00:33:51 +0200 Subject: [PATCH 04/17] update tests and disable bool == other types --- stl/inc/xutility | 7 ++-- tests/std/tests/VSO_0180469_ptr_cat/test.cpp | 38 ++++++++++++-------- 2 files changed, 28 insertions(+), 17 deletions(-) diff --git a/stl/inc/xutility b/stl/inc/xutility index 4a9f99584c4..a069d08ee5f 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -4908,10 +4908,13 @@ _FwdIt fill_n(_ExPo&&, _FwdIt _Dest, _Diff _Count_raw, const _Ty& _Val) noexcept // but false for `short == unsigned short`.) template && !is_volatile_v<_Elem1> // - && is_integral_v<_Elem2> && !is_volatile_v<_Elem2>> + && _Is_nonbool_integral<_Elem1> && !is_volatile_v<_Elem1> // + && _Is_nonbool_integral<_Elem2> && !is_volatile_v<_Elem2>> _INLINE_VAR constexpr bool _Can_memcmp_elements = static_cast<_Elem1>(-1) == static_cast<_Elem2>(-1); +template <> +inline constexpr bool _Can_memcmp_elements = true; + #ifdef __cpp_lib_byte // Allow memcmping std::byte. // inline is required here as explicit specializations of variable templates are problematic in C++14. diff --git a/tests/std/tests/VSO_0180469_ptr_cat/test.cpp b/tests/std/tests/VSO_0180469_ptr_cat/test.cpp index e0747b48caf..5c574977a54 100644 --- a/tests/std/tests/VSO_0180469_ptr_cat/test.cpp +++ b/tests/std/tests/VSO_0180469_ptr_cat/test.cpp @@ -257,23 +257,31 @@ void test_case_Equal_memcmp_is_safe_comparator() { #ifdef __cpp_lib_concepts // contiguous iterators should not change the answer - STATIC_ASSERT( - _Equal_memcmp_is_safe::iterator, typename vector::iterator, Pr> == Expected); - STATIC_ASSERT(_Equal_memcmp_is_safe::const_iterator, typename vector::const_iterator, - Pr> == Expected); + if constexpr (!is_same_v && !is_same_v) { // vector::iterator is not contiguous + STATIC_ASSERT( + _Equal_memcmp_is_safe::iterator, typename vector::iterator, Pr> == Expected); + STATIC_ASSERT(_Equal_memcmp_is_safe::const_iterator, + typename vector::const_iterator, Pr> == Expected); + } STATIC_ASSERT( _Equal_memcmp_is_safe::iterator, typename array::iterator, Pr> == Expected); STATIC_ASSERT(_Equal_memcmp_is_safe::const_iterator, typename array::const_iterator, Pr> == Expected); // Mixing contiguous iterators should not change the answer - STATIC_ASSERT(_Equal_memcmp_is_safe::iterator, typename vector::const_iterator, - Pr> == Expected); - STATIC_ASSERT(_Equal_memcmp_is_safe::const_iterator, - typename vector::const_iterator, Pr> == Expected); - STATIC_ASSERT( - _Equal_memcmp_is_safe::iterator, typename array::iterator, Pr> == Expected); - STATIC_ASSERT(_Equal_memcmp_is_safe::iterator, typename array::const_iterator, - Pr> == Expected); + if constexpr (!is_same_v && !is_same_v) { + STATIC_ASSERT(_Equal_memcmp_is_safe::iterator, typename vector::const_iterator, + Pr> == Expected); + } + if constexpr (!is_same_v) { + STATIC_ASSERT(_Equal_memcmp_is_safe::const_iterator, + typename vector::const_iterator, Pr> == Expected); + } + if constexpr (!is_same_v) { + STATIC_ASSERT(_Equal_memcmp_is_safe::iterator, typename array::iterator, + Pr> == Expected); + STATIC_ASSERT(_Equal_memcmp_is_safe::iterator, typename array::const_iterator, + Pr> == Expected); + } // span iterators are contiguous STATIC_ASSERT( _Equal_memcmp_is_safe::iterator, typename span::iterator, Pr> == Expected); @@ -335,7 +343,8 @@ void test_case_Equal_memcmp_is_safe() { } void equal_safe_test_cases() { - // memcmp is safe for non-bool integral types + // memcmp is safe for integral types + test_case_Equal_memcmp_is_safe(); test_case_Equal_memcmp_is_safe(); test_case_Equal_memcmp_is_safe(); test_case_Equal_memcmp_is_safe(); @@ -377,8 +386,7 @@ void equal_safe_test_cases() { test_case_Equal_memcmp_is_safe(); test_case_Equal_memcmp_is_safe(); test_case_Equal_memcmp_is_safe(); - // memcmp is not safe for bool types - test_case_Equal_memcmp_is_safe(); + // memcmp is not safe between bool and other integral types test_case_Equal_memcmp_is_safe(); test_case_Equal_memcmp_is_safe(); // No enums From 40bed1c96eaea0a2aa0be1d35f8ef14e50461330 Mon Sep 17 00:00:00 2001 From: Adam Bucior <35536269+AdamBucior@users.noreply.github.com> Date: Sat, 8 Aug 2020 00:46:38 +0200 Subject: [PATCH 05/17] _INLINE_VAR --- stl/inc/xutility | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stl/inc/xutility b/stl/inc/xutility index a069d08ee5f..212fd76905d 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -4913,7 +4913,7 @@ template (-1) == static_cast<_Elem2>(-1); template <> -inline constexpr bool _Can_memcmp_elements = true; +_INLINE_VAR constexpr bool _Can_memcmp_elements = true; #ifdef __cpp_lib_byte // Allow memcmping std::byte. From 5256769df845f90f95e4238f1ad7b9170000b0af Mon Sep 17 00:00:00 2001 From: Adam Bucior <35536269+AdamBucior@users.noreply.github.com> Date: Sat, 8 Aug 2020 10:05:18 +0200 Subject: [PATCH 06/17] workaround --- stl/inc/xutility | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/stl/inc/xutility b/stl/inc/xutility index 212fd76905d..987d0e4e59e 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -4912,8 +4912,8 @@ template && !is_volatile_v<_Elem2>> _INLINE_VAR constexpr bool _Can_memcmp_elements = static_cast<_Elem1>(-1) == static_cast<_Elem2>(-1); -template <> -_INLINE_VAR constexpr bool _Can_memcmp_elements = true; +template +_INLINE_VAR constexpr bool _Can_memcmp_elements = true; #ifdef __cpp_lib_byte // Allow memcmping std::byte. From 2ed711efd12809e17861af762a2ba93f46c9c7fb Mon Sep 17 00:00:00 2001 From: Adam Bucior <35536269+AdamBucior@users.noreply.github.com> Date: Sat, 8 Aug 2020 10:41:20 +0200 Subject: [PATCH 07/17] still failing --- stl/inc/xutility | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/stl/inc/xutility b/stl/inc/xutility index 987d0e4e59e..4f76259e24b 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -4912,9 +4912,6 @@ template && !is_volatile_v<_Elem2>> _INLINE_VAR constexpr bool _Can_memcmp_elements = static_cast<_Elem1>(-1) == static_cast<_Elem2>(-1); -template -_INLINE_VAR constexpr bool _Can_memcmp_elements = true; - #ifdef __cpp_lib_byte // Allow memcmping std::byte. // inline is required here as explicit specializations of variable templates are problematic in C++14. @@ -4930,7 +4927,7 @@ template _INLINE_VAR constexpr bool _Can_memcmp_elements<_Ty1*, _Ty2*, false> = is_same_v, remove_cv_t<_Ty2>>; template -_INLINE_VAR constexpr bool _Can_memcmp_elements<_Elem1, _Elem2, false> = false; +_INLINE_VAR constexpr bool _Can_memcmp_elements<_Elem1, _Elem2, false> = is_same_v<_Elem1, bool> && is_same_v<_Elem2, bool>; // _Pred_is_consistent_with_memcmp<_Elem1, _Elem2, _Pr> reports whether `_Pr(_Elem1, _Elem2)` returns // `_Elem1 == _Elem2` without performing any type conversions that could affect the memcmp optimization. From 86262ed1e88080c01e14b04bb25826b1fc643bd4 Mon Sep 17 00:00:00 2001 From: Adam Bucior <35536269+AdamBucior@users.noreply.github.com> Date: Sat, 8 Aug 2020 10:43:21 +0200 Subject: [PATCH 08/17] clang-format --- stl/inc/xutility | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/stl/inc/xutility b/stl/inc/xutility index 4f76259e24b..556b30dd15e 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -4927,7 +4927,8 @@ template _INLINE_VAR constexpr bool _Can_memcmp_elements<_Ty1*, _Ty2*, false> = is_same_v, remove_cv_t<_Ty2>>; template -_INLINE_VAR constexpr bool _Can_memcmp_elements<_Elem1, _Elem2, false> = is_same_v<_Elem1, bool> && is_same_v<_Elem2, bool>; +_INLINE_VAR constexpr bool _Can_memcmp_elements<_Elem1, _Elem2, false> = + is_same_v<_Elem1, bool>&& is_same_v<_Elem2, bool>; // _Pred_is_consistent_with_memcmp<_Elem1, _Elem2, _Pr> reports whether `_Pr(_Elem1, _Elem2)` returns // `_Elem1 == _Elem2` without performing any type conversions that could affect the memcmp optimization. From 1b91524ad010015dd6bbbeabb74948108f1aa487 Mon Sep 17 00:00:00 2001 From: Adam Bucior <35536269+AdamBucior@users.noreply.github.com> Date: Mon, 10 Aug 2020 14:50:27 +0200 Subject: [PATCH 09/17] _Fill_memset --- stl/inc/algorithm | 9 ++------- stl/inc/memory | 12 ++++-------- stl/inc/xmemory | 13 ++++--------- stl/inc/xutility | 24 ++++++++++-------------- 4 files changed, 20 insertions(+), 38 deletions(-) diff --git a/stl/inc/algorithm b/stl/inc/algorithm index 34ae5417ca1..1bebe70c3c0 100644 --- a/stl/inc/algorithm +++ b/stl/inc/algorithm @@ -3993,9 +3993,7 @@ namespace ranges { #endif // __cpp_lib_is_constant_evaluated { const auto _Distance = static_cast(_ULast - _UFirst); - using _DestTy = _Iter_value_t; - // first cast _Value to _DestTy in case _DestTy is bool - _CSTD memset(_UFirst, static_cast(static_cast<_DestTy>(_Value)), _Distance); + _Fill_memset(_UFirst, _Value, _Distance); _UFirst += _Distance; _Seek_wrapped(_First, _UFirst); return _First; @@ -4034,10 +4032,7 @@ namespace ranges { if (!_STD is_constant_evaluated()) #endif // __cpp_lib_is_constant_evaluated { - using _DestTy = _Iter_value_t; - // first cast _Value to _DestTy in case _DestTy is bool - _CSTD memset(_UFirst, static_cast(static_cast<_DestTy>(_Value)), - static_cast(_Count)); + _Fill_memset(_UFirst, _Value, static_cast(_Count)); _UFirst += _Count; _Seek_wrapped(_First, _UFirst); // no need to move since _UFirst is a pointer return _First; diff --git a/stl/inc/memory b/stl/inc/memory index c610dcaef78..02595fa3426 100644 --- a/stl/inc/memory +++ b/stl/inc/memory @@ -134,9 +134,7 @@ _NoThrowFwdIt uninitialized_fill_n(_NoThrowFwdIt _First, const _Diff _Count_raw, if (0 < _Count) { auto _UFirst = _Get_unwrapped_n(_First, _Count); if constexpr (_Fill_memset_is_safe<_Unwrapped_n_t, _Tval>) { - using _DestTy = _Iter_value_t<_Unwrapped_n_t>; - // first cast _Val to _DestTy in case _DestTy is bool - _CSTD memset(_UFirst, static_cast(static_cast<_DestTy>(_Val)), _Count); + _Fill_memset(_UFirst, _Val, _Count); _UFirst += _Count; } else { _Uninitialized_backout<_Unwrapped_n_t> _Backout{_UFirst}; @@ -169,9 +167,7 @@ template _NoThrowFwdIt _Uninitialized_fill_n_unchecked1( const _NoThrowFwdIt _First, const _Diff _Count, const _Tval& _Val, true_type) { // copy _Count copies of _Val to raw _First, memset optimization - using _DestTy = _Iter_value_t<_NoThrowFwdIt>; - // first cast _Val to _DestTy in case _DestTy is bool - _CSTD memset(_First, static_cast(static_cast<_DestTy>(_Val)), _Count); + _Fill_memset(_First, _Val, _Count); return _First + _Count; } @@ -1657,7 +1653,7 @@ void _Uninitialized_fill_multidimensional_n(_Ty* const _Out, const size_t _Size, } _Guard._Target = nullptr; } else if constexpr (_Fill_memset_is_safe<_Ty*, _Ty>) { - _CSTD memset(_Out, static_cast(_Val), _Size); + _Fill_memset(_Out, _Val, _Size); } else { _Uninitialized_rev_destroying_backout _Backout{_Out}; for (size_t _Idx = 0; _Idx < _Size; ++_Idx) { @@ -1980,7 +1976,7 @@ void _Uninitialized_fill_multidimensional_n_al(_Ty* const _Out, const size_t _Si } _Guard._Target = nullptr; } else if constexpr (_Fill_memset_is_safe<_Ty*, _Ty> && _Uses_default_construct<_Alloc, _Ty*, const _Ty&>::value) { - _CSTD memset(_Out, static_cast(_Val), _Size); + _Fill_memset(_Out, _Val, _Size); } else { _Uninitialized_rev_destroying_backout_al _Backout{_Out, _Al}; for (size_t _Idx = 0; _Idx < _Size; ++_Idx) { diff --git a/stl/inc/xmemory b/stl/inc/xmemory index 920205a37d0..af502b46e7a 100644 --- a/stl/inc/xmemory +++ b/stl/inc/xmemory @@ -1705,7 +1705,7 @@ _Alloc_ptr_t<_Alloc> _Uninitialized_fill_n( // copy _Count copies of _Val to raw _First, using _Al using _Ty = typename _Alloc::value_type; if constexpr (_Fill_memset_is_safe<_Ty*, _Ty> && _Uses_default_construct<_Alloc, _Ty*, _Ty>::value) { - _CSTD memset(_Unfancy(_First), static_cast(_Val), static_cast(_Count)); + _Fill_memset(_Unfancy(_First), _Val, static_cast(_Count)); return _First + _Count; } else { _Uninitialized_backout_al<_Alloc> _Backout{_First, _Al}; @@ -1733,7 +1733,7 @@ template _Alloc_ptr_t<_Alloc> _Uninit_alloc_fill_n1(_Alloc_ptr_t<_Alloc> _First, _Alloc_size_t<_Alloc> _Count, const typename _Alloc::value_type& _Val, _Alloc&, true_type) { // copy _Count copies of _Val to raw _First, using default _Alloc construct, memset optimization - _CSTD memset(_Unfancy(_First), static_cast(_Val), _Count); + _Fill_memset(_Unfancy(_First), _Val, _Count); return _First + _Count; } @@ -1756,10 +1756,7 @@ void uninitialized_fill(const _NoThrowFwdIt _First, const _NoThrowFwdIt _Last, c auto _UFirst = _Get_unwrapped(_First); const auto _ULast = _Get_unwrapped(_Last); if constexpr (_Fill_memset_is_safe<_Unwrapped_t, _Tval>) { - using _DestTy = _Iter_value_t<_Unwrapped_t>; - // first cast _Val to _DestTy in case _DestTy is bool - _CSTD memset( - _UFirst, static_cast(static_cast<_DestTy>(_Val)), static_cast(_ULast - _UFirst)); + _Fill_memset(_UFirst, _Val, static_cast(_ULast - _UFirst)); } else { _Uninitialized_backout<_Unwrapped_t> _Backout{_UFirst}; while (_Backout._Last != _ULast) { @@ -1786,9 +1783,7 @@ template void _Uninitialized_fill_unchecked( const _NoThrowFwdIt _First, const _NoThrowFwdIt _Last, const _Tval& _Val, true_type) { // copy _Val throughout raw [_First, _Last), memset optimization - using _DestTy = _Iter_value_t<_NoThrowFwdIt>; - // first cast _Val to _DestTy in case _DestTy is bool - _CSTD memset(_First, static_cast(static_cast<_DestTy>(_Val)), static_cast(_Last - _First)); + _Fill_memset(_First, _Val, static_cast(_Last - _First)); } template diff --git a/stl/inc/xutility b/stl/inc/xutility index 556b30dd15e..1c13baf4f55 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -4751,6 +4751,12 @@ _INLINE_VAR constexpr bool _Fill_memset_is_safe = template _INLINE_VAR constexpr bool _Fill_memset_is_safe<_FwdIt, _Ty, false> = false; +template +void _Fill_memset(_DestTy* const _Dest, const _Ty& _Val, size_t _Count) { + // first cast _Val to _DestTy in case _DestTy is bool + _CSTD memset(_Dest, static_cast(static_cast<_DestTy>(_Val)), _Count); +} + #if _HAS_IF_CONSTEXPR template _CONSTEXPR20 void fill(const _FwdIt _First, const _FwdIt _Last, const _Ty& _Val) { @@ -4766,10 +4772,7 @@ _CONSTEXPR20 void fill(const _FwdIt _First, const _FwdIt _Last, const _Ty& _Val) if (!_STD is_constant_evaluated()) #endif // __cpp_lib_is_constant_evaluated { - using _DestTy = _Iter_value_t; - // first cast _Val to _DestTy in case _DestTy is bool - _CSTD memset(_UFirst, static_cast(static_cast<_DestTy>(_Val)), - static_cast(_ULast - _UFirst)); + _Fill_memset(_UFirst, _Val, static_cast(_ULast - _UFirst)); return; } } @@ -4791,9 +4794,7 @@ void _Fill_unchecked1(_FwdIt _First, _FwdIt _Last, const _Ty& _Val, false_type) template void _Fill_unchecked1(_FwdIt _First, _FwdIt _Last, const _Ty& _Val, true_type) { // copy _Val through [_First, _Last), memset optimization - using _DestTy = _Iter_value_t<_FwdIt>; - // first cast _Val to _DestTy in case _DestTy is bool - _CSTD memset(_First, static_cast(static_cast<_DestTy>(_Val)), static_cast(_Last - _First)); + _Fill_memset(_First, _Val, static_cast(_Last - _First)); } template @@ -4832,10 +4833,7 @@ _CONSTEXPR20 _OutIt fill_n(_OutIt _Dest, const _Diff _Count_raw, const _Ty& _Val if (!_STD is_constant_evaluated()) #endif // __cpp_lib_is_constant_evaluated { - using _DestTy = _Iter_value_t; - // first cast _Val to _DestTy in case _DestTy is bool - _CSTD memset( - _UDest, static_cast(static_cast<_DestTy>(_Val)), static_cast(_Count)); + _Fill_memset(_UDest, _Val, static_cast(_Count)); _UDest += _Count; _Seek_wrapped(_Dest, _UDest); return _Dest; @@ -4866,9 +4864,7 @@ _OutIt _Fill_n_unchecked2(_OutIt _Dest, _Diff _Count, const _Ty& _Val, false_typ template _OutIt _Fill_n_unchecked2(_OutIt _Dest, _Diff _Count, const _Ty& _Val, true_type) { // copy _Val _Count times through [_Dest, ...), memset optimization - using _DestTy = _Iter_value_t<_OutIt>; - // first cast _Val to _DestTy in case _DestTy is bool - _CSTD memset(_Dest, static_cast(static_cast<_DestTy>(_Val)), static_cast(_Count)); + _Fill_memset(_Dest, _Val, static_cast(_Count)); return _Dest + _Count; } From 130b731491d949b73ba7eff2e64c9ad63f4727dc Mon Sep 17 00:00:00 2001 From: Adam Bucior <35536269+AdamBucior@users.noreply.github.com> Date: Tue, 11 Aug 2020 13:51:44 +0200 Subject: [PATCH 10/17] remove ref and add const Co-authored-by: Alex Guteniev --- stl/inc/xutility | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stl/inc/xutility b/stl/inc/xutility index 1c13baf4f55..8bcfd483a10 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -4752,7 +4752,7 @@ template _INLINE_VAR constexpr bool _Fill_memset_is_safe<_FwdIt, _Ty, false> = false; template -void _Fill_memset(_DestTy* const _Dest, const _Ty& _Val, size_t _Count) { +void _Fill_memset(_DestTy* const _Dest, const _Ty _Val, const size_t _Count) { // first cast _Val to _DestTy in case _DestTy is bool _CSTD memset(_Dest, static_cast(static_cast<_DestTy>(_Val)), _Count); } From a67679320efa32ea0a0da47a00e6a55ef52b0752 Mon Sep 17 00:00:00 2001 From: Adam Bucior <35536269+AdamBucior@users.noreply.github.com> Date: Wed, 12 Aug 2020 12:31:32 +0200 Subject: [PATCH 11/17] Fix #1183 --- stl/inc/xutility | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/stl/inc/xutility b/stl/inc/xutility index 8bcfd483a10..379ca50038c 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -4744,9 +4744,9 @@ struct _Is_character_or_byte_or_bool : true_type {}; // _Fill_memset_is_safe determines if _FwdIt and _Ty are eligible for memset optimization in fill template > -_INLINE_VAR constexpr bool _Fill_memset_is_safe = - conjunction_v, _Is_character_or_byte_or_bool<_Unwrap_enum_t<_Iter_value_t<_FwdIt>>>, - is_assignable<_Iter_ref_t<_FwdIt>, const _Ty&>>; +_INLINE_VAR constexpr bool _Fill_memset_is_safe = conjunction_v, + _Is_character_or_byte_or_bool<_Unwrap_enum_t>>>, + is_assignable<_Iter_ref_t<_FwdIt>, const _Ty&>>; template _INLINE_VAR constexpr bool _Fill_memset_is_safe<_FwdIt, _Ty, false> = false; From 5211954ef306fe6f7073c77a4a6acebe82d6214f Mon Sep 17 00:00:00 2001 From: Adam Bucior <35536269+AdamBucior@users.noreply.github.com> Date: Wed, 12 Aug 2020 13:58:04 +0200 Subject: [PATCH 12/17] Simple test case for #1183 --- tests/std/tests/VSO_0180469_fill_family/test.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/std/tests/VSO_0180469_fill_family/test.cpp b/tests/std/tests/VSO_0180469_fill_family/test.cpp index 88a510dc616..b3a76a0c629 100644 --- a/tests/std/tests/VSO_0180469_fill_family/test.cpp +++ b/tests/std/tests/VSO_0180469_fill_family/test.cpp @@ -20,7 +20,7 @@ using namespace std; // This thing is a workaround for C4309 "truncation of constant value" template T cast(U i) { - return static_cast(i); + return static_cast>(i); } // Tests that `fillCall`(buffer, value, startIndex, endIndex) fills [startIndex, endIndex) with `value` @@ -131,6 +131,8 @@ int main() { test_fill(); test_fill(); + test_fill(); + test_uninitialized_fill( [](count_copies* buff, size_t n, const count_copies& src) { uninitialized_fill(buff, buff + n, src); }); From 7223a0bf038fc8d0a018c6c8e2beba3d33993106 Mon Sep 17 00:00:00 2001 From: Adam Bucior <35536269+AdamBucior@users.noreply.github.com> Date: Wed, 12 Aug 2020 19:00:10 +0200 Subject: [PATCH 13/17] deprecated volatile parameters and return values --- tests/std/tests/VSO_0180469_fill_family/test.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/std/tests/VSO_0180469_fill_family/test.cpp b/tests/std/tests/VSO_0180469_fill_family/test.cpp index b3a76a0c629..3741c9be603 100644 --- a/tests/std/tests/VSO_0180469_fill_family/test.cpp +++ b/tests/std/tests/VSO_0180469_fill_family/test.cpp @@ -19,7 +19,7 @@ using namespace std; // This thing is a workaround for C4309 "truncation of constant value" template -T cast(U i) { +remove_volatile_t cast(U i) { return static_cast>(i); } @@ -131,7 +131,7 @@ int main() { test_fill(); test_fill(); - test_fill(); + test_fill(); test_uninitialized_fill( [](count_copies* buff, size_t n, const count_copies& src) { uninitialized_fill(buff, buff + n, src); }); From e17656fbbed195803ff797749c144c2dbc86954d Mon Sep 17 00:00:00 2001 From: Adam Bucior <35536269+AdamBucior@users.noreply.github.com> Date: Tue, 1 Sep 2020 10:43:05 +0200 Subject: [PATCH 14/17] Code review changes --- stl/inc/xutility | 4 ++-- tests/std/tests/P0896R4_ranges_alg_fill/test.cpp | 2 +- tests/std/tests/P0896R4_ranges_alg_fill_n/test.cpp | 2 +- tests/std/tests/VSO_0180469_fill_family/test.cpp | 10 +++++----- tests/std/tests/VSO_0180469_ptr_cat/test.cpp | 2 ++ 5 files changed, 11 insertions(+), 9 deletions(-) diff --git a/stl/inc/xutility b/stl/inc/xutility index 379ca50038c..22879090778 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -4753,8 +4753,8 @@ _INLINE_VAR constexpr bool _Fill_memset_is_safe<_FwdIt, _Ty, false> = false; template void _Fill_memset(_DestTy* const _Dest, const _Ty _Val, const size_t _Count) { - // first cast _Val to _DestTy in case _DestTy is bool - _CSTD memset(_Dest, static_cast(static_cast<_DestTy>(_Val)), _Count); + _DestTy _Dest_val = _Val; // implicitly convert (a cast would suppress warnings); also handles _DestTy being bool + _CSTD memset(_Dest, static_cast(_Dest_val), _Count); } #if _HAS_IF_CONSTEXPR diff --git a/tests/std/tests/P0896R4_ranges_alg_fill/test.cpp b/tests/std/tests/P0896R4_ranges_alg_fill/test.cpp index 6ed2eee049f..de124175a30 100644 --- a/tests/std/tests/P0896R4_ranges_alg_fill/test.cpp +++ b/tests/std/tests/P0896R4_ranges_alg_fill/test.cpp @@ -34,7 +34,7 @@ struct instantiator { { // Validate int is properly converted to bool bool output[] = {false, true, false}; fill(ranges::begin(output), ranges::end(output), 5); - for (bool elem : output) { + for (const bool &elem : output) { assert(elem == true); } } diff --git a/tests/std/tests/P0896R4_ranges_alg_fill_n/test.cpp b/tests/std/tests/P0896R4_ranges_alg_fill_n/test.cpp index 8f48639030d..9a478b1dc51 100644 --- a/tests/std/tests/P0896R4_ranges_alg_fill_n/test.cpp +++ b/tests/std/tests/P0896R4_ranges_alg_fill_n/test.cpp @@ -39,7 +39,7 @@ struct instantiator { { // Validate int is properly converted to bool bool output[] = {false, true, false}; fill_n(ranges::begin(output), ranges::distance(output), 5); - for (bool elem : output) { + for (const bool &elem : output) { assert(elem == true); } } diff --git a/tests/std/tests/VSO_0180469_fill_family/test.cpp b/tests/std/tests/VSO_0180469_fill_family/test.cpp index 3741c9be603..1878e8e00f3 100644 --- a/tests/std/tests/VSO_0180469_fill_family/test.cpp +++ b/tests/std/tests/VSO_0180469_fill_family/test.cpp @@ -131,7 +131,7 @@ int main() { test_fill(); test_fill(); - test_fill(); + test_fill(); // Test GH-1183 test_uninitialized_fill( [](count_copies* buff, size_t n, const count_copies& src) { uninitialized_fill(buff, buff + n, src); }); @@ -143,28 +143,28 @@ int main() { { bool output[] = {false, true, false}; fill(output, output + 3, 5); - for (bool elem : output) { + for (const bool &elem : output) { assert(elem == true); } } { bool output[] = {false, true, false}; fill_n(output, 3, 5); - for (bool elem : output) { + for (const bool &elem : output) { assert(elem == true); } } { bool output[] = {false, true, false}; uninitialized_fill(output, output + 3, 5); - for (bool elem : output) { + for (const bool &elem : output) { assert(elem == true); } } { bool output[] = {false, true, false}; uninitialized_fill_n(output, 3, 5); - for (bool elem : output) { + for (const bool &elem : output) { assert(elem == true); } } diff --git a/tests/std/tests/VSO_0180469_ptr_cat/test.cpp b/tests/std/tests/VSO_0180469_ptr_cat/test.cpp index 5c574977a54..14b7c7d7bda 100644 --- a/tests/std/tests/VSO_0180469_ptr_cat/test.cpp +++ b/tests/std/tests/VSO_0180469_ptr_cat/test.cpp @@ -272,10 +272,12 @@ void test_case_Equal_memcmp_is_safe_comparator() { STATIC_ASSERT(_Equal_memcmp_is_safe::iterator, typename vector::const_iterator, Pr> == Expected); } + if constexpr (!is_same_v) { STATIC_ASSERT(_Equal_memcmp_is_safe::const_iterator, typename vector::const_iterator, Pr> == Expected); } + if constexpr (!is_same_v) { STATIC_ASSERT(_Equal_memcmp_is_safe::iterator, typename array::iterator, Pr> == Expected); From ec457b1a03bec3833077e6ca65413da8810c6f72 Mon Sep 17 00:00:00 2001 From: Adam Bucior <35536269+AdamBucior@users.noreply.github.com> Date: Tue, 1 Sep 2020 10:50:13 +0200 Subject: [PATCH 15/17] clang-format --- tests/std/tests/P0896R4_ranges_alg_fill/test.cpp | 2 +- tests/std/tests/P0896R4_ranges_alg_fill_n/test.cpp | 2 +- tests/std/tests/VSO_0180469_fill_family/test.cpp | 8 ++++---- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/std/tests/P0896R4_ranges_alg_fill/test.cpp b/tests/std/tests/P0896R4_ranges_alg_fill/test.cpp index de124175a30..0bea140c685 100644 --- a/tests/std/tests/P0896R4_ranges_alg_fill/test.cpp +++ b/tests/std/tests/P0896R4_ranges_alg_fill/test.cpp @@ -34,7 +34,7 @@ struct instantiator { { // Validate int is properly converted to bool bool output[] = {false, true, false}; fill(ranges::begin(output), ranges::end(output), 5); - for (const bool &elem : output) { + for (const bool& elem : output) { assert(elem == true); } } diff --git a/tests/std/tests/P0896R4_ranges_alg_fill_n/test.cpp b/tests/std/tests/P0896R4_ranges_alg_fill_n/test.cpp index 9a478b1dc51..622794b11c3 100644 --- a/tests/std/tests/P0896R4_ranges_alg_fill_n/test.cpp +++ b/tests/std/tests/P0896R4_ranges_alg_fill_n/test.cpp @@ -39,7 +39,7 @@ struct instantiator { { // Validate int is properly converted to bool bool output[] = {false, true, false}; fill_n(ranges::begin(output), ranges::distance(output), 5); - for (const bool &elem : output) { + for (const bool& elem : output) { assert(elem == true); } } diff --git a/tests/std/tests/VSO_0180469_fill_family/test.cpp b/tests/std/tests/VSO_0180469_fill_family/test.cpp index 1878e8e00f3..2ec62a9404f 100644 --- a/tests/std/tests/VSO_0180469_fill_family/test.cpp +++ b/tests/std/tests/VSO_0180469_fill_family/test.cpp @@ -143,28 +143,28 @@ int main() { { bool output[] = {false, true, false}; fill(output, output + 3, 5); - for (const bool &elem : output) { + for (const bool& elem : output) { assert(elem == true); } } { bool output[] = {false, true, false}; fill_n(output, 3, 5); - for (const bool &elem : output) { + for (const bool& elem : output) { assert(elem == true); } } { bool output[] = {false, true, false}; uninitialized_fill(output, output + 3, 5); - for (const bool &elem : output) { + for (const bool& elem : output) { assert(elem == true); } } { bool output[] = {false, true, false}; uninitialized_fill_n(output, 3, 5); - for (const bool &elem : output) { + for (const bool& elem : output) { assert(elem == true); } } From b40d1bbac123eaf1f2dcc810672694aae30f1eaa Mon Sep 17 00:00:00 2001 From: Adam Bucior <35536269+AdamBucior@users.noreply.github.com> Date: Wed, 2 Sep 2020 21:17:49 +0200 Subject: [PATCH 16/17] memcmp with bool == non-bool --- stl/inc/xutility | 10 +++++----- tests/std/tests/VSO_0180469_ptr_cat/test.cpp | 10 +++++++--- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/stl/inc/xutility b/stl/inc/xutility index 22879090778..cdb5018932d 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -4904,9 +4904,10 @@ _FwdIt fill_n(_ExPo&&, _FwdIt _Dest, _Diff _Count_raw, const _Ty& _Val) noexcept // but false for `short == unsigned short`.) template && !is_volatile_v<_Elem1> // - && _Is_nonbool_integral<_Elem2> && !is_volatile_v<_Elem2>> -_INLINE_VAR constexpr bool _Can_memcmp_elements = static_cast<_Elem1>(-1) == static_cast<_Elem2>(-1); + && is_integral_v<_Elem1> && !is_volatile_v<_Elem1> // + && is_integral_v<_Elem2> && !is_volatile_v<_Elem2>> +_INLINE_VAR constexpr bool _Can_memcmp_elements = + is_same_v<_Elem1, bool> || is_same_v<_Elem2, bool> || static_cast<_Elem1>(-1) == static_cast<_Elem2>(-1); #ifdef __cpp_lib_byte // Allow memcmping std::byte. @@ -4923,8 +4924,7 @@ template _INLINE_VAR constexpr bool _Can_memcmp_elements<_Ty1*, _Ty2*, false> = is_same_v, remove_cv_t<_Ty2>>; template -_INLINE_VAR constexpr bool _Can_memcmp_elements<_Elem1, _Elem2, false> = - is_same_v<_Elem1, bool>&& is_same_v<_Elem2, bool>; +_INLINE_VAR constexpr bool _Can_memcmp_elements<_Elem1, _Elem2, false> = false; // _Pred_is_consistent_with_memcmp<_Elem1, _Elem2, _Pr> reports whether `_Pr(_Elem1, _Elem2)` returns // `_Elem1 == _Elem2` without performing any type conversions that could affect the memcmp optimization. diff --git a/tests/std/tests/VSO_0180469_ptr_cat/test.cpp b/tests/std/tests/VSO_0180469_ptr_cat/test.cpp index 14b7c7d7bda..1516b8405b3 100644 --- a/tests/std/tests/VSO_0180469_ptr_cat/test.cpp +++ b/tests/std/tests/VSO_0180469_ptr_cat/test.cpp @@ -388,9 +388,13 @@ void equal_safe_test_cases() { test_case_Equal_memcmp_is_safe(); test_case_Equal_memcmp_is_safe(); test_case_Equal_memcmp_is_safe(); - // memcmp is not safe between bool and other integral types - test_case_Equal_memcmp_is_safe(); - test_case_Equal_memcmp_is_safe(); +#pragma warning(push) +#pragma warning(disable : 4806) // no value of type '_Elem1' promoted to type '_Elem2' can equal the given constant + // memcmp is safe between bool and other integral types with the same size because we don't care about + // representations other than 0 and 1 + test_case_Equal_memcmp_is_safe(); + test_case_Equal_memcmp_is_safe(); +#pragma warning(pop) // No enums test_case_Equal_memcmp_is_safe(); test_case_Equal_memcmp_is_safe(); From c1f04b0ae84603f602f9f85027b756287391afa6 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Wed, 2 Sep 2020 15:24:48 -0700 Subject: [PATCH 17/17] Silence C4806 in . --- stl/inc/xutility | 3 +++ tests/std/tests/VSO_0180469_ptr_cat/test.cpp | 3 --- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/stl/inc/xutility b/stl/inc/xutility index cdb5018932d..99041c60cae 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -4902,12 +4902,15 @@ _FwdIt fill_n(_ExPo&&, _FwdIt _Dest, _Diff _Count_raw, const _Ty& _Val) noexcept // * They can't be volatile. // * Finally, the usual arithmetic conversions must preserve bit patterns. (This is true for `int == unsigned int`, // but false for `short == unsigned short`.) +#pragma warning(push) +#pragma warning(disable : 4806) // no value of type 'bool' promoted to type 'char' can equal the given constant template && !is_volatile_v<_Elem1> // && is_integral_v<_Elem2> && !is_volatile_v<_Elem2>> _INLINE_VAR constexpr bool _Can_memcmp_elements = is_same_v<_Elem1, bool> || is_same_v<_Elem2, bool> || static_cast<_Elem1>(-1) == static_cast<_Elem2>(-1); +#pragma warning(pop) #ifdef __cpp_lib_byte // Allow memcmping std::byte. diff --git a/tests/std/tests/VSO_0180469_ptr_cat/test.cpp b/tests/std/tests/VSO_0180469_ptr_cat/test.cpp index 1516b8405b3..993ac08ecaf 100644 --- a/tests/std/tests/VSO_0180469_ptr_cat/test.cpp +++ b/tests/std/tests/VSO_0180469_ptr_cat/test.cpp @@ -388,13 +388,10 @@ void equal_safe_test_cases() { test_case_Equal_memcmp_is_safe(); test_case_Equal_memcmp_is_safe(); test_case_Equal_memcmp_is_safe(); -#pragma warning(push) -#pragma warning(disable : 4806) // no value of type '_Elem1' promoted to type '_Elem2' can equal the given constant // memcmp is safe between bool and other integral types with the same size because we don't care about // representations other than 0 and 1 test_case_Equal_memcmp_is_safe(); test_case_Equal_memcmp_is_safe(); -#pragma warning(pop) // No enums test_case_Equal_memcmp_is_safe(); test_case_Equal_memcmp_is_safe();