https://gcc.gnu.org/g:bd3a312728fbf8c35a09239b9180269f938f872e
commit r15-1213-gbd3a312728fbf8c35a09239b9180269f938f872e Author: Jonathan Wakely <jwak...@redhat.com> Date: Mon Jun 10 14:08:16 2024 +0100 libstdc++: Fix std::tr2::dynamic_bitset shift operations [PR115399] The shift operations for dynamic_bitset fail to zero out words where the non-zero bits were shifted to a completely different word. For a right shift we don't need to sanitize the unused bits in the high word, because we know they were already clear and a right shift doesn't change that. libstdc++-v3/ChangeLog: PR libstdc++/115399 * include/tr2/dynamic_bitset (operator>>=): Remove redundant call to _M_do_sanitize. * include/tr2/dynamic_bitset.tcc (_M_do_left_shift): Zero out low bits in words that should no longer be populated. (_M_do_right_shift): Likewise for high bits. * testsuite/tr2/dynamic_bitset/pr115399.cc: New test. Diff: --- libstdc++-v3/include/tr2/dynamic_bitset | 5 +-- libstdc++-v3/include/tr2/dynamic_bitset.tcc | 6 ++-- .../testsuite/tr2/dynamic_bitset/pr115399.cc | 37 ++++++++++++++++++++++ 3 files changed, 40 insertions(+), 8 deletions(-) diff --git a/libstdc++-v3/include/tr2/dynamic_bitset b/libstdc++-v3/include/tr2/dynamic_bitset index 0e4e88942870..274c4f6a1386 100644 --- a/libstdc++-v3/include/tr2/dynamic_bitset +++ b/libstdc++-v3/include/tr2/dynamic_bitset @@ -815,10 +815,7 @@ namespace tr2 operator>>=(size_type __pos) { if (__builtin_expect(__pos < this->_M_Nb, 1)) - { - this->_M_do_right_shift(__pos); - this->_M_do_sanitize(); - } + this->_M_do_right_shift(__pos); else this->_M_do_reset(); return *this; diff --git a/libstdc++-v3/include/tr2/dynamic_bitset.tcc b/libstdc++-v3/include/tr2/dynamic_bitset.tcc index 63ba6f285c7a..5aac7d88ee37 100644 --- a/libstdc++-v3/include/tr2/dynamic_bitset.tcc +++ b/libstdc++-v3/include/tr2/dynamic_bitset.tcc @@ -60,8 +60,7 @@ namespace tr2 this->_M_w[__wshift] = this->_M_w[0] << __offset; } - //// std::fill(this->_M_w.begin(), this->_M_w.begin() + __wshift, - //// static_cast<_WordT>(0)); + std::fill_n(this->_M_w.begin(), __wshift, _WordT(0)); } } @@ -88,8 +87,7 @@ namespace tr2 this->_M_w[__limit] = this->_M_w[_M_w.size()-1] >> __offset; } - ////std::fill(this->_M_w.begin() + __limit + 1, this->_M_w.end(), - //// static_cast<_WordT>(0)); + std::fill_n(this->_M_w.end() - __wshift, __wshift, _WordT(0)); } } diff --git a/libstdc++-v3/testsuite/tr2/dynamic_bitset/pr115399.cc b/libstdc++-v3/testsuite/tr2/dynamic_bitset/pr115399.cc new file mode 100644 index 000000000000..e626e4a5d156 --- /dev/null +++ b/libstdc++-v3/testsuite/tr2/dynamic_bitset/pr115399.cc @@ -0,0 +1,37 @@ +// { dg-do run { target c++11 } } + +// PR libstdc++/115399 +// std::tr2::dynamic_bitset shift behaves differently from std::bitset + +#include <tr2/dynamic_bitset> +#include <testsuite_hooks.h> + +void +test_left_shift() +{ + std::tr2::dynamic_bitset<> b(65); + b[0] = 1; + auto b2 = b << 64; + VERIFY(b2[64] == 1); + VERIFY(b2[0] == 0); + b <<= 64; + VERIFY( b2 == b ); +} + +void +test_right_shift() +{ + std::tr2::dynamic_bitset<> b(65); + b[64] = 1; + auto b2 = b >> 64; + VERIFY(b2[64] == 0); + VERIFY(b2[0] == 1); + b >>= 64; + VERIFY( b2 == b ); +} + +int main() +{ + test_left_shift(); + test_right_shift(); +}