diff options
author | Jonathan Wakely <jwakely@redhat.com> | 2019-07-22 17:53:27 +0100 |
---|---|---|
committer | Jonathan Wakely <redi@gcc.gnu.org> | 2019-07-22 17:53:27 +0100 |
commit | 281ab2fbff7398643352e86fcddc83098efd6310 (patch) | |
tree | 5e500b94f761c64dfe86debc7cf2745280099424 /libstdc++-v3/include/std/bit | |
parent | 462e6f9a932a44ca73715dc5c2960e5b332f63f7 (diff) | |
download | gcc-281ab2fbff7398643352e86fcddc83098efd6310.zip gcc-281ab2fbff7398643352e86fcddc83098efd6310.tar.gz gcc-281ab2fbff7398643352e86fcddc83098efd6310.tar.bz2 |
Change std::ceil2 to be undefined if the result can't be represented
* include/std/bit (__ceil2): Make unrepresentable results undefined,
as per P1355R2. Add debug assertion. Perform one left shift, not two,
so that out of range values cause undefined behaviour. Ensure that
shift will still be undefined if left operand is promoted.
* testsuite/26_numerics/bit/bit.pow.two/ceil2.cc: Replace checks for
unrepresentable values with checks that they are not core constant
expressions.
* testsuite/26_numerics/bit/bit.pow.two/ceil2_neg.cc: New test.
From-SVN: r273705
Diffstat (limited to 'libstdc++-v3/include/std/bit')
-rw-r--r-- | libstdc++-v3/include/std/bit | 24 |
1 files changed, 21 insertions, 3 deletions
diff --git a/libstdc++-v3/include/std/bit b/libstdc++-v3/include/std/bit index dd33dcf..d019b1e 100644 --- a/libstdc++-v3/include/std/bit +++ b/libstdc++-v3/include/std/bit @@ -197,9 +197,27 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION constexpr auto _Nd = numeric_limits<_Tp>::digits; if (__x == 0 || __x == 1) return 1; - const unsigned __n = _Nd - std::__countl_zero((_Tp)(__x - 1u)); - const _Tp __y_2 = (_Tp)1u << (__n - 1u); - return __y_2 << 1u; + auto __shift_exponent = _Nd - std::__countl_zero((_Tp)(__x - 1u)); + // If the shift exponent equals _Nd then the correct result is not + // representable as a value of _Tp, and so the result is undefined. + // Want that undefined behaviour to be detected in constant expressions, + // by UBSan, and by debug assertions. +#ifdef _GLIBCXX_HAVE_BUILTIN_IS_CONSTANT_EVALUATED + if (!__builtin_is_constant_evaluated()) + __glibcxx_assert( __shift_exponent != numeric_limits<_Tp>::digits ); +#endif + using __promoted_type = decltype(__x << 1); + if _GLIBCXX17_CONSTEXPR (!is_same<__promoted_type, _Tp>::value) + { + // If __x undergoes integral promotion then shifting by _Nd is + // not undefined. In order to make the shift undefined, so that + // it is diagnosed in constant expressions and by UBsan, we also + // need to "promote" the shift exponent to be too large for the + // promoted type. + const int __extra_exp = sizeof(__promoted_type) / sizeof(_Tp) / 2; + __shift_exponent |= (__shift_exponent & _Nd) << __extra_exp; + } + return (_Tp)1u << __shift_exponent; } template<typename _Tp> |