2018-08-30 Jonathan Wakely <jwakely@redhat.com>
+ * include/bits/hashtable_policy.h (__clp2): Fix calculation for LLP64
+ targets where sizeof(size_t) > sizeof(long). Avoid undefined shifts
+ of the number of bits in the type.
+ * include/std/bit (__ceil2): Avoid undefined shifts.
+ * testsuite/26_numerics/bit/bit.pow.two/ceil2.cc: Test values with
+ the most signifiant bit set.
+
* config/abi/pre/gnu.ver: Add missing exports for mingw.
* include/ext/pointer.h (_Pointer_adapter): Define operators for
// Equivalent to return __n ? std::ceil2(__n) : 0;
if (__n < 2)
return __n;
- return 1ul << (numeric_limits<unsigned long>::digits
- - __builtin_clzl(__n - 1ul));
+ const unsigned __lz = sizeof(size_t) > sizeof(long)
+ ? __builtin_clzll(__n - 1ull)
+ : __builtin_clzl(__n - 1ul);
+ // Doing two shifts avoids undefined behaviour when __lz == 0.
+ return (size_t(1) << (numeric_limits<size_t>::digits - __lz - 1)) << 1;
}
/// Rehash policy providing power of 2 bucket numbers. Avoids modulo
__ceil2(_Tp __x) noexcept
{
constexpr auto _Nd = numeric_limits<_Tp>::digits;
- if (__x == 0)
+ if (__x == 0 || __x == 1)
return 1;
- return (_Tp)1u << (_Nd - std::__countl_zero((_Tp)(__x - 1u)));
+ const unsigned __n = _Nd - std::__countl_zero((_Tp)(__x - 1u));
+ const _Tp __y_2 = (_Tp)1u << (__n - 1u);
+ return __y_2 << 1u;
}
template<typename _Tp>
static_assert( std::ceil2(UInt(3) << 64) == (UInt(4) << 64) );
}
+ constexpr UInt msb = UInt(1) << (std::numeric_limits<UInt>::digits - 1);
+ static_assert( std::ceil2( msb ) == msb );
+ // Larger values cannot be represented so the return value is unspecified,
+ // but must still be valid in constant expressions, i.e. not undefined.
+ static_assert( std::ceil2( UInt(msb + 1) ) != 77 );
+ static_assert( std::ceil2( UInt(msb + 2) ) != 77 );
+ static_assert( std::ceil2( UInt(msb + 77) ) != 77 );
+
return true;
}