Adds MSVC support to the `<bit>` functions.
This commit is contained in:
Charlie Barto 2020-07-01 20:27:49 -07:00 коммит произвёл GitHub
Родитель afcf7b608d
Коммит 5e3423a377
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
11 изменённых файлов: 260 добавлений и 98 удалений

Просмотреть файл

@ -12,6 +12,8 @@
#pragma message("The contents of <bit> are available only with C++20 or later.")
#else // ^^^ !_HAS_CXX20 / _HAS_CXX20 vvv
#include <intrin0.h>
#include <isa_availability.h>
#include <limits>
#include <type_traits>
@ -23,6 +25,7 @@ _STL_DISABLE_CLANG_WARNINGS
#undef new
_STD_BEGIN
template <class _To, class _From,
enable_if_t<conjunction_v<bool_constant<sizeof(_To) == sizeof(_From)>, is_trivially_copyable<_To>,
is_trivially_copyable<_From>>,
@ -31,7 +34,6 @@ _NODISCARD constexpr _To bit_cast(const _From& _Val) noexcept {
return __builtin_bit_cast(_To, _Val);
}
#ifdef __cpp_lib_bitops // TRANSITION, VSO-1020212
template <class _Ty, enable_if_t<_Is_standard_unsigned_integer<_Ty>, int> = 0>
_NODISCARD constexpr int countl_zero(_Ty _Val) noexcept;
@ -94,17 +96,126 @@ _NODISCARD constexpr _Ty rotr(const _Ty _Val, const int _Rotation) noexcept {
}
}
template <class _Ty, enable_if_t<_Is_standard_unsigned_integer<_Ty>, int> _Enabled>
_NODISCARD constexpr int countl_zero(const _Ty _Val) noexcept {
// Implementation of popcount without using specialized CPU instructions.
// Used at compile time and when said instructions are not supported.
template <class _Ty>
_NODISCARD constexpr int _Popcount_fallback(_Ty _Val) noexcept {
constexpr int _Digits = numeric_limits<_Ty>::digits;
// we static_cast these bit patterns in order to truncate them to the correct size
_Val = static_cast<_Ty>(_Val - ((_Val >> 1) & static_cast<_Ty>(0x5555'5555'5555'5555ull)));
_Val = static_cast<_Ty>((_Val & static_cast<_Ty>(0x3333'3333'3333'3333ull))
+ ((_Val >> 2) & static_cast<_Ty>(0x3333'3333'3333'3333ull)));
_Val = static_cast<_Ty>((_Val + (_Val >> 4)) & static_cast<_Ty>(0x0F0F'0F0F'0F0F'0F0Full));
for (int _Shift_digits = 8; _Shift_digits < _Digits; _Shift_digits <<= 1) {
_Val = static_cast<_Ty>(_Val + static_cast<_Ty>(_Val >> _Shift_digits));
}
// we want the bottom "slot" that's big enough to store _Digits
return static_cast<int>(_Val & static_cast<_Ty>(_Digits + _Digits - 1));
}
#if defined(_M_IX86) || defined(_M_X64)
// TRANSITION, VS 2019 16.8 Preview 1, intrin0.h will declare __lzcnt* and __popcnt*
extern "C" {
__MACHINEX86_X64(unsigned int __lzcnt(unsigned int))
__MACHINEX86_X64(unsigned short __lzcnt16(unsigned short))
__MACHINEX64(unsigned __int64 __lzcnt64(unsigned __int64))
__MACHINEX86_X64(unsigned int __popcnt(unsigned int))
__MACHINEX86_X64(unsigned short __popcnt16(unsigned short))
__MACHINEX64(unsigned __int64 __popcnt64(unsigned __int64))
extern int __isa_available;
}
template <class _Ty>
_NODISCARD int _Checked_x86_x64_countl_zero(const _Ty _Val) noexcept {
constexpr int _Digits = numeric_limits<_Ty>::digits;
#ifndef __AVX2__
const bool _Have_lzcnt = __isa_available >= __ISA_AVAILABLE_AVX2;
// lzcnt (when it doesn't fall back to bsr) is defined correctly for zero
// bsr has undefined output for zero
if (!_Have_lzcnt && _Val == 0) {
return _Digits;
}
#endif // __AVX2__
// We use lzcnt (actually bsr if lzcnt is not supported) now that we know
// we're not zero. We can do this because lzcnt and bsr share the same instruction
// encoding.
if constexpr (_Digits <= 16) {
return static_cast<int>(__lzcnt16(_Val) - (16 - _Digits));
} else if constexpr (_Digits == 32) {
return static_cast<int>(__lzcnt(_Val));
} else {
#ifdef _M_IX86
const unsigned int _High = _Val >> 32;
const auto _Low = static_cast<unsigned int>(_Val);
if (_High == 0) {
return 32 + _Checked_x86_x64_countl_zero(_Low);
} else {
return _Checked_x86_x64_countl_zero(_High);
}
#else // ^^^ _M_IX86 / !_M_IX86 vvv
return static_cast<int>(__lzcnt64(_Val));
#endif // _M_IX86
}
// note: we don't need to call a fallback here because
// all supported x86 processors at least have bsr/bsf
}
template <class _Ty>
_NODISCARD int _Checked_x86_x64_popcount(const _Ty _Val) noexcept {
constexpr int _Digits = numeric_limits<_Ty>::digits;
#ifndef __AVX__
const bool _Have_popcnt = __isa_available >= __ISA_AVAILABLE_SSE42;
if (!_Have_popcnt) {
return _Popcount_fallback(_Val);
}
#endif // !defined(__AVX__)
if constexpr (_Digits <= 16) {
return static_cast<int>(__popcnt16(_Val));
} else if constexpr (_Digits == 32) {
return static_cast<int>(__popcnt(_Val));
} else {
#ifdef _M_IX86
return static_cast<int>(__popcnt(_Val >> 32) + __popcnt(static_cast<unsigned int>(_Val)));
#else // ^^^ _M_IX86 / !_M_IX86 vvv
return static_cast<int>(__popcnt64(_Val));
#endif // _M_IX86
}
}
#endif // defined(_M_IX86) || defined(_M_X64)
#if defined(_M_ARM) || defined(_M_ARM64)
template <class _Ty>
_NODISCARD int _Checked_arm_arm64_countl_zero(const _Ty _Val) noexcept {
constexpr int _Digits = numeric_limits<_Ty>::digits;
if (_Val == 0) {
return _Digits;
}
if constexpr (sizeof(_Ty) <= sizeof(unsigned int)) {
return __builtin_clz(_Val) - (numeric_limits<unsigned int>::digits - _Digits);
if constexpr (_Digits <= 32) {
return _CountLeadingZeros(_Val);
} else {
return __builtin_clzll(_Val) - (numeric_limits<unsigned long long>::digits - _Digits);
return _CountLeadingZeros64(_Val);
}
}
#endif // defined(_M_ARM) || defined(_M_ARM64)
template <class _Ty, enable_if_t<_Is_standard_unsigned_integer<_Ty>, int> _Enabled>
_NODISCARD constexpr int countl_zero(const _Ty _Val) noexcept {
if (_STD is_constant_evaluated()) {
return _Countl_zero_fallback(_Val);
} else {
#if defined(_M_IX86) || defined(_M_X64)
return _Checked_x86_x64_countl_zero(_Val);
#elif defined(_M_ARM) || defined(_M_ARM64)
return _Checked_arm_arm64_countl_zero(_Val);
#else
#error Unsupported Hardware
#endif
}
}
@ -125,17 +236,17 @@ _NODISCARD constexpr int countr_one(const _Ty _Val) noexcept {
template <class _Ty, enable_if_t<_Is_standard_unsigned_integer<_Ty>, int> _Enabled = 0>
_NODISCARD constexpr int popcount(const _Ty _Val) noexcept {
if constexpr (sizeof(_Ty) <= sizeof(unsigned int)) {
return __builtin_popcount(_Val);
} else {
return __builtin_popcountll(_Val);
#if defined(_M_IX86) || defined(_M_X64)
if (!_STD is_constant_evaluated()) {
return _Checked_x86_x64_popcount(_Val);
}
#endif // defined(_M_IX86) || defined(_M_X64)
return _Popcount_fallback(_Val);
}
#endif // __cpp_lib_bitops
enum class endian { little = 0, big = 1, native = little };
_STD_END
_STD_END
#pragma pop_macro("new")
_STL_RESTORE_CLANG_WARNINGS
#pragma warning(pop)

Просмотреть файл

@ -11,6 +11,8 @@
#include <cfloat>
#include <climits>
#include <cwchar>
#include <intrin0.h>
#include <isa_availability.h>
#include <xstddef>
#pragma pack(push, _CRT_PACKING)
@ -1009,24 +1011,102 @@ public:
static constexpr int min_exponent10 = LDBL_MIN_10_EXP;
};
#ifdef __cpp_lib_bitops // TRANSITION, VSO-1020212
// Implementation of countl_zero without using specialized CPU instructions.
// Used at compile time and when said instructions are not supported.
// see "Hacker's Delight" section 5-3
template <class _Ty>
inline constexpr bool _Is_standard_unsigned_integer =
_NODISCARD constexpr int _Countl_zero_fallback(_Ty _Val) noexcept {
_Ty _Yy = 0;
unsigned int _Nn = numeric_limits<_Ty>::digits;
unsigned int _Cc = numeric_limits<_Ty>::digits / 2;
do {
_Yy = static_cast<_Ty>(_Val >> _Cc);
if (_Yy != 0) {
_Nn -= _Cc;
_Val = _Yy;
}
_Cc >>= 1;
} while (_Cc != 0);
return static_cast<int>(_Nn) - static_cast<int>(_Val);
}
// Implementation of countr_zero without using specialized CPU instructions.
// Used at compile time and when said instructions are not supported.
// see "Hacker's Delight" section 5-4
template <class _Ty>
_NODISCARD constexpr int _Countr_zero_fallback(const _Ty _Val) noexcept {
constexpr int _Digits = std::numeric_limits<_Ty>::digits;
return _Digits - _Countl_zero_fallback(static_cast<_Ty>(static_cast<_Ty>(~_Val) & static_cast<_Ty>(_Val - 1)));
}
#if defined(_M_IX86) || defined(_M_X64)
// TRANSITION, VS 2019 16.8 Preview 1, intrin0.h will declare _tzcnt*
extern "C" {
extern int __isa_available;
#ifdef __clang__
#define _TZCNT_U32 __builtin_ia32_tzcnt_u32
#define _TZCNT_U64 __builtin_ia32_tzcnt_u64
#else // ^^^ __clang__ / !__clang__ vvv
__MACHINEX86_X64(unsigned int _tzcnt_u32(unsigned int))
__MACHINEX64(unsigned __int64 _tzcnt_u64(unsigned __int64));
#define _TZCNT_U32 _tzcnt_u32
#define _TZCNT_U64 _tzcnt_u64
#endif // __clang__
}
template <class _Ty>
_NODISCARD int _Checked_x86_x64_countr_zero(const _Ty _Val) noexcept {
constexpr int _Digits = numeric_limits<_Ty>::digits;
constexpr _Ty _Max = (numeric_limits<_Ty>::max)();
#ifndef __AVX2__
const bool _Have_tzcnt = __isa_available >= __ISA_AVAILABLE_AVX2;
if (!_Have_tzcnt && _Val == 0) {
return _Digits;
}
#endif // __AVX2__
if constexpr (_Digits <= 32) {
// Intended widening to int. This operation means that a narrow 0 will widen
// to 0xFFFF....FFFF0... instead of 0. We need this to avoid counting all the zeros
// of the wider type.
return static_cast<int>(_TZCNT_U32(static_cast<unsigned int>(~_Max | _Val)));
} else {
#ifdef _M_IX86
const unsigned int _High = _Val >> 32;
const unsigned int _Low = static_cast<unsigned int>(_Val);
if (_Low == 0) {
return 32 + _Checked_x86_x64_countr_zero(_High);
} else {
return _Checked_x86_x64_countr_zero(_Low);
}
#else // ^^^ _M_IX86 / !_M_IX86 vvv
return static_cast<int>(_TZCNT_U64(_Val));
#endif // _M_IX86
}
}
#undef _TZCNT_U32
#undef _TZCNT_U64
#endif // defined(_M_IX86) || defined(_M_X64)
template <class _Ty>
constexpr bool _Is_standard_unsigned_integer =
_Is_any_of_v<remove_cv_t<_Ty>, unsigned char, unsigned short, unsigned int, unsigned long, unsigned long long>;
template <class _Ty, enable_if_t<_Is_standard_unsigned_integer<_Ty>, int> = 0>
_NODISCARD constexpr int _Countr_zero(const _Ty _Val) noexcept {
if (_Val == 0) {
return numeric_limits<_Ty>::digits;
}
if constexpr (sizeof(_Ty) <= sizeof(unsigned int)) {
return __builtin_ctz(_Val);
} else {
return __builtin_ctzll(_Val);
#if defined(_M_IX86) || defined(_M_X64)
#ifdef __cpp_lib_is_constant_evaluated
if (!_STD is_constant_evaluated()) {
return _Checked_x86_x64_countr_zero(_Val);
}
#endif // defined(__cpp_lib_is_constant_evaluated)
#endif // defined(_M_IX86) || defined(_M_X64)
// C++17 constexpr gcd() calls this function, so it should be constexpr unless we detect runtime evaluation.
return _Countr_zero_fallback(_Val);
}
#endif // __cpp_lib_bitops
_STD_END
#pragma pop_macro("new")

Просмотреть файл

@ -10,9 +10,9 @@
#if _STL_COMPILER_PREPROCESSOR
#include <xutility>
#if _HAS_CXX20
#if _HAS_CXX17
#include <limits>
#endif // _HAS_CXX20
#endif // _HAS_CXX17
#pragma pack(push, _CRT_PACKING)
#pragma warning(push, _STL_WARNING_LEVEL)
@ -560,26 +560,6 @@ _NODISCARD constexpr auto _Abs_u(const _Arithmetic _Val) noexcept {
}
}
// FUNCTION TEMPLATE _Stl_bitscan_forward
template <class _Unsigned>
_NODISCARD constexpr unsigned long _Stl_bitscan_forward(_Unsigned _Mask) noexcept {
#ifdef __cpp_lib_bitops // TRANSITION, VSO-1020212
return static_cast<unsigned long>(_Countr_zero(_Mask));
#else // ^^^ __cpp_lib_bitops / !__cpp_lib_bitops vvv
// find the index of the least significant set bit (_BitScanForward isn't constexpr... yet :))
static_assert(is_unsigned_v<_Unsigned>, "Bitscan only works on bits");
unsigned long _Count = 0;
if (_Mask != 0) {
while ((_Mask & 1U) == 0) {
_Mask >>= 1;
++_Count;
}
}
return _Count;
#endif // !__cpp_lib_bitops
}
// FUNCTION TEMPLATE gcd
template <class _Mt, class _Nt>
_NODISCARD constexpr common_type_t<_Mt, _Nt> gcd(const _Mt _Mx, const _Nt _Nx) noexcept /* strengthened */ {
@ -598,12 +578,13 @@ _NODISCARD constexpr common_type_t<_Mt, _Nt> gcd(const _Mt _Mx, const _Nt _Nx) n
return static_cast<_Common>(_Mx_magnitude);
}
const auto _Mx_trailing_zeroes = _Stl_bitscan_forward(_Mx_magnitude);
const auto _Common_factors_of_2 = (_STD min)(_Mx_trailing_zeroes, _Stl_bitscan_forward(_Nx_magnitude));
const auto _Mx_trailing_zeroes = static_cast<unsigned long>(_Countr_zero(_Mx_magnitude));
const auto _Common_factors_of_2 =
(_STD min)(_Mx_trailing_zeroes, static_cast<unsigned long>(_Countr_zero(_Nx_magnitude)));
_Nx_magnitude >>= _Common_factors_of_2;
_Mx_magnitude >>= _Mx_trailing_zeroes;
do {
_Nx_magnitude >>= _Stl_bitscan_forward(_Nx_magnitude);
_Nx_magnitude >>= static_cast<unsigned long>(_Countr_zero(_Nx_magnitude));
if (_Mx_magnitude > _Nx_magnitude) {
_Common_unsigned _Temp = _Mx_magnitude;
_Mx_magnitude = _Nx_magnitude;

Просмотреть файл

@ -1842,13 +1842,6 @@ inline constexpr bool is_nothrow_invocable_r_v =
_Select_invoke_traits<_Callable, _Args...>::template _Is_nothrow_invocable_r<_Rx>::value;
#endif // _HAS_CXX17
#if _HAS_CXX20
// FUNCTION is_constant_evaluated
_NODISCARD constexpr bool is_constant_evaluated() noexcept {
return __builtin_is_constant_evaluated();
}
#endif // _HAS_CXX20
// STRUCT TEMPLATE _Weak_types
template <class _Ty, class = void>
struct _Weak_result_type {}; // default definition

Просмотреть файл

@ -175,6 +175,13 @@ template <class _Ty, class... _Types>
_INLINE_VAR constexpr bool _Is_any_of_v = // true if and only if _Ty is in _Types
disjunction_v<is_same<_Ty, _Types>...>;
#if _HAS_CXX20
// FUNCTION is_constant_evaluated
_NODISCARD constexpr bool is_constant_evaluated() noexcept {
return __builtin_is_constant_evaluated();
}
#endif // _HAS_CXX20
// STRUCT TEMPLATE is_integral
template <class _Ty>
_INLINE_VAR constexpr bool is_integral_v = _Is_any_of_v<remove_cv_t<_Ty>, bool, char, signed char, unsigned char,

Просмотреть файл

@ -1140,13 +1140,8 @@
#define __cpp_lib_atomic_shared_ptr 201711L
#define __cpp_lib_bind_front 201907L
#define __cpp_lib_bit_cast 201806L
#ifdef __clang__ // TRANSITION, VSO-1020212
// a future MSVC update will embed CPU feature detection into <bit> intrinsics
#define __cpp_lib_bitops 201907L
#endif // __clang__
#define __cpp_lib_bounded_array_traits 201902L
#define __cpp_lib_bitops 201907L
#define __cpp_lib_bounded_array_traits 201902L
#ifdef __cpp_char8_t
#define __cpp_lib_char8_t 201907L
@ -1174,14 +1169,10 @@
#define __cpp_lib_destroying_delete 201806L
#endif // __cpp_impl_destroying_delete
#define __cpp_lib_endian 201907L
#define __cpp_lib_erase_if 202002L
#define __cpp_lib_generic_unordered_lookup 201811L
#ifdef __cpp_lib_bitops // TRANSITION, VSO-1020212
#define __cpp_lib_int_pow2 202002L
#endif
#define __cpp_lib_endian 201907L
#define __cpp_lib_erase_if 202002L
#define __cpp_lib_generic_unordered_lookup 201811L
#define __cpp_lib_int_pow2 202002L
#define __cpp_lib_integer_comparison_functions 202002L
#define __cpp_lib_is_constant_evaluated 201811L
#define __cpp_lib_is_nothrow_convertible 201806L

Просмотреть файл

@ -62,6 +62,8 @@ std/numerics/bit/bit.pow.two/floor2.pass.cpp FAIL
std/numerics/bit/bit.pow.two/ispow2.pass.cpp FAIL
std/numerics/bit/bit.pow.two/log2p1.pass.cpp FAIL
# test emits warning C4310: cast truncates constant value
std/numerics/bit/bitops.rot/rotl.pass.cpp:0 FAIL
# *** INTERACTIONS WITH CONTEST / C1XX THAT UPSTREAM LIKELY WON'T FIX ***
# Tracked by VSO-593630 "<filesystem> Enable libcxx filesystem tests"
@ -454,15 +456,6 @@ std/utilities/time/time.hms/time.hms.members/subseconds.pass.cpp FAIL
std/utilities/time/time.hms/time.hms.members/to_duration.pass.cpp FAIL
std/utilities/time/time.hms/time.hms.members/width.pass.cpp FAIL
# C++20 P0553R4 "<bit> Rotating And Counting Functions"
std/numerics/bit/bitops.count/countl_one.pass.cpp:0 FAIL
std/numerics/bit/bitops.count/countl_zero.pass.cpp:0 FAIL
std/numerics/bit/bitops.count/countr_one.pass.cpp:0 FAIL
std/numerics/bit/bitops.count/countr_zero.pass.cpp:0 FAIL
std/numerics/bit/bitops.count/popcount.pass.cpp:0 FAIL
std/numerics/bit/bitops.rot/rotl.pass.cpp:0 FAIL
std/numerics/bit/bitops.rot/rotr.pass.cpp:0 FAIL
# C++20 P0608R3 "Improving variant's Converting Constructor/Assignment"
std/utilities/variant/variant.variant/variant.assign/conv.pass.cpp FAIL
std/utilities/variant/variant.variant/variant.assign/T.pass.cpp FAIL

Просмотреть файл

@ -62,6 +62,8 @@ numerics\bit\bit.pow.two\floor2.pass.cpp
numerics\bit\bit.pow.two\ispow2.pass.cpp
numerics\bit\bit.pow.two\log2p1.pass.cpp
# test emits warning C4310: cast truncates constant value
numerics\bit\bitops.rot\rotl.pass.cpp
# *** INTERACTIONS WITH CONTEST / C1XX THAT UPSTREAM LIKELY WON'T FIX ***
# Tracked by VSO-593630 "<filesystem> Enable libcxx filesystem tests"
@ -454,15 +456,6 @@ utilities\time\time.hms\time.hms.members\subseconds.pass.cpp
utilities\time\time.hms\time.hms.members\to_duration.pass.cpp
utilities\time\time.hms\time.hms.members\width.pass.cpp
# C++20 P0553R4 "<bit> Rotating And Counting Functions"
numerics\bit\bitops.count\countl_one.pass.cpp
numerics\bit\bitops.count\countl_zero.pass.cpp
numerics\bit\bitops.count\countr_one.pass.cpp
numerics\bit\bitops.count\countr_zero.pass.cpp
numerics\bit\bitops.count\popcount.pass.cpp
numerics\bit\bitops.rot\rotl.pass.cpp
numerics\bit\bitops.rot\rotr.pass.cpp
# C++20 P0608R3 "Improving variant's Converting Constructor/Assignment"
utilities\variant\variant.variant\variant.assign\conv.pass.cpp
utilities\variant\variant.variant\variant.assign\T.pass.cpp

Просмотреть файл

@ -6,7 +6,6 @@
using namespace std;
#ifdef __cpp_lib_bitops // TRANSITION, VSO-1020212
template <typename T>
constexpr bool test_countl_zero() {
constexpr int digits = numeric_limits<T>::digits;
@ -105,6 +104,25 @@ constexpr bool test_rotr() {
return true;
}
// Tests functions for 64-bit operands that have either high or low halves as zero.
// These may be split into two operations on 32-bit platforms and we need to check
// if we handle the == zero or == ones case correctly.
constexpr bool test_64bit_split_ops() {
constexpr unsigned long long zero_one = 0x0000'0000'FFFF'FFFF;
constexpr unsigned long long one_zero = 0xFFFF'FFFF'0000'0000;
assert(popcount(zero_one) == 32);
assert(popcount(one_zero) == 32);
assert(countr_zero(zero_one) == 0);
assert(countr_zero(one_zero) == 32);
assert(countl_zero(zero_one) == 32);
assert(countl_zero(one_zero) == 0);
assert(countr_one(zero_one) == 32);
assert(countr_one(one_zero) == 0);
assert(countl_one(zero_one) == 0);
assert(countl_one(one_zero) == 32);
return true;
}
template <typename T>
constexpr bool test_popcount_specialcases() {
constexpr int digits = numeric_limits<T>::digits;
@ -153,17 +171,16 @@ void test_all() {
test_rotl<T>();
static_assert(test_rotr<T>());
test_rotr<T>();
static_assert(test_64bit_split_ops());
test_64bit_split_ops();
static_assert(test_popcount_specialcases<T>());
test_popcount_specialcases<T>();
}
#endif // __cpp_lib_bitops
int main() {
#ifdef __cpp_lib_bitops // TRANSITION, VSO-1020212
test_all<unsigned char>();
test_all<unsigned short>();
test_all<unsigned int>();
test_all<unsigned long>();
test_all<unsigned long long>();
#endif // __cpp_lib_bitops
}

Просмотреть файл

@ -7,7 +7,6 @@
using namespace std;
#ifdef __cpp_lib_bitops // TRANSITION, VSO-1020212
template <typename T>
constexpr bool test_has_single_bit() {
assert(!has_single_bit(T{0}));
@ -97,10 +96,8 @@ void test_all() {
static_assert(test_bit_width<T>());
test_bit_width<T>();
}
#endif // __cpp_lib_bitops
int main() {
#ifdef __cpp_lib_bitops // TRANSITION, VSO-1020212
test_all<unsigned char>();
test_all<unsigned short>();
test_all<unsigned int>();
@ -108,5 +105,4 @@ int main() {
test_all<unsigned long long>();
test_bit_floor_specialcases_unsigned();
test_bit_ceil_specialcases_unsigned();
#endif // __cpp_lib_bitops
}

Просмотреть файл

@ -189,7 +189,7 @@ STATIC_ASSERT(__cpp_lib_bit_cast == 201806L);
#endif
#endif
#if _HAS_CXX20 && defined(__clang__) // TRANSITION, VSO-1020212
#if _HAS_CXX20
#ifndef __cpp_lib_bitops
#error __cpp_lib_bitops is not defined
#elif __cpp_lib_bitops != 201907L
@ -641,7 +641,7 @@ STATIC_ASSERT(__cpp_lib_hypot == 201603L);
STATIC_ASSERT(__cpp_lib_incomplete_container_elements == 201505L);
#endif
#if _HAS_CXX20 && defined(__clang__) // TRANSITION, VSO-1020212
#if _HAS_CXX20
#ifndef __cpp_lib_int_pow2
#error __cpp_lib_int_pow2 is not defined
#elif __cpp_lib_int_pow2 != 202002L