Skip to content
Merged
24 changes: 21 additions & 3 deletions stl/inc/vector
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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};
Expand Down
17 changes: 10 additions & 7 deletions tests/libcxx/expected_results.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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: <vector>: _Copy_vbool() mishandles vector<bool>s 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 ***

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
29 changes: 29 additions & 0 deletions tests/std/tests/GH_000625_vector_bool_optimization/test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1304,6 +1304,35 @@ void randomized_test_copy(mt19937_64& gen) {
}
}

#if _HAS_CXX20
template <size_t N, size_t Offset = 0>
constexpr bool test_gh_5345() {
// GH-5345 <vector>: _Copy_vbool() mishandles vector<bool>s of size 32 and 64, revealed by constexpr Clang
vector<bool> 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<bool> 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();
Expand Down