diff --git a/stl/inc/vector b/stl/inc/vector index 8d3f31bb0b4..1ef309dffa7 100644 --- a/stl/inc/vector +++ b/stl/inc/vector @@ -3816,7 +3816,7 @@ _CONSTEXPR20 _OutIt _Copy_vbool(_VbIt _First, _VbIt _Last, _OutIt _Dest) { const auto _FirstSourceMask = static_cast<_Vbase>(-1) << _First._Myoff; const auto _FirstDestMask = _Dest._Myoff == 0 ? 0 : (static_cast<_Vbase>(-1) >> (_VBITS - _Dest._Myoff)); - const auto _LastSourceMask = static_cast<_Vbase>(-1) >> (_VBITS - _Last._Myoff); + const auto _LastSourceMask = _Last._Myoff == 0 ? 0 : (static_cast<_Vbase>(-1) >> (_VBITS - _Last._Myoff)); const auto _LastDestMask = static_cast<_Vbase>(-1) << _DestEnd._Myoff; const bool _IsSingleBlockSource = _VbFirst == _VbLast; @@ -3859,8 +3859,26 @@ _CONSTEXPR20 _OutIt _Copy_vbool(_VbIt _First, _VbIt _Last, _OutIt _Dest) { } #if _HAS_CXX20 - if (!_STD is_constant_evaluated()) -#endif + if (_STD is_constant_evaluated()) { + if (_Dest._Myoff == _First._Myoff) { + const auto _FirstSourceVal = *_VbFirst & _FirstSourceMask; + *_VbDest = (*_VbDest & _FirstDestMask) | _FirstSourceVal; + + ++_VbFirst; + ++_VbDest; + for (; _VbFirst != _VbLast; ++_VbFirst, ++_VbDest) { + *_VbDest = *_VbFirst; + } + + if (_Last._Myoff != 0) { + const auto _LastSourceVal = *_VbFirst & _LastSourceMask; + *_VbDest = (*_VbDest & _LastDestMask) | _LastSourceVal; + } + + return _DestEnd; + } + } else +#endif // _HAS_CXX20 { // If _First and _Dest have matching char alignment, use memmove const auto _UnalignedFirstBits = _First._Myoff & _Vbase{7}; diff --git a/tests/libcxx/expected_results.txt b/tests/libcxx/expected_results.txt index 3285f4d32ae..2d96ceff630 100644 --- a/tests/libcxx/expected_results.txt +++ b/tests/libcxx/expected_results.txt @@ -656,13 +656,6 @@ std/input.output/string.streams/stringbuf/stringbuf.members/view.pass.cpp FAIL std/input.output/syncstream/syncbuf/syncstream.syncbuf.cons/dtor.pass.cpp FAIL std/input.output/syncstream/syncbuf/syncstream.syncbuf.members/emit.pass.cpp FAIL -# GH-5345: : _Copy_vbool() mishandles vectors of size 32 and 64, revealed by constexpr Clang -std/algorithms/alg.modifying.operations/alg.copy/copy_n.pass.cpp:2 FAIL -std/algorithms/alg.modifying.operations/alg.copy/copy.pass.cpp:2 FAIL -std/algorithms/alg.modifying.operations/alg.move/move.pass.cpp:2 FAIL -std/algorithms/alg.nonmodifying/alg.equal/equal.pass.cpp FAIL -std/algorithms/alg.nonmodifying/alg.equal/ranges.equal.pass.cpp FAIL - # *** VCRUNTIME BUGS *** @@ -1067,6 +1060,7 @@ std/utilities/utility/mem.res/mem.poly.allocator.class/mem.poly.allocator.mem/co # Not analyzed, failing due to constexpr step limits. std/algorithms/alg.modifying.operations/alg.copy/ranges.copy_backward.pass.cpp:2 FAIL +std/algorithms/alg.modifying.operations/alg.move/move.pass.cpp:2 FAIL std/algorithms/alg.modifying.operations/alg.rotate/rotate.pass.cpp FAIL std/algorithms/alg.nonmodifying/alg.contains/ranges.contains_subrange.pass.cpp:2 FAIL std/algorithms/alg.nonmodifying/alg.count/count.pass.cpp FAIL @@ -1198,6 +1192,15 @@ std/containers/views/mdspan/mdspan/index_operator.pass.cpp:1 FAIL std/utilities/utility/utility.swap/swap_array.pass.cpp:0 FAIL std/utilities/utility/utility.swap/swap_array.pass.cpp:1 FAIL +# Not analyzed. MSVC constexpr ICE. +std/algorithms/alg.nonmodifying/alg.equal/equal.pass.cpp:0 FAIL +std/algorithms/alg.nonmodifying/alg.equal/equal.pass.cpp:1 FAIL +std/algorithms/alg.nonmodifying/alg.equal/ranges.equal.pass.cpp:0 FAIL +std/algorithms/alg.nonmodifying/alg.equal/ranges.equal.pass.cpp:1 FAIL + +# Not analyzed. Possible Clang constexpr bug involving the test's sized_allocator and our check for transposed ranges. +std/algorithms/alg.modifying.operations/alg.copy/copy.pass.cpp:2 FAIL + # Not analyzed. SKIPPED because this is x86-specific, fatal error C1060: compiler is out of heap space std/algorithms/alg.modifying.operations/alg.transform/ranges.transform.binary.iterator.pass.cpp:0 SKIPPED std/algorithms/alg.modifying.operations/alg.transform/ranges.transform.binary.iterator.pass.cpp:1 SKIPPED diff --git a/tests/std/tests/GH_000625_vector_bool_optimization/test.cpp b/tests/std/tests/GH_000625_vector_bool_optimization/test.cpp index c96ea1bbafd..79e4a7a127d 100644 --- a/tests/std/tests/GH_000625_vector_bool_optimization/test.cpp +++ b/tests/std/tests/GH_000625_vector_bool_optimization/test.cpp @@ -1304,6 +1304,35 @@ void randomized_test_copy(mt19937_64& gen) { } } +#if _HAS_CXX20 +template +constexpr bool test_gh_5345() { + // GH-5345 : _Copy_vbool() mishandles vectors of size 32 and 64, revealed by constexpr Clang + vector src(N, true); + + for (size_t i = 2; i != N; ++i) { + for (size_t j = i * 2; j < N; j += i) { + src[j] = false; + } + } + + vector dst(N, false); + copy(src.begin() + Offset, src.end(), dst.begin() + Offset); + return equal(src.begin() + Offset, src.end(), dst.begin() + Offset, dst.end()); +} + +static_assert(test_gh_5345<17>()); +static_assert(test_gh_5345<17, 1>()); +static_assert(test_gh_5345<32>()); +static_assert(test_gh_5345<32, 5>()); +static_assert(test_gh_5345<43>()); +static_assert(test_gh_5345<43, 10>()); +static_assert(test_gh_5345<64>()); +static_assert(test_gh_5345<64, 16>()); +static_assert(test_gh_5345<120>()); +static_assert(test_gh_5345<120, 31>()); +#endif // _HAS_CXX20 + int main() { test_fill(); test_find();