-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[libc++] Fix copy_backward for vector<bool> with small storage types #131560
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
e476d1c
to
d4e2246
Compare
d4e2246
to
e5d6a82
Compare
@llvm/pr-subscribers-libcxx Author: Peng Liu (winner245) ChangesThis patch fixes an issue in libc++ where Fixes #131718. Patch is 21.53 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/131560.diff 5 Files Affected:
diff --git a/libcxx/include/__algorithm/copy_backward.h b/libcxx/include/__algorithm/copy_backward.h
index 02ffc14361e6a..9f890645a41d3 100644
--- a/libcxx/include/__algorithm/copy_backward.h
+++ b/libcxx/include/__algorithm/copy_backward.h
@@ -52,7 +52,7 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI __bit_iterator<_Cp, false> _
difference_type __dn = std::min(static_cast<difference_type>(__last.__ctz_), __n);
__n -= __dn;
unsigned __clz = __bits_per_word - __last.__ctz_;
- __storage_type __m = (~__storage_type(0) << (__last.__ctz_ - __dn)) & (~__storage_type(0) >> __clz);
+ __storage_type __m = std::__middle_mask<__storage_type>(__clz, __last.__ctz_ - __dn);
__storage_type __b = *__last.__seg_ & __m;
*__result.__seg_ &= ~__m;
*__result.__seg_ |= __b;
@@ -69,7 +69,7 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI __bit_iterator<_Cp, false> _
__n -= __nw * __bits_per_word;
// do last word
if (__n > 0) {
- __storage_type __m = ~__storage_type(0) << (__bits_per_word - __n);
+ __storage_type __m = std::__leading_mask<__storage_type>(__bits_per_word - __n);
__storage_type __b = *--__last.__seg_ & __m;
*--__result.__seg_ &= ~__m;
*__result.__seg_ |= __b;
@@ -94,12 +94,12 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI __bit_iterator<_Cp, false> _
difference_type __dn = std::min(static_cast<difference_type>(__last.__ctz_), __n);
__n -= __dn;
unsigned __clz_l = __bits_per_word - __last.__ctz_;
- __storage_type __m = (~__storage_type(0) << (__last.__ctz_ - __dn)) & (~__storage_type(0) >> __clz_l);
+ __storage_type __m = std::__middle_mask<__storage_type>(__clz_l, __last.__ctz_ - __dn);
__storage_type __b = *__last.__seg_ & __m;
unsigned __clz_r = __bits_per_word - __result.__ctz_;
__storage_type __ddn = std::min(__dn, static_cast<difference_type>(__result.__ctz_));
if (__ddn > 0) {
- __m = (~__storage_type(0) << (__result.__ctz_ - __ddn)) & (~__storage_type(0) >> __clz_r);
+ __m = std::__middle_mask<__storage_type>(__clz_r, __result.__ctz_ - __ddn);
*__result.__seg_ &= ~__m;
if (__result.__ctz_ > __last.__ctz_)
*__result.__seg_ |= __b << (__result.__ctz_ - __last.__ctz_);
@@ -112,7 +112,7 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI __bit_iterator<_Cp, false> _
// __result.__ctz_ == 0
--__result.__seg_;
__result.__ctz_ = static_cast<unsigned>(-__dn & (__bits_per_word - 1));
- __m = ~__storage_type(0) << __result.__ctz_;
+ __m = std::__leading_mask<__storage_type>(__result.__ctz_);
*__result.__seg_ &= ~__m;
__last.__ctz_ -= __dn + __ddn;
*__result.__seg_ |= __b << (__result.__ctz_ - __last.__ctz_);
@@ -123,7 +123,7 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI __bit_iterator<_Cp, false> _
// __result.__ctz_ != 0 || __n == 0
// do middle words
unsigned __clz_r = __bits_per_word - __result.__ctz_;
- __storage_type __m = ~__storage_type(0) >> __clz_r;
+ __storage_type __m = std::__trailing_mask<__storage_type>(__clz_r);
for (; __n >= __bits_per_word; __n -= __bits_per_word) {
__storage_type __b = *--__last.__seg_;
*__result.__seg_ &= ~__m;
@@ -133,11 +133,11 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI __bit_iterator<_Cp, false> _
}
// do last word
if (__n > 0) {
- __m = ~__storage_type(0) << (__bits_per_word - __n);
+ __m = std::__leading_mask<__storage_type>(__bits_per_word - __n);
__storage_type __b = *--__last.__seg_ & __m;
__clz_r = __bits_per_word - __result.__ctz_;
__storage_type __dn = std::min(__n, static_cast<difference_type>(__result.__ctz_));
- __m = (~__storage_type(0) << (__result.__ctz_ - __dn)) & (~__storage_type(0) >> __clz_r);
+ __m = std::__middle_mask<__storage_type>(__clz_r, __result.__ctz_ - __dn);
*__result.__seg_ &= ~__m;
*__result.__seg_ |= __b >> (__bits_per_word - __result.__ctz_);
__result.__ctz_ = static_cast<unsigned>(((-__dn & (__bits_per_word - 1)) + __result.__ctz_) % __bits_per_word);
@@ -146,7 +146,7 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI __bit_iterator<_Cp, false> _
// __result.__ctz_ == 0
--__result.__seg_;
__result.__ctz_ = static_cast<unsigned>(-__n & (__bits_per_word - 1));
- __m = ~__storage_type(0) << __result.__ctz_;
+ __m = std::__leading_mask<__storage_type>(__result.__ctz_);
*__result.__seg_ &= ~__m;
*__result.__seg_ |= __b << (__result.__ctz_ - (__bits_per_word - __n - __dn));
}
diff --git a/libcxx/include/__bit_reference b/libcxx/include/__bit_reference
index 58cbd4d51c88e..f5c22fc0a3ade 100644
--- a/libcxx/include/__bit_reference
+++ b/libcxx/include/__bit_reference
@@ -82,13 +82,20 @@ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _StorageType __trailing_mask
return static_cast<_StorageType>(~static_cast<_StorageType>(0)) >> __clz;
}
+// Creates a mask of type `_StorageType` with a specified number of trailing zeros (__ctz) and sets all remaining
+// bits to one.
+template <class _StorageType>
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _StorageType __leading_mask(unsigned __ctz) {
+ static_assert(is_unsigned<_StorageType>::value, "__leading_mask only works with unsigned types");
+ return static_cast<_StorageType>(~static_cast<_StorageType>(0)) << __ctz;
+}
+
// Creates a mask of type `_StorageType` with a specified number of leading zeros (__clz), a specified number of
// trailing zeros (__ctz), and sets all bits in between to one.
template <class _StorageType>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _StorageType __middle_mask(unsigned __clz, unsigned __ctz) {
static_assert(is_unsigned<_StorageType>::value, "__middle_mask only works with unsigned types");
- return (static_cast<_StorageType>(~static_cast<_StorageType>(0)) << __ctz) &
- std::__trailing_mask<_StorageType>(__clz);
+ return std::__leading_mask<_StorageType>(__ctz) & std::__trailing_mask<_StorageType>(__clz);
}
// This function is designed to operate correctly even for smaller integral types like `uint8_t`, `uint16_t`,
diff --git a/libcxx/include/__fwd/bit_reference.h b/libcxx/include/__fwd/bit_reference.h
index e212667f3de1f..99d1fdbc41959 100644
--- a/libcxx/include/__fwd/bit_reference.h
+++ b/libcxx/include/__fwd/bit_reference.h
@@ -33,6 +33,9 @@ __fill_masked_range(_StoragePointer __word, unsigned __ctz, unsigned __clz, bool
template <class _StorageType>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _StorageType __trailing_mask(unsigned __clz);
+template <class _StorageType>
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _StorageType __leading_mask(unsigned __ctz);
+
template <class _StorageType>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _StorageType __middle_mask(unsigned __clz, unsigned __ctz);
diff --git a/libcxx/test/std/algorithms/alg.modifying.operations/alg.copy/copy_backward.pass.cpp b/libcxx/test/std/algorithms/alg.modifying.operations/alg.copy/copy_backward.pass.cpp
index 8a528a96f5294..def192d4d6637 100644
--- a/libcxx/test/std/algorithms/alg.modifying.operations/alg.copy/copy_backward.pass.cpp
+++ b/libcxx/test/std/algorithms/alg.modifying.operations/alg.copy/copy_backward.pass.cpp
@@ -13,10 +13,13 @@
// constexpr OutIter // constexpr after C++17
// copy_backward(InIter first, InIter last, OutIter result);
+// XFAIL: FROZEN-CXX03-HEADERS-FIXME
+
#include <algorithm>
#include <cassert>
#include <vector>
+#include "sized_allocator.h"
#include "test_macros.h"
#include "test_iterators.h"
#include "type_algorithms.h"
@@ -111,6 +114,146 @@ TEST_CONSTEXPR_CXX20 bool test() {
assert(test_vector_bool(256));
}
+ // Validate std::copy_backward with std::vector<bool> iterators and custom storage types.
+ // Ensure that assigned bits hold the intended values, while unassigned bits stay unchanged.
+ // Related issue: https://github.com/llvm/llvm-project/issues/131718.
+ {
+ //// Tests for std::copy_backward with aligned bits
+
+ { // Test the first (partial) word for uint8_t
+ using Alloc = sized_allocator<bool, std::uint8_t, std::int8_t>;
+ std::vector<bool, Alloc> in(7, false, Alloc(1));
+ std::vector<bool, Alloc> out(8, true, Alloc(1));
+ std::copy_backward(in.begin(), in.begin() + 1, out.begin() + 1);
+ assert(out[0] == false);
+ for (std::size_t i = 1; i < out.size(); ++i)
+ assert(out[i] == true);
+ }
+ { // Test the last (partial) word for uint8_t
+ using Alloc = sized_allocator<bool, std::uint8_t, std::int8_t>;
+ std::vector<bool, Alloc> in(8, false, Alloc(1));
+ for (std::size_t i = 0; i < in.size(); i += 2)
+ in[i] = true;
+ std::vector<bool, Alloc> out(8, true, Alloc(1));
+ std::copy_backward(in.end() - 4, in.end(), out.end());
+ for (std::size_t i = 0; i < static_cast<std::size_t>(in.size() - 4); ++i)
+ assert(out[i] == true);
+ for (std::size_t i = in.size() + 4; i < out.size(); ++i)
+ assert(in[i] == out[i]);
+ }
+ { // Test the middle (whole) words for uint8_t
+ using Alloc = sized_allocator<bool, std::uint8_t, std::int8_t>;
+ std::vector<bool, Alloc> in(17, false, Alloc(1));
+ for (std::size_t i = 0; i < in.size(); i += 2)
+ in[i] = true;
+ std::vector<bool, Alloc> out(24, true, Alloc(1));
+ std::copy_backward(in.begin(), in.end(), out.begin() + in.size());
+ for (std::size_t i = 0; i < in.size(); ++i)
+ assert(in[i] == out[i]);
+ for (std::size_t i = in.size(); i < out.size(); ++i)
+ assert(out[i] == true);
+ }
+
+ { // Test the first (partial) word for uint16_t
+ using Alloc = sized_allocator<bool, std::uint16_t, std::int16_t>;
+ std::vector<bool, Alloc> in(14, false, Alloc(1));
+ std::vector<bool, Alloc> out(16, true, Alloc(1));
+ std::copy_backward(in.begin(), in.begin() + 2, out.begin() + 2);
+ assert(out[0] == false);
+ assert(out[1] == false);
+ for (std::size_t i = 2; i < out.size(); ++i)
+ assert(out[i] == true);
+ }
+ { // Test the last (partial) word for uint16_t
+ using Alloc = sized_allocator<bool, std::uint16_t, std::int16_t>;
+ std::vector<bool, Alloc> in(16, false, Alloc(1));
+ for (std::size_t i = 0; i < in.size(); i += 2)
+ in[i] = true;
+ std::vector<bool, Alloc> out(16, true, Alloc(1));
+ std::copy_backward(in.end() - 8, in.end(), out.end());
+ for (std::size_t i = 0; i < static_cast<std::size_t>(in.size() - 8); ++i)
+ assert(out[i] == true);
+ for (std::size_t i = in.size() + 8; i < out.size(); ++i)
+ assert(in[i] == out[i]);
+ }
+ { // Test the middle (whole) words for uint16_t
+ using Alloc = sized_allocator<bool, std::uint16_t, std::int16_t>;
+ std::vector<bool, Alloc> in(34, false, Alloc(1));
+ for (std::size_t i = 0; i < in.size(); i += 2)
+ in[i] = true;
+ std::vector<bool, Alloc> out(48, true, Alloc(1));
+ std::copy_backward(in.begin(), in.end(), out.begin() + in.size());
+ for (std::size_t i = 0; i < in.size(); ++i)
+ assert(in[i] == out[i]);
+ for (std::size_t i = in.size(); i < out.size(); ++i)
+ assert(out[i] == true);
+ }
+
+ //// Tests for std::copy_backward with unaligned bits
+
+ { // Test the first (partial) word for uint8_t
+ using Alloc = sized_allocator<bool, std::uint8_t, std::int8_t>;
+ std::vector<bool, Alloc> in(8, false, Alloc(1));
+ std::vector<bool, Alloc> out(8, true, Alloc(1));
+ std::copy_backward(in.begin(), in.begin() + 1, out.begin() + 1);
+ assert(out[0] == false);
+ for (std::size_t i = 1; i < out.size(); ++i)
+ assert(out[i] == true);
+ }
+ { // Test the last (partial) word for uint8_t
+ using Alloc = sized_allocator<bool, std::uint8_t, std::int8_t>;
+ std::vector<bool, Alloc> in(8, false, Alloc(1));
+ std::vector<bool, Alloc> out(8, true, Alloc(1));
+ std::copy_backward(in.end() - 1, in.end(), out.begin() + 1);
+ assert(out[0] == false);
+ for (std::size_t i = 1; i < out.size(); ++i)
+ assert(out[i] == true);
+ }
+ { // Test the middle (whole) words for uint8_t
+ using Alloc = sized_allocator<bool, std::uint8_t, std::int8_t>;
+ std::vector<bool, Alloc> in(16, false, Alloc(1));
+ for (std::size_t i = 0; i < in.size(); i += 2)
+ in[i] = true;
+ std::vector<bool, Alloc> out(17, true, Alloc(1));
+ std::copy_backward(in.begin(), in.end(), out.end());
+ assert(out[0] == true);
+ for (std::size_t i = 0; i < in.size(); ++i)
+ assert(in[i] == out[i + 1]);
+ }
+
+ { // Test the first (partial) word for uint16_t
+ using Alloc = sized_allocator<bool, std::uint16_t, std::int16_t>;
+ std::vector<bool, Alloc> in(16, false, Alloc(1));
+ std::vector<bool, Alloc> out(16, true, Alloc(1));
+ std::copy_backward(in.begin(), in.begin() + 2, out.begin() + 2);
+ assert(out[0] == false);
+ assert(out[1] == false);
+ for (std::size_t i = 2; i < out.size(); ++i)
+ assert(out[i] == true);
+ }
+ { // Test the last (partial) word for uint16_t
+ using Alloc = sized_allocator<bool, std::uint16_t, std::int16_t>;
+ std::vector<bool, Alloc> in(16, false, Alloc(1));
+ std::vector<bool, Alloc> out(16, true, Alloc(1));
+ std::copy_backward(in.end() - 2, in.end(), out.begin() + 2);
+ assert(out[0] == false);
+ assert(out[1] == false);
+ for (std::size_t i = 2; i < out.size(); ++i)
+ assert(out[i] == true);
+ }
+ { // Test the middle (whole) words for uint16_t
+ using Alloc = sized_allocator<bool, std::uint16_t, std::int16_t>;
+ std::vector<bool, Alloc> in(32, false, Alloc(1));
+ for (std::size_t i = 0; i < in.size(); i += 2)
+ in[i] = true;
+ std::vector<bool, Alloc> out(33, true, Alloc(1));
+ std::copy_backward(in.begin(), in.end(), out.end());
+ assert(out[0] == true);
+ for (std::size_t i = 0; i < in.size(); ++i)
+ assert(in[i] == out[i + 1]);
+ }
+ }
+
return true;
}
diff --git a/libcxx/test/std/algorithms/alg.modifying.operations/alg.copy/ranges.copy_backward.pass.cpp b/libcxx/test/std/algorithms/alg.modifying.operations/alg.copy/ranges.copy_backward.pass.cpp
index a7fa3db23e6ba..e7251ab905db5 100644
--- a/libcxx/test/std/algorithms/alg.modifying.operations/alg.copy/ranges.copy_backward.pass.cpp
+++ b/libcxx/test/std/algorithms/alg.modifying.operations/alg.copy/ranges.copy_backward.pass.cpp
@@ -28,6 +28,7 @@
#include <vector>
#include "almost_satisfies_types.h"
+#include "sized_allocator.h"
#include "test_iterators.h"
#include "test_macros.h"
@@ -355,6 +356,146 @@ constexpr bool test() {
assert(test_vector_bool(199));
assert(test_vector_bool(256));
}
+
+ // Validate std::ranges::copy_backward with std::vector<bool> iterators and custom storage types.
+ // Ensure that assigned bits hold the intended values, while unassigned bits stay unchanged.
+ // Related issue: https://github.com/llvm/llvm-project/issues/131718.
+ {
+ //// Tests for std::ranges::copy_backward with aligned bits
+
+ { // Test the first (partial) word for uint8_t
+ using Alloc = sized_allocator<bool, std::uint8_t, std::int8_t>;
+ std::vector<bool, Alloc> in(7, false, Alloc(1));
+ std::vector<bool, Alloc> out(8, true, Alloc(1));
+ std::ranges::copy_backward(std::ranges::subrange(in.begin(), in.begin() + 1), out.begin() + 1);
+ assert(out[0] == false);
+ for (std::size_t i = 1; i < out.size(); ++i)
+ assert(out[i] == true);
+ }
+ { // Test the last (partial) word for uint8_t
+ using Alloc = sized_allocator<bool, std::uint8_t, std::int8_t>;
+ std::vector<bool, Alloc> in(8, false, Alloc(1));
+ for (std::size_t i = 0; i < in.size(); i += 2)
+ in[i] = true;
+ std::vector<bool, Alloc> out(8, true, Alloc(1));
+ std::ranges::copy_backward(std::ranges::subrange(in.end() - 4, in.end()), out.end());
+ for (std::size_t i = 0; i < static_cast<std::size_t>(in.size() - 4); ++i)
+ assert(out[i] == true);
+ for (std::size_t i = in.size() + 4; i < out.size(); ++i)
+ assert(in[i] == out[i]);
+ }
+ { // Test the middle (whole) words for uint8_t
+ using Alloc = sized_allocator<bool, std::uint8_t, std::int8_t>;
+ std::vector<bool, Alloc> in(17, false, Alloc(1));
+ for (std::size_t i = 0; i < in.size(); i += 2)
+ in[i] = true;
+ std::vector<bool, Alloc> out(24, true, Alloc(1));
+ std::ranges::copy_backward(std::ranges::subrange(in.begin(), in.end()), out.begin() + in.size());
+ for (std::size_t i = 0; i < in.size(); ++i)
+ assert(in[i] == out[i]);
+ for (std::size_t i = in.size(); i < out.size(); ++i)
+ assert(out[i] == true);
+ }
+
+ { // Test the first (partial) word for uint16_t
+ using Alloc = sized_allocator<bool, std::uint16_t, std::int16_t>;
+ std::vector<bool, Alloc> in(14, false, Alloc(1));
+ std::vector<bool, Alloc> out(16, true, Alloc(1));
+ std::ranges::copy_backward(std::ranges::subrange(in.begin(), in.begin() + 2), out.begin() + 2);
+ assert(out[0] == false);
+ assert(out[1] == false);
+ for (std::size_t i = 2; i < out.size(); ++i)
+ assert(out[i] == true);
+ }
+ { // Test the last (partial) word for uint16_t
+ using Alloc = sized_allocator<bool, std::uint16_t, std::int16_t>;
+ std::vector<bool, Alloc> in(16, false, Alloc(1));
+ for (std::size_t i = 0; i < in.size(); i += 2)
+ in[i] = true;
+ std::vector<bool, Alloc> out(16, true, Alloc(1));
+ std::ranges::copy_backward(std::ranges::subrange(in.end() - 8, in.end()), out.end());
+ for (std::size_t i = 0; i < static_cast<std::size_t>(in.size() - 8); ++i)
+ assert(out[i] == true);
+ for (std::size_t i = in.size() + 8; i < out.size(); ++i)
+ assert(in[i] == out[i]);
+ }
+ { // Test the middle (whole) words for uint16_t
+ using Alloc = sized_allocator<bool, std::uint16_t, std::int16_t>;
+ std::vector<bool, Alloc> in(34, false, Alloc(1));
+ for (std::size_t i = 0; i < in.size(); i += 2)
+ in[i] = true;
+ std::vector<bool, Alloc> out(48, true, Alloc(1));
+ std::ranges::copy_backward(std::ranges::subrange(in.begin(), in.end()), out.begin() + in.size());
+ for (std::size_t i = 0; i < in.size(); ++i)
+ assert(in[i] == out[i]);
+ for (std::size_t i = in.size(); i < out.size(); ++i)
+ assert(out[i] == true);
+ }
+
+ //// Tests for std::ranges::copy_backward with unaligned bits
+
+ { // Test the first (partial) word for uint8_t
+ using Alloc = sized_allocator<bool, std::uint8_t, std::int8_t>;
+ std::vector<bool, Alloc> in(8, false, Alloc(1));
+ std::vector<bool, Alloc> out(8, true, Alloc(1));
+ std::ranges::copy_backward(std::ranges::subrange(in.begin(), in.begin() + 1), out.begin() + 1);
+ assert(out[0] == false);
+ for (std::size_t i = 1; i < out.size(); ++i)
+ assert(out[i] == true);
+ }
+ { // Test the last (partial) word for uint8_t
+ using Alloc = sized_allocator<bool, std::uint8_t, std::int8_t>;
+ std::vector<bool, Alloc> in(8, false, Alloc(1));
+ std::vector<bool, Alloc> out(8, true, Alloc(1));
+ std::ranges::copy_backward(std::ranges::subrange(in.end() - 1, in.end()), out.begin() + 1);
+ assert(out[0] == false);
+ for (std::size_t i = 1; i < out.size(); ++i)
+ assert(out[i] == true);
+ }
+ { // Test the middle (whole) words for uint8_t
+ using Alloc = sized_allocator<bool, std::uint8_t, std::int8_t>;
+ std::vector<bool, Alloc> in(16, false, Alloc(1));
+ for (std::size_t i = 0; i < in.size(); i += 2)
+ in[i] = true;
+ std::vector<bool, Alloc> out(17, true, Alloc(1));
+ std::ranges::copy_backward(std::ranges::subrange(in.begin(), in.end()), out.end());
+ assert(out[0] == true);
+ for (std::size_t i = 0; i < in.size(); ++i)
+ assert(in[i] == out[i + 1]...
[truncated]
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the patches, and especially for the structured approach to fixing all of these issues! This makes reviewing a lot easier and it also makes it easier to focus on a single problem at a time, which often has the side effect of increased quality of the fix + its tests.
This patch fixes an issue in libc++ where
std::copy_backward
andranges::copy_backward
incorrectly copystd::vector<bool>
with small storage types (e.g.,uint8_t
,uint16_t
). The problem arises from flawed bit mask computations involving integral promotions and sign-bit extension, leading to unintended zeroing of bits. This patch corrects the bitwise operations to ensure correct bit-level copying.Fixes #131718.