From 70c992436e12e23bd6466c0be827d4f1548e53b1 Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Tue, 16 Aug 2022 14:27:09 +0800 Subject: [PATCH 01/25] Backport integer-class types to C++14 mode Co-authored-by: Matt Stephanson --- stl/inc/__msvc_int128.hpp | 326 +++++++++++++++++++++++++++++++------- 1 file changed, 268 insertions(+), 58 deletions(-) diff --git a/stl/inc/__msvc_int128.hpp b/stl/inc/__msvc_int128.hpp index e26d7ead234..6d73953f048 100644 --- a/stl/inc/__msvc_int128.hpp +++ b/stl/inc/__msvc_int128.hpp @@ -9,12 +9,25 @@ #include #if _STL_COMPILER_PREPROCESSOR -#ifdef __cpp_lib_concepts +#include +#include // TRANSITION, GH-2520 +#include +#include + +#if _HAS_CXX20 #include #include +#define _ZERO_OR_NO_INIT +#else // ^^^ _HAS_CXX20 / vvv !_HAS_CXX20 +#define _ZERO_OR_NO_INIT = {0} +#endif // _HAS_CXX20 + +#ifdef __cpp_lib_concepts #include -#include -#include // TRANSITION, GH-2520 +#define _TEMPLATE_CLASS_INTEGRAL(type) template +#else +#define _TEMPLATE_CLASS_INTEGRAL(type) template , int> = 0> +#endif // __cpp_lib_concepts #pragma pack(push, _CRT_PACKING) #pragma warning(push, _STL_WARNING_LEVEL) @@ -57,7 +70,7 @@ struct } #if _STL_128_INTRINSICS - if (!_STD is_constant_evaluated()) { + if (!_Is_constant_evaluated()) { _Word[1] = __shiftleft128(_Word[0], _Word[1], _Count); } else #endif // _STL_128_INTRINSICS @@ -81,7 +94,7 @@ struct } #if _STL_128_INTRINSICS - if (!_STD is_constant_evaluated()) { + if (!_Is_constant_evaluated()) { _Word[0] = __shiftright128(_Word[0], _Word[1], _Count); } else #endif // _STL_128_INTRINSICS @@ -96,7 +109,7 @@ struct unsigned char _Carry, uint64_t _Left, uint64_t _Right, uint64_t& _Result) noexcept { // _STL_INTERNAL_CHECK(_Carry < 2); #if _STL_128_INTRINSICS - if (!_STD is_constant_evaluated()) { + if (!_Is_constant_evaluated()) { return _addcarry_u64(_Carry, _Left, _Right, &_Result); } #endif // _STL_128_INTRINSICS @@ -110,7 +123,7 @@ struct unsigned char _Carry, uint64_t _Left, uint64_t _Right, uint64_t& _Result) noexcept { // _STL_INTERNAL_CHECK(_Carry < 2); #if _STL_128_INTRINSICS - if (!_STD is_constant_evaluated()) { + if (!_Is_constant_evaluated()) { return _subborrow_u64(_Carry, _Left, _Right, &_Result); } #endif // _STL_128_INTRINSICS @@ -124,7 +137,7 @@ struct static constexpr void _Knuth_4_3_1_M( const uint32_t (&__u)[__m], const uint32_t (&__v)[__n], uint32_t (&__w)[__n + __m]) noexcept { #ifdef _ENABLE_STL_INTERNAL_CHECK - constexpr auto _Int_max = size_t{(numeric_limits::max)()}; + constexpr auto _Int_max = size_t{(numeric_limits::max) ()}; _STL_INTERNAL_STATIC_ASSERT(__m <= _Int_max); _STL_INTERNAL_STATIC_ASSERT(__n <= _Int_max); #endif // _ENABLE_STL_INTERNAL_CHECK @@ -148,7 +161,7 @@ struct _NODISCARD static constexpr uint64_t _UMul128( const uint64_t _Left, const uint64_t _Right, uint64_t& _High_result) noexcept { #if _STL_128_INTRINSICS - if (!_STD is_constant_evaluated()) { + if (!_Is_constant_evaluated()) { return _umul128(_Left, _Right, &_High_result); } #endif // _STL_128_INTRINSICS @@ -161,7 +174,7 @@ struct static_cast(_Right), static_cast(_Right >> 32), }; - uint32_t __w[4]; + uint32_t __w[4] _ZERO_OR_NO_INIT; // multiply 2-digit numbers with 4-digit result in base 2^32 _Knuth_4_3_1_M(__u, __v, __w); @@ -197,7 +210,7 @@ struct } int64_t __k = 0; - int64_t __t; + int64_t __t _ZERO_OR_NO_INIT; for (int __i = 0; __i < static_cast(__n); ++__i) { const auto _Prod = static_cast(__qhat) * static_cast(__v[__i]); __t = __u[__i + __j] - __k - static_cast(_Prod); @@ -228,12 +241,16 @@ struct // _STL_INTERNAL_CHECK(_High < _Div); #if _STL_128_DIV_INTRINSICS - if (!_STD is_constant_evaluated()) { + if (!_Is_constant_evaluated()) { return _udiv128(_High, _Low, _Div, &_Remainder); } #endif // _STL_128_DIV_INTRINSICS +#if _HAS_CXX20 const auto __d = _STD countl_zero(static_cast(_Div >> 32)); +#else // ^^^ _HAS_CXX20 / vvv !_HAS_CXX20 + const auto __d = _Countl_zero_fallback(static_cast(_Div >> 32)); +#endif // _HAS_CXX20 if (__d >= 32) { // _Div < 2^32 auto _Rem = (_High << 32) | (_Low >> 32); auto _Result = _Rem / static_cast(_Div); @@ -259,7 +276,7 @@ struct static_cast(_Div << __d), static_cast(_Div >> (32 - __d)), }; - uint32_t __q[3]; + uint32_t __q[3] _ZERO_OR_NO_INIT; _Knuth_4_3_1_D(__u, 5, __v, 2, __q); // _STL_INTERNAL_CHECK(__u[4] == 0); @@ -273,9 +290,14 @@ struct constexpr _Base128() noexcept : _Word{} {} - template + _TEMPLATE_CLASS_INTEGRAL(_Ty) constexpr _Base128(const _Ty _Val) noexcept : _Word{static_cast(_Val)} { - if constexpr (signed_integral<_Ty>) { +#ifdef __cpp_lib_concepts + if constexpr (signed_integral<_Ty>) +#else + if constexpr (is_integral_v<_Ty> && is_signed_v<_Ty>) +#endif + { if (_Val < 0) { _Word[1] = ~0ull; } @@ -284,7 +306,7 @@ struct constexpr explicit _Base128(const uint64_t _Low, const uint64_t _High) noexcept : _Word{_Low, _High} {} - template + _TEMPLATE_CLASS_INTEGRAL(_Ty) _NODISCARD constexpr explicit operator _Ty() const noexcept { return static_cast<_Ty>(_Word[0]); } @@ -293,7 +315,17 @@ struct return (_Word[0] | _Word[1]) != 0; } +#if _HAS_CXX20 _NODISCARD_FRIEND constexpr bool operator==(const _Base128&, const _Base128&) noexcept = default; +#else // ^^^ _HAS_CXX20 / vvv !_HAS_CXX20 + _NODISCARD_FRIEND constexpr bool operator==(const _Base128& _Left, const _Base128& _Right) noexcept { + return _Left._Word[0] == _Right._Word[0] && _Left._Word[1] == _Right._Word[1]; + } + + _NODISCARD_FRIEND constexpr bool operator!=(const _Base128& _Left, const _Base128& _Right) noexcept { + return !(_Left == _Right); + } +#endif _NODISCARD_FRIEND constexpr bool operator<(const _Base128& _Left, const _Base128& _Right) noexcept { if (_Left._Word[1] < _Right._Word[1]) { @@ -315,35 +347,35 @@ struct return !(_Left < _Right); } - template + _TEMPLATE_CLASS_INTEGRAL(_Ty) _NODISCARD_FRIEND constexpr _Ty operator<<(const _Ty _Left, const _Base128& _Right) noexcept { return _Left << _Right._Word[0]; } - template + _TEMPLATE_CLASS_INTEGRAL(_Ty) _NODISCARD_FRIEND constexpr _Ty operator>>(const _Ty _Left, const _Base128& _Right) noexcept { return _Left >> _Right._Word[0]; } - template + _TEMPLATE_CLASS_INTEGRAL(_Ty) constexpr _Base128& operator<<=(const _Ty _Count) noexcept { _Left_shift(static_cast(_Count)); return *this; } - template + _TEMPLATE_CLASS_INTEGRAL(_Ty) friend constexpr _Ty& operator<<=(_Ty& _Left, const _Base128& _Right) noexcept { _Left <<= _Right._Word[0]; return _Left; } - template + _TEMPLATE_CLASS_INTEGRAL(_Ty) constexpr _Base128& operator>>=(const _Ty _Count) noexcept { _Unsigned_right_shift(static_cast(_Count)); return *this; } - template + _TEMPLATE_CLASS_INTEGRAL(_Ty) friend constexpr _Ty& operator>>=(_Ty& _Left, const _Base128& _Right) noexcept { _Left >>= _Right._Word[0]; return _Left; @@ -426,14 +458,18 @@ struct // _STL_INTERNAL_CHECK(_Den._Word[1] != 0); // _STL_INTERNAL_CHECK(_Num._Word[1] > _Den._Word[1]); // Normalize by shifting both left until _Den's high bit is set (So _Den's high digit is >= b / 2) +#if _HAS_CXX20 const auto __d = _STD countl_zero(_Den._Word[1]); +#else // ^^^ _HAS_CXX20 / vvv !_HAS_CXX20 + const auto __d = _Countl_zero_fallback(_Den._Word[1]); +#endif // _HAS_CXX20 _Den <<= __d; auto _High_digit = __d == 0 ? 0 : _Num._Word[1] >> (64 - __d); // This creates a third digit for _Num _Num <<= __d; _Base128 __qhat; __qhat._Word[1] = _High_digit >= _Den._Word[1]; - uint64_t __rhat; + uint64_t __rhat _ZERO_OR_NO_INIT; __qhat._Word[0] = _UDiv128(_High_digit >= _Den._Word[1] ? _High_digit - _Den._Word[1] : _High_digit, _Num._Word[1], _Den._Word[1], __rhat); @@ -458,10 +494,10 @@ struct // _STL_INTERNAL_CHECK(__qhat._Word[1] == 0); // [_High_digit | _Num] -= __qhat * _Den [Since __qhat < b, this is 3-digit - 1-digit * 2-digit] - uint64_t _Prod0_hi; + uint64_t _Prod0_hi _ZERO_OR_NO_INIT; uint64_t _Prod_lo = _UMul128(__qhat._Word[0], _Den._Word[0], _Prod0_hi); auto _Borrow = _SubBorrow64(0, _Num._Word[0], _Prod_lo, _Num._Word[0]); - uint64_t _Prod1_hi; + uint64_t _Prod1_hi _ZERO_OR_NO_INIT; _Prod_lo = _UMul128(__qhat._Word[0], _Den._Word[1], _Prod1_hi); _Prod1_hi += _AddCarry64(0, _Prod_lo, _Prod0_hi, _Prod_lo); _Borrow = _SubBorrow64(_Borrow, _Num._Word[1], _Prod_lo, _Num._Word[1]); @@ -471,7 +507,11 @@ struct } return __qhat; #else // ^^^ 128-bit intrinsics / no such intrinsics vvv - auto __d = _STD countl_zero(_Den._Word[1]); +#if _HAS_CXX20 + auto __d = _STD countl_zero(_Den._Word[1]); +#else // ^^^ _HAS_CXX20 / vvv !_HAS_CXX20 + auto __d = _Countl_zero_fallback(_Den._Word[1]); +#endif // _HAS_CXX20 const bool _Three_word_den = __d >= 32; __d &= 31; uint32_t __u[5]{ @@ -516,7 +556,7 @@ struct } #endif // !_STL_128_DIV_INTRINSICS _NODISCARD static constexpr _Base128 _Modulo(const _Base128& _Num, const uint64_t _Den) noexcept { - uint64_t _Rem; + uint64_t _Rem _ZERO_OR_NO_INIT; (void) _UDiv128(_Num._Word[1] % _Den, _Num._Word[0], _Den, _Rem); return _Rem; } @@ -551,13 +591,17 @@ struct // _STL_INTERNAL_CHECK(_Den._Word[1] != 0); // _STL_INTERNAL_CHECK(_Num._Word[1] > _Den._Word[1]); // Normalize by shifting both left until _Den's high bit is set (So _Den's high digit is >= b / 2) +#if _HAS_CXX20 const auto __d = _STD countl_zero(_Den._Word[1]); +#else // ^^^ _HAS_CXX20 / vvv !_HAS_CXX20 + const auto __d = _Countl_zero_fallback(_Den._Word[1]); +#endif // _HAS_CXX20 _Den <<= __d; auto _High_digit = __d == 0 ? 0 : _Num._Word[1] >> (64 - __d); // This creates a third digit for _Num _Num <<= __d; uint64_t __qhat_high = _High_digit >= _Den._Word[1]; - uint64_t __rhat; + uint64_t __rhat _ZERO_OR_NO_INIT; uint64_t __qhat = _UDiv128(_High_digit >= _Den._Word[1] ? _High_digit - _Den._Word[1] : _High_digit, _Num._Word[1], _Den._Word[1], __rhat); @@ -585,10 +629,10 @@ struct // _STL_INTERNAL_CHECK(__qhat_high == 0); // [_High_digit | _Num] -= __qhat * _Den [3-digit - 1-digit * 2-digit] - uint64_t _Prod0_hi; + uint64_t _Prod0_hi _ZERO_OR_NO_INIT; uint64_t _Prod_lo = _UMul128(__qhat, _Den._Word[0], _Prod0_hi); auto _Borrow = _SubBorrow64(0, _Num._Word[0], _Prod_lo, _Num._Word[0]); - uint64_t _Prod1_hi; + uint64_t _Prod1_hi _ZERO_OR_NO_INIT; _Prod_lo = _UMul128(__qhat, _Den._Word[1], _Prod1_hi); _Prod1_hi += _AddCarry64(0, _Prod_lo, _Prod0_hi, _Prod_lo); _Borrow = _SubBorrow64(_Borrow, _Num._Word[1], _Prod_lo, _Num._Word[1]); @@ -598,7 +642,11 @@ struct (void) _AddCarry64(_Carry, _Num._Word[1], _Den._Word[1], _Num._Word[1]); } #else // ^^^ 128-bit intrinsics / no such intrinsics vvv - auto __d = _STD countl_zero(_Den._Word[1]); +#if _HAS_CXX20 + auto __d = _STD countl_zero(_Den._Word[1]); +#else // ^^^ _HAS_CXX20 / vvv !_HAS_CXX20 + auto __d = _Countl_zero_fallback(_Den._Word[1]); +#endif // _HAS_CXX20 const bool _Three_word_den = __d >= 32; __d &= 31; uint32_t __u[5]{ @@ -638,19 +686,19 @@ struct return _Num; } - template + _TEMPLATE_CLASS_INTEGRAL(_Ty) friend constexpr _Ty& operator&=(_Ty& _Left, const _Base128& _Right) noexcept { _Left &= _Right._Word[0]; return _Left; } - template + _TEMPLATE_CLASS_INTEGRAL(_Ty) friend constexpr _Ty& operator^=(_Ty& _Left, const _Base128& _Right) noexcept { _Left ^= _Right._Word[0]; return _Left; } - template + _TEMPLATE_CLASS_INTEGRAL(_Ty) friend constexpr _Ty& operator|=(_Ty& _Left, const _Base128& _Right) noexcept { _Left |= _Right._Word[0]; return _Left; @@ -663,6 +711,10 @@ struct _Unsigned128 : _Base128 { using _Signed_type = _Signed128; using _Unsigned_type = _Unsigned128; +#if !_HAS_CXX17 + constexpr _Unsigned128() noexcept : _Base128{} {} +#endif // !_HAS_CXX17 + using _Base128::_Base128; constexpr explicit _Unsigned128(const _Base128& _That) noexcept : _Base128{_That} {} @@ -671,6 +723,7 @@ struct _Unsigned128 : _Base128 { return *this; } +#if _HAS_CXX20 _NODISCARD_FRIEND constexpr strong_ordering operator<=>( const _Unsigned128& _Left, const _Unsigned128& _Right) noexcept { strong_ordering _Ord = _Left._Word[1] <=> _Right._Word[1]; @@ -679,6 +732,27 @@ struct _Unsigned128 : _Base128 { } return _Ord; } +#else // ^^^ _HAS_CXX20 / vvv !_HAS_CXX20 + _NODISCARD_FRIEND constexpr bool operator<(const _Unsigned128& _Left, const _Unsigned128& _Right) noexcept { + if (_Left._Word[1] < _Right._Word[1]) + return true; + if (_Right._Word[1] < _Left._Word[1]) + return false; + return _Left._Word[0] < _Right._Word[0]; + } + + _NODISCARD_FRIEND constexpr bool operator>(const _Unsigned128& _Left, const _Unsigned128& _Right) noexcept { + return _Right < _Left; + } + + _NODISCARD_FRIEND constexpr bool operator<=(const _Unsigned128& _Left, const _Unsigned128& _Right) noexcept { + return !(_Right < _Left); + } + + _NODISCARD_FRIEND constexpr bool operator>=(const _Unsigned128& _Left, const _Unsigned128& _Right) noexcept { + return !(_Left < _Right); + } +#endif // _HAS_CXX20 _NODISCARD_FRIEND constexpr _Unsigned128 operator<<(const _Unsigned128& _Left, const _Base128& _Right) noexcept { auto _Tmp{_Left}; @@ -686,7 +760,7 @@ struct _Unsigned128 : _Base128 { return _Tmp; } - template + _TEMPLATE_CLASS_INTEGRAL(_Ty) constexpr _Unsigned128& operator<<=(const _Ty _Count) noexcept { _Left_shift(static_cast(_Count)); return *this; @@ -702,7 +776,7 @@ struct _Unsigned128 : _Base128 { return _Tmp; } - template + _TEMPLATE_CLASS_INTEGRAL(_Ty) constexpr _Unsigned128& operator>>=(const _Ty _Count) noexcept { _Unsigned_right_shift(static_cast(_Count)); return *this; @@ -760,7 +834,7 @@ struct _Unsigned128 : _Base128 { _AddCarry64(_Carry, _Word[1], _That._Word[1], _Word[1]); return *this; } - template + _TEMPLATE_CLASS_INTEGRAL(_Ty) friend constexpr _Ty& operator+=(_Ty& _Left, const _Unsigned128& _Right) noexcept { _Left += _Right._Word[0]; return _Left; @@ -778,7 +852,7 @@ struct _Unsigned128 : _Base128 { _SubBorrow64(_Borrow, _Word[1], _That._Word[1], _Word[1]); return *this; } - template + _TEMPLATE_CLASS_INTEGRAL(_Ty) friend constexpr _Ty& operator-=(_Ty& _Left, const _Unsigned128& _Right) noexcept { _Left -= _Right._Word[0]; return _Left; @@ -792,13 +866,13 @@ struct _Unsigned128 : _Base128 { *this = *this * _That; return *this; } - template + _TEMPLATE_CLASS_INTEGRAL(_Ty) friend constexpr _Ty& operator*=(_Ty& _Left, const _Unsigned128& _Right) noexcept { _Left *= _Right._Word[0]; return _Left; } - template + _TEMPLATE_CLASS_INTEGRAL(_Ty) _NODISCARD_FRIEND constexpr _Unsigned128 operator/(const _Unsigned128& _Num, const _Ty _Den) noexcept { #if !_STL_128_DIV_INTRINSICS if constexpr (sizeof(_Ty) <= 4) { @@ -813,7 +887,7 @@ struct _Unsigned128 : _Base128 { return _Unsigned128{_Base128::_Divide(_Num, _Den)}; } - template + _TEMPLATE_CLASS_INTEGRAL(_Ty) constexpr _Unsigned128& operator/=(const _Ty _That) noexcept { #if !_STL_128_DIV_INTRINSICS if constexpr (sizeof(_Ty) <= 4) { @@ -829,7 +903,7 @@ struct _Unsigned128 : _Base128 { *this = _Unsigned128{_Base128::_Divide(*this, _That)}; return *this; } - template + _TEMPLATE_CLASS_INTEGRAL(_Ty) friend constexpr _Ty& operator/=(_Ty& _Left, const _Unsigned128& _Right) noexcept { if (_Right._Word[1] != 0) { _Left = 0; @@ -839,7 +913,7 @@ struct _Unsigned128 : _Base128 { return _Left; } - template + _TEMPLATE_CLASS_INTEGRAL(_Ty) _NODISCARD_FRIEND constexpr _Unsigned128 operator%(const _Base128& _Num, const _Ty _Den) noexcept { #if !_STL_128_DIV_INTRINSICS if constexpr (sizeof(_Ty) <= 4) { @@ -854,7 +928,7 @@ struct _Unsigned128 : _Base128 { return _Unsigned128{_Base128::_Modulo(_Num, _Den)}; } - template + _TEMPLATE_CLASS_INTEGRAL(_Ty) constexpr _Unsigned128& operator%=(const _Ty _Den) noexcept { *this = *this % _Den; return *this; @@ -863,7 +937,7 @@ struct _Unsigned128 : _Base128 { *this = *this % _Den; return *this; } - template + _TEMPLATE_CLASS_INTEGRAL(_Ty) friend constexpr _Ty& operator%=(_Ty& _Left, const _Unsigned128& _Right) noexcept { if (_Right._Word[1] == 0) { _Left %= _Right._Word[0]; @@ -946,6 +1020,7 @@ class numeric_limits<_Unsigned128> : public _Num_int_base { static constexpr int digits10 = 38; }; +#ifdef __cpp_lib_concepts template struct common_type<_Ty, _Unsigned128> { using type = _Unsigned128; @@ -954,11 +1029,21 @@ template struct common_type<_Unsigned128, _Ty> { using type = _Unsigned128; }; +#else // ^^^ defined(__cpp_lib_concepts) / vvv !defined(__cpp_lib_concepts) +template +struct common_type<_Ty, _Unsigned128> : enable_if, _Unsigned128> {}; +template +struct common_type<_Unsigned128, _Ty> : enable_if, _Unsigned128> {}; +#endif // __cpp_lib_concepts struct _Signed128 : _Base128 { using _Signed_type = _Signed128; using _Unsigned_type = _Unsigned128; +#if !_HAS_CXX17 + constexpr _Signed128() noexcept : _Base128{} {} +#endif // !_HAS_CXX17 + using _Base128::_Base128; constexpr explicit _Signed128(const _Base128& _That) noexcept : _Base128{_That} {} @@ -967,6 +1052,7 @@ struct _Signed128 : _Base128 { return *this; } +#if _HAS_CXX20 _NODISCARD_FRIEND constexpr strong_ordering operator<=>( const _Signed128& _Left, const _Signed128& _Right) noexcept { strong_ordering _Ord = static_cast(_Left._Word[1]) <=> static_cast(_Right._Word[1]); @@ -975,6 +1061,27 @@ struct _Signed128 : _Base128 { } return _Ord; } +#else // ^^^ _HAS_CXX20 / vvv !_HAS_CXX20 + _NODISCARD_FRIEND constexpr bool operator<(const _Signed128& _Left, const _Signed128& _Right) noexcept { + if (static_cast(_Left._Word[1]) < static_cast(_Right._Word[1])) + return true; + if (static_cast(_Right._Word[1]) < static_cast(_Left._Word[1])) + return false; + return _Left._Word[0] < _Right._Word[0]; + } + + _NODISCARD_FRIEND constexpr bool operator>(const _Signed128& _Left, const _Signed128& _Right) noexcept { + return _Right < _Left; + } + + _NODISCARD_FRIEND constexpr bool operator<=(const _Signed128& _Left, const _Signed128& _Right) noexcept { + return !(_Right < _Left); + } + + _NODISCARD_FRIEND constexpr bool operator>=(const _Signed128& _Left, const _Signed128& _Right) noexcept { + return !(_Left < _Right); + } +#endif // _HAS_CXX20 _NODISCARD_FRIEND constexpr _Signed128 operator<<(const _Signed128& _Left, const _Base128& _Right) noexcept { auto _Tmp{_Left}; @@ -982,7 +1089,7 @@ struct _Signed128 : _Base128 { return _Tmp; } - template + _TEMPLATE_CLASS_INTEGRAL(_Ty) constexpr _Signed128& operator<<=(const _Ty _Count) noexcept { _Left_shift(static_cast(_Count)); return *this; @@ -1004,7 +1111,7 @@ struct _Signed128 : _Base128 { } #if _STL_128_INTRINSICS - if (!_STD is_constant_evaluated()) { + if (!_Is_constant_evaluated()) { _Word[0] = __shiftright128(_Word[0], _Word[1], _Count); } else #endif // _STL_128_INTRINSICS @@ -1021,7 +1128,7 @@ struct _Signed128 : _Base128 { return _Tmp; } - template + _TEMPLATE_CLASS_INTEGRAL(_Ty) constexpr _Signed128& operator>>=(const _Ty _Count) noexcept { _Signed_right_shift(static_cast(_Count)); return *this; @@ -1079,7 +1186,7 @@ struct _Signed128 : _Base128 { _AddCarry64(_Carry, _Word[1], _That._Word[1], _Word[1]); return *this; } - template + _TEMPLATE_CLASS_INTEGRAL(_Ty) friend constexpr _Ty& operator+=(_Ty& _Left, const _Signed128& _Right) noexcept { _Left = static_cast<_Ty>(_Signed128{_Left} + _Right); return _Left; @@ -1097,7 +1204,7 @@ struct _Signed128 : _Base128 { _SubBorrow64(_Borrow, _Word[1], _That._Word[1], _Word[1]); return *this; } - template + _TEMPLATE_CLASS_INTEGRAL(_Ty) friend constexpr _Ty& operator-=(_Ty& _Left, const _Signed128& _Right) noexcept { _Left = static_cast<_Ty>(_Signed128{_Left} - _Right); return _Left; @@ -1121,7 +1228,7 @@ struct _Signed128 : _Base128 { return _Result; } - template + _TEMPLATE_CLASS_INTEGRAL(_Ty) constexpr _Signed128& operator*=(const _Ty _That) noexcept { *this = *this * _That; return *this; @@ -1134,13 +1241,13 @@ struct _Signed128 : _Base128 { *this = _Signed128{static_cast(*this) * _That}; return *this; } - template + _TEMPLATE_CLASS_INTEGRAL(_Ty) friend constexpr _Ty& operator*=(_Ty& _Left, const _Signed128& _Right) noexcept { _Left = static_cast<_Ty>(_Signed128{_Left} * _Right); return _Left; } - template + _TEMPLATE_CLASS_INTEGRAL(_Ty) _NODISCARD_FRIEND constexpr _Signed128 operator/(_Signed128 _Num, _Ty _Den) noexcept { bool _Negative = false; _Num._Strip_negative(_Negative); @@ -1177,7 +1284,7 @@ struct _Signed128 : _Base128 { return _Result; } - template + _TEMPLATE_CLASS_INTEGRAL(_Ty) constexpr _Signed128& operator/=(const _Ty _That) noexcept { *this = *this / _That; return *this; @@ -1190,7 +1297,7 @@ struct _Signed128 : _Base128 { *this = _Signed128{static_cast<_Base128&>(*this) / _That}; return *this; } - template + _TEMPLATE_CLASS_INTEGRAL(_Ty) friend constexpr _Ty& operator/=(_Ty& _Left, const _Signed128& _Right) noexcept { _Left = static_cast<_Ty>(_Signed128{_Left} / _Right); return _Left; @@ -1212,7 +1319,7 @@ struct _Signed128 : _Base128 { return _Signed128{_Result}; } - template + _TEMPLATE_CLASS_INTEGRAL(_Ty) constexpr _Signed128& operator%=(const _Ty _That) noexcept { *this = *this % _That; return *this; @@ -1225,7 +1332,7 @@ struct _Signed128 : _Base128 { *this = static_cast(*this) % _That; return *this; } - template + _TEMPLATE_CLASS_INTEGRAL(_Ty) friend constexpr _Ty& operator%=(_Ty& _Left, const _Signed128& _Right) noexcept { _Left = static_cast<_Ty>(_Signed128{_Left} % _Right); return _Left; @@ -1305,6 +1412,7 @@ class numeric_limits<_Signed128> : public _Num_int_base { static constexpr int digits10 = 38; }; +#ifdef __cpp_lib_concepts template struct common_type<_Ty, _Signed128> { using type = _Signed128; @@ -1313,6 +1421,12 @@ template struct common_type<_Signed128, _Ty> { using type = _Signed128; }; +#else // ^^^ defined(__cpp_lib_concepts) / vvv !defined(__cpp_lib_concepts) +template +struct common_type<_Ty, _Signed128> : enable_if, _Signed128> {}; +template +struct common_type<_Signed128, _Ty> : enable_if, _Signed128> {}; +#endif // __cpp_lib_concepts template <> struct common_type<_Signed128, _Unsigned128> { @@ -1323,15 +1437,111 @@ struct common_type<_Unsigned128, _Signed128> { using type = _Unsigned128; }; +inline namespace literals { + inline namespace _Int128_literals { + namespace _Detail { + enum class _U128_parse_status : unsigned char { + _Valid, + _Overflow, + _Invalid, + }; + + struct _U128_parse_result { + _U128_parse_status _Status_code; + _Unsigned128 _Value; + }; + + _CONSTEVAL unsigned int _Char_to_digit(const char _Ch) noexcept { + if (_Ch >= '0' && _Ch <= '9') + return static_cast(_Ch - '0'); + if (_Ch >= 'A' && _Ch <= 'F') + return static_cast(_Ch - 'A' + 10); + if (_Ch >= 'a' && _Ch <= 'f') + return static_cast(_Ch - 'a' + 10); + return static_cast(-1); + } + + template + _CONSTEVAL _U128_parse_result _Parse_u128_impl() noexcept { + constexpr char _Char_seq[]{_Chars...}; + constexpr auto _U128_max = (_STD numeric_limits<_Unsigned128>::max)(); + + _Unsigned128 _Val{}; + for (size_t _Ind = 0; _Ind != sizeof...(_Chars); ++_Ind) { + if (_Char_seq[_Ind] == '\'') { + continue; + } + + const unsigned int _Digit = _Char_to_digit(_Char_seq[_Ind]); + if (_Digit == static_cast(-1)) { + return {_U128_parse_status::_Invalid, _Unsigned128{}}; + } + if ((_Val > _U128_max / _Base) || (_Base * _Val > _U128_max - _Digit)) { + return {_U128_parse_status::_Overflow, _Unsigned128{}}; + } + + _Val = _Base * _Val + _Digit; + } + return {_U128_parse_status::_Valid, _Val}; + } + + template + _INLINE_VAR constexpr _U128_parse_result _Parsed_u128 = _Parse_u128_impl<10, _Chars...>(); + + template + _INLINE_VAR constexpr _U128_parse_result + _Parsed_u128<'0', 'X', _Chars...> = _Parse_u128_impl<16, _Chars...>(); + + template + _INLINE_VAR constexpr _U128_parse_result + _Parsed_u128<'0', 'x', _Chars...> = _Parse_u128_impl<16, _Chars...>(); + + template + _INLINE_VAR constexpr _U128_parse_result + _Parsed_u128<'0', 'B', _Chars...> = _Parse_u128_impl<2, _Chars...>(); + + template + _INLINE_VAR constexpr _U128_parse_result + _Parsed_u128<'0', 'b', _Chars...> = _Parse_u128_impl<2, _Chars...>(); + + template + _INLINE_VAR constexpr _U128_parse_result _Parsed_u128<'0', _Chars...> = _Parse_u128_impl<8, _Chars...>(); + } // namespace _Detail + + template + _CONSTEVAL _Unsigned128 operator"" __u128() noexcept { + constexpr const auto& _Parsed_result = _Detail::_Parsed_u128<_Chars...>; + static_assert(_Parsed_result._Status_code != _Detail::_U128_parse_status::_Invalid, + "Invalid characters in the integer literal"); + static_assert(_Parsed_result._Status_code != _Detail::_U128_parse_status::_Overflow, + "The integer literal is too large for an unsigned 128-bit number"); + return _Parsed_result._Value; + } + + template + _CONSTEVAL _Signed128 operator"" __i128() noexcept { + constexpr const auto& _Parsed_result = _Detail::_Parsed_u128<_Chars...>; + static_assert(_Parsed_result._Status_code != _Detail::_U128_parse_status::_Invalid, + "Invalid characters in the integer literal"); + static_assert(_Parsed_result._Status_code != _Detail::_U128_parse_status::_Overflow + && _Parsed_result._Value._Word[1] < (static_cast(1) << 63), + "The integer literal is too large for a signed 128-bit number"); + return static_cast<_Signed128>(_Parsed_result._Value); + } + } // namespace _Int128_literals +} // namespace literals + #undef _STL_128_INTRINSICS #undef _STL_128_DIV_INTRINSICS _STD_END +#undef _TEMPLATE_CLASS_INTEGRAL +#undef _ZERO_OR_NO_INIT + #pragma pop_macro("new") _STL_RESTORE_CLANG_WARNINGS #pragma warning(pop) #pragma pack(pop) -#endif // __cpp_lib_concepts #endif // _STL_COMPILER_PREPROCESSOR #endif // __MSVC_INT128_HPP From 918aa3bb79174052b1b674d3ecec5888eec3f5f2 Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Tue, 16 Aug 2022 14:29:03 +0800 Subject: [PATCH 02/25] Test _Signed128/_Unsigned128 in all modes --- .../std/tests/P1522R1_difference_type/env.lst | 2 +- .../tests/P1522R1_difference_type/test.cpp | 357 ++++++++++++------ 2 files changed, 248 insertions(+), 111 deletions(-) diff --git a/tests/std/tests/P1522R1_difference_type/env.lst b/tests/std/tests/P1522R1_difference_type/env.lst index 7b6bcff4830..19f025bd0e6 100644 --- a/tests/std/tests/P1522R1_difference_type/env.lst +++ b/tests/std/tests/P1522R1_difference_type/env.lst @@ -1,4 +1,4 @@ # Copyright (c) Microsoft Corporation. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -RUNALL_INCLUDE ..\strict_concepts_20_matrix.lst +RUNALL_INCLUDE ..\usual_matrix.lst diff --git a/tests/std/tests/P1522R1_difference_type/test.cpp b/tests/std/tests/P1522R1_difference_type/test.cpp index 0a2cc61c943..34a24177844 100644 --- a/tests/std/tests/P1522R1_difference_type/test.cpp +++ b/tests/std/tests/P1522R1_difference_type/test.cpp @@ -3,26 +3,45 @@ #include <__msvc_int128.hpp> #include -#include -#include #include #include #include #include +#if _HAS_CXX20 +#include + +#if !defined(__EDG__) // TRANSITION, GH-395 +#include +#endif // !defined(__EDG__) +#endif // _HAS_CXX20 + +#if _HAS_CXX20 && !defined(__EDG__) // TRANSITION, GH-395 +#define SAME_AS std::same_as +#else // ^^^ has concepts / vvv has no concepts +#define SAME_AS std::is_same_v +#endif // _HAS_CXX20 && !defined(__EDG__) + +#define STATIC_ASSERT(...) static_assert(__VA_ARGS__, #__VA_ARGS__) + using std::_Signed128; using std::_Unsigned128; +using namespace std::literals::_Int128_literals; -constexpr void check_equal(const auto& x) { +template +constexpr void check_equal(const I& x) { assert(x == x); assert(!(x != x)); assert(!(x < x)); assert(!(x > x)); assert(x <= x); assert(x >= x); +#if _HAS_CXX20 assert(x <=> x == 0); +#endif // _HAS_CXX20 } +#if _HAS_CXX20 constexpr void check_order(const auto& x, const auto& y, const std::strong_ordering ord) { assert((x == y) == (ord == std::strong_ordering::equal)); assert((x != y) == (ord != std::strong_ordering::equal)); @@ -41,72 +60,82 @@ constexpr void check_order(const auto& x, const auto& y, const std::strong_order assert((x <=> y) == (ord <=> 0)); assert((y <=> x) == (0 <=> ord)); } +#endif // _HAS_CXX20 constexpr bool test_unsigned() { - static_assert(std::regular<_Unsigned128>); - static_assert(std::three_way_comparable<_Unsigned128, std::strong_ordering>); - - static_assert(std::numeric_limits<_Unsigned128>::min() == 0); - static_assert(std::numeric_limits<_Unsigned128>::max() == ~_Unsigned128{}); - static_assert(std::numeric_limits<_Unsigned128>::digits == 128); - static_assert(std::numeric_limits<_Unsigned128>::is_modulo); - - static_assert(std::same_as, _Unsigned128>); - static_assert(std::same_as, _Unsigned128>); - static_assert(std::same_as, _Unsigned128>); - static_assert(std::same_as, _Unsigned128>); - static_assert(std::same_as, _Unsigned128>); +#if _HAS_CXX20 && !defined(__EDG__) // TRANSITION, GH-395 + STATIC_ASSERT(std::regular<_Unsigned128>); + STATIC_ASSERT(std::three_way_comparable<_Unsigned128, std::strong_ordering>); +#endif // _HAS_CXX20 && !defined(__EDG__) + + STATIC_ASSERT(std::numeric_limits<_Unsigned128>::min() == 0); + STATIC_ASSERT(std::numeric_limits<_Unsigned128>::max() == ~_Unsigned128{}); + STATIC_ASSERT(std::numeric_limits<_Unsigned128>::digits == 128); + STATIC_ASSERT(std::numeric_limits<_Unsigned128>::is_modulo); + + STATIC_ASSERT(SAME_AS, _Unsigned128>); + STATIC_ASSERT(SAME_AS, _Unsigned128>); + STATIC_ASSERT(SAME_AS, _Unsigned128>); + STATIC_ASSERT(SAME_AS, _Unsigned128>); + STATIC_ASSERT(SAME_AS, _Unsigned128>); #ifdef __cpp_char8_t - static_assert(std::same_as, _Unsigned128>); + STATIC_ASSERT(SAME_AS, _Unsigned128>); #endif // __cpp_char8_t - static_assert(std::same_as, _Unsigned128>); - static_assert(std::same_as, _Unsigned128>); - static_assert(std::same_as, _Unsigned128>); - static_assert(std::same_as, _Unsigned128>); - static_assert(std::same_as, _Unsigned128>); - static_assert(std::same_as, _Unsigned128>); - static_assert(std::same_as, _Unsigned128>); - static_assert(std::same_as, _Unsigned128>); - static_assert(std::same_as, _Unsigned128>); - static_assert(std::same_as, _Unsigned128>); - static_assert(std::same_as, _Unsigned128>); - - static_assert(std::same_as, _Unsigned128>); - static_assert(std::same_as, _Unsigned128>); - static_assert(std::same_as, _Unsigned128>); - static_assert(std::same_as, _Unsigned128>); - static_assert(std::same_as, _Unsigned128>); + STATIC_ASSERT(SAME_AS, _Unsigned128>); + STATIC_ASSERT(SAME_AS, _Unsigned128>); + STATIC_ASSERT(SAME_AS, _Unsigned128>); + STATIC_ASSERT(SAME_AS, _Unsigned128>); + STATIC_ASSERT(SAME_AS, _Unsigned128>); + STATIC_ASSERT(SAME_AS, _Unsigned128>); + STATIC_ASSERT(SAME_AS, _Unsigned128>); + STATIC_ASSERT(SAME_AS, _Unsigned128>); + STATIC_ASSERT(SAME_AS, _Unsigned128>); + STATIC_ASSERT(SAME_AS, _Unsigned128>); + STATIC_ASSERT(SAME_AS, _Unsigned128>); + + STATIC_ASSERT(SAME_AS, _Unsigned128>); + STATIC_ASSERT(SAME_AS, _Unsigned128>); + STATIC_ASSERT(SAME_AS, _Unsigned128>); + STATIC_ASSERT(SAME_AS, _Unsigned128>); + STATIC_ASSERT(SAME_AS, _Unsigned128>); #ifdef __cpp_char8_t - static_assert(std::same_as, _Unsigned128>); + STATIC_ASSERT(SAME_AS, _Unsigned128>); #endif // __cpp_char8_t - static_assert(std::same_as, _Unsigned128>); - static_assert(std::same_as, _Unsigned128>); - static_assert(std::same_as, _Unsigned128>); - static_assert(std::same_as, _Unsigned128>); - static_assert(std::same_as, _Unsigned128>); - static_assert(std::same_as, _Unsigned128>); - static_assert(std::same_as, _Unsigned128>); - static_assert(std::same_as, _Unsigned128>); - static_assert(std::same_as, _Unsigned128>); - static_assert(std::same_as, _Unsigned128>); - static_assert(std::same_as, _Unsigned128>); - - static_assert(std::_Integer_class<_Unsigned128>); - static_assert(std::_Integer_like<_Unsigned128>); - static_assert(!std::_Signed_integer_like<_Unsigned128>); - static_assert(std::same_as, _Unsigned128>); - static_assert(std::same_as, _Signed128>); + STATIC_ASSERT(SAME_AS, _Unsigned128>); + STATIC_ASSERT(SAME_AS, _Unsigned128>); + STATIC_ASSERT(SAME_AS, _Unsigned128>); + STATIC_ASSERT(SAME_AS, _Unsigned128>); + STATIC_ASSERT(SAME_AS, _Unsigned128>); + STATIC_ASSERT(SAME_AS, _Unsigned128>); + STATIC_ASSERT(SAME_AS, _Unsigned128>); + STATIC_ASSERT(SAME_AS, _Unsigned128>); + STATIC_ASSERT(SAME_AS, _Unsigned128>); + STATIC_ASSERT(SAME_AS, _Unsigned128>); + STATIC_ASSERT(SAME_AS, _Unsigned128>); + +#if _HAS_CXX20 && !defined(__EDG__) // TRANSITION, GH-395 + STATIC_ASSERT(std::_Integer_class<_Unsigned128>); + STATIC_ASSERT(std::_Integer_like<_Unsigned128>); + STATIC_ASSERT(!std::_Signed_integer_like<_Unsigned128>); + STATIC_ASSERT(SAME_AS, _Unsigned128>); + STATIC_ASSERT(SAME_AS, _Signed128>); +#endif // _HAS_CXX20 && !defined(__EDG__) check_equal(_Unsigned128{}); check_equal(_Unsigned128{42}); check_equal(_Unsigned128{-42}); check_equal(_Unsigned128{0x11111111'11111111, 0x22222222'22222222}); + check_equal(0x22222222'22222222'11111111'11111111__u128); +#if _HAS_CXX20 check_order(_Unsigned128{42}, _Unsigned128{-42}, std::strong_ordering::less); check_order(_Unsigned128{0, 42}, _Unsigned128{0, 52}, std::strong_ordering::less); // ordered only by MSW check_order(_Unsigned128{42}, _Unsigned128{52}, std::strong_ordering::less); // ordered only by LSW check_order(_Unsigned128{0x11111111'11111111, 0x22222222'22222222}, _Unsigned128{0x01010101'01010101, 0x01010101'01010101}, std::strong_ordering::greater); + check_order(0x22222222'22222222'11111111'11111111__u128, 0x01010101'01010101'01010101'01010101__u128, + std::strong_ordering::greater); +#endif // _HAS_CXX20 { _Unsigned128 u{42}; @@ -169,6 +198,7 @@ constexpr bool test_unsigned() { product = _Unsigned128{0x01010101'01010101, 0x01010101'01010101} * 5; assert(product._Word[0] == 0x05050505'05050505); assert(product._Word[1] == 0x05050505'05050505); + assert(product == 0x05050505'05050505'05050505'05050505__u128); product = 5 * _Unsigned128{0x01010101'01010101, 0x01010101'01010101}; assert(product._Word[0] == 0x05050505'05050505); @@ -178,6 +208,7 @@ constexpr bool test_unsigned() { product *= product; assert(product._Word[0] == 0x08070605'04030201); assert(product._Word[1] == 0x100f0e0d'0c0b0a09); + assert(product == 0x100f0e0d'0c0b0a09'08070605'04030201__u128); assert(+product == product); assert(-product + product == 0); @@ -185,18 +216,21 @@ constexpr bool test_unsigned() { * _Unsigned128{0x000f0e0d'0c0b0a09, 0x08070605'04030201}; assert(product._Word[0] == 0x6dc18e55'16d48f48); assert(product._Word[1] == 0xdc1b6bce'43cd6c21); + assert(product == 0xdc1b6bce'43cd6c21'6dc18e55'16d48f48__u128); assert(+product == product); assert(-product + product == 0); product <<= 11; assert(product._Word[0] == 0x0c72a8b6'a47a4000); assert(product._Word[1] == 0xdb5e721e'6b610b6e); + assert(product == 0xdb5e721e'6b610b6e'0c72a8b6'a47a4000__u128); assert(+product == product); assert(-product + product == 0); product >>= 17; assert(product._Word[0] == 0x85b70639'545b523d); assert(product._Word[1] == 0x00006daf'390f35b0); + assert(product == 0x00006daf'390f35b0'85b70639'545b523d__u128); assert(+product == product); assert(-product + product == 0); } @@ -213,6 +247,7 @@ constexpr bool test_unsigned() { q = _Unsigned128{0x01010101'01010101, 0x01010101'01010101} / _Unsigned128{13}; assert(q._Word[0] == 0xc50013c5'0013c500); assert(q._Word[1] == 0x0013c500'13c50013); + assert(q == 0x0013c500'13c50013'c50013c5'0013c500__u128); q = _Unsigned128{0x22222222'22222222, 0x22222222'22222222} / _Unsigned128{0x11111111'11111111, 0x11111111'11111111}; @@ -262,16 +297,19 @@ constexpr bool test_unsigned() { const _Unsigned128 x{0x01020304'02030405, 0x03040506'04050607}; const _Unsigned128 y{0x07060504'06050403, 0x05040302'04030101}; assert(((x & y) == _Unsigned128{0x01020104'02010401, 0x01040102'04010001})); + assert(((x & y) == 0x01040102'04010001'01020104'02010401__u128)); auto tmp = x; tmp &= y; assert(tmp == (x & y)); assert(((x | y) == _Unsigned128{0x07060704'06070407, 0x07040706'04070707})); + assert(((x | y) == 0x07040706'04070707'07060704'06070407__u128)); tmp = x; tmp |= y; assert(tmp == (x | y)); assert(((x ^ y) == _Unsigned128{0x06040600'04060006, 0x06000604'00060706})); + assert(((x ^ y) == 0x06000604'00060706'06040600'04060006__u128)); tmp = x; tmp ^= y; assert(tmp == (x ^ y)); @@ -308,79 +346,120 @@ constexpr bool test_unsigned() { assert(x._Word[0] == ~0ull); assert(x._Word[1] == static_cast(std::numeric_limits::max())); } + { + STATIC_ASSERT(noexcept(0__u128)); + STATIC_ASSERT(noexcept(42__u128)); + STATIC_ASSERT(noexcept(4'2__u128)); + STATIC_ASSERT(noexcept(052__u128)); + STATIC_ASSERT(noexcept(05'2__u128)); + STATIC_ASSERT(noexcept(0x2a__u128)); + STATIC_ASSERT(noexcept(0X2a__u128)); + STATIC_ASSERT(noexcept(0x2A__u128)); + STATIC_ASSERT(noexcept(0X2A__u128)); + STATIC_ASSERT(noexcept(0x2'A__u128)); + STATIC_ASSERT(noexcept(0b101010__u128)); + STATIC_ASSERT(noexcept(0b1'0101'0__u128)); + STATIC_ASSERT(noexcept(340282366920938463463374607431768211455__u128)); + STATIC_ASSERT(noexcept(0xffffffff'FFFFFFFF'ffffFFFF'FFFFffff__u128)); + + STATIC_ASSERT(42__u128 == 42); + STATIC_ASSERT(42__u128 == 42); + STATIC_ASSERT(42__u128 == 052__u128); + STATIC_ASSERT(42__u128 == 05'2__u128); + STATIC_ASSERT(42__u128 == 0x2a__u128); + STATIC_ASSERT(42__u128 == 0X2'a__u128); + STATIC_ASSERT(42__u128 == 0b101010__u128); + STATIC_ASSERT(42__u128 == 0b101'010__u128); + STATIC_ASSERT( + 340'2823'6692'0938'4634'6337'4607'4317'6821'1455__u128 == 0xffffffff'FFFFFFFF'ffffFFFF'FFFFffff__u128); + + STATIC_ASSERT( + 340'282'366'920'938'463'463'374'607'431'768'211'455__u128 == std::numeric_limits<_Unsigned128>::max()); + STATIC_ASSERT(0xffffffff'ffffffff'ffffffff'ffffffff__u128 == std::numeric_limits<_Unsigned128>::max()); + } return true; } constexpr bool test_signed() { - static_assert(std::regular<_Signed128>); - static_assert(std::three_way_comparable<_Signed128, std::strong_ordering>); - - static_assert(std::numeric_limits<_Signed128>::min() == _Signed128{0, 1ull << 63}); - static_assert(std::numeric_limits<_Signed128>::max() == _Signed128{~0ull, ~0ull >> 1}); - static_assert(std::numeric_limits<_Signed128>::digits == 127); - static_assert(!std::numeric_limits<_Signed128>::is_modulo); - - static_assert(std::same_as, _Signed128>); - static_assert(std::same_as, _Signed128>); - static_assert(std::same_as, _Signed128>); - static_assert(std::same_as, _Signed128>); - static_assert(std::same_as, _Signed128>); +#if _HAS_CXX20 && !defined(__EDG__) // TRANSITION, GH-395 + STATIC_ASSERT(std::regular<_Signed128>); + STATIC_ASSERT(std::three_way_comparable<_Signed128, std::strong_ordering>); +#endif // _HAS_CXX20 && !defined(__EDG__) + + STATIC_ASSERT(std::numeric_limits<_Signed128>::min() == _Signed128{0, 1ull << 63}); + STATIC_ASSERT(std::numeric_limits<_Signed128>::max() == _Signed128{~0ull, ~0ull >> 1}); + STATIC_ASSERT(std::numeric_limits<_Signed128>::digits == 127); + STATIC_ASSERT(!std::numeric_limits<_Signed128>::is_modulo); + + STATIC_ASSERT(SAME_AS, _Signed128>); + STATIC_ASSERT(SAME_AS, _Signed128>); + STATIC_ASSERT(SAME_AS, _Signed128>); + STATIC_ASSERT(SAME_AS, _Signed128>); + STATIC_ASSERT(SAME_AS, _Signed128>); #ifdef __cpp_char8_t - static_assert(std::same_as, _Signed128>); + STATIC_ASSERT(SAME_AS, _Signed128>); #endif // __cpp_char8_t - static_assert(std::same_as, _Signed128>); - static_assert(std::same_as, _Signed128>); - static_assert(std::same_as, _Signed128>); - static_assert(std::same_as, _Signed128>); - static_assert(std::same_as, _Signed128>); - static_assert(std::same_as, _Signed128>); - static_assert(std::same_as, _Signed128>); - static_assert(std::same_as, _Signed128>); - static_assert(std::same_as, _Signed128>); - static_assert(std::same_as, _Signed128>); - - static_assert(std::same_as, _Signed128>); - static_assert(std::same_as, _Signed128>); - static_assert(std::same_as, _Signed128>); - static_assert(std::same_as, _Signed128>); - static_assert(std::same_as, _Signed128>); + STATIC_ASSERT(SAME_AS, _Signed128>); + STATIC_ASSERT(SAME_AS, _Signed128>); + STATIC_ASSERT(SAME_AS, _Signed128>); + STATIC_ASSERT(SAME_AS, _Signed128>); + STATIC_ASSERT(SAME_AS, _Signed128>); + STATIC_ASSERT(SAME_AS, _Signed128>); + STATIC_ASSERT(SAME_AS, _Signed128>); + STATIC_ASSERT(SAME_AS, _Signed128>); + STATIC_ASSERT(SAME_AS, _Signed128>); + STATIC_ASSERT(SAME_AS, _Signed128>); + + STATIC_ASSERT(SAME_AS, _Signed128>); + STATIC_ASSERT(SAME_AS, _Signed128>); + STATIC_ASSERT(SAME_AS, _Signed128>); + STATIC_ASSERT(SAME_AS, _Signed128>); + STATIC_ASSERT(SAME_AS, _Signed128>); #ifdef __cpp_char8_t - static_assert(std::same_as, _Signed128>); + STATIC_ASSERT(SAME_AS, _Signed128>); #endif // __cpp_char8_t - static_assert(std::same_as, _Signed128>); - static_assert(std::same_as, _Signed128>); - static_assert(std::same_as, _Signed128>); - static_assert(std::same_as, _Signed128>); - static_assert(std::same_as, _Signed128>); - static_assert(std::same_as, _Signed128>); - static_assert(std::same_as, _Signed128>); - static_assert(std::same_as, _Signed128>); - static_assert(std::same_as, _Signed128>); - static_assert(std::same_as, _Signed128>); - - static_assert(std::_Integer_class<_Signed128>); - static_assert(std::_Integer_like<_Signed128>); - static_assert(std::_Signed_integer_like<_Signed128>); - static_assert(std::same_as, _Unsigned128>); - static_assert(std::same_as, _Signed128>); + STATIC_ASSERT(SAME_AS, _Signed128>); + STATIC_ASSERT(SAME_AS, _Signed128>); + STATIC_ASSERT(SAME_AS, _Signed128>); + STATIC_ASSERT(SAME_AS, _Signed128>); + STATIC_ASSERT(SAME_AS, _Signed128>); + STATIC_ASSERT(SAME_AS, _Signed128>); + STATIC_ASSERT(SAME_AS, _Signed128>); + STATIC_ASSERT(SAME_AS, _Signed128>); + STATIC_ASSERT(SAME_AS, _Signed128>); + STATIC_ASSERT(SAME_AS, _Signed128>); + +#if _HAS_CXX20 && !defined(__EDG__) // TRANSITION, GH-395 + STATIC_ASSERT(std::_Integer_class<_Signed128>); + STATIC_ASSERT(std::_Integer_like<_Signed128>); + STATIC_ASSERT(std::_Signed_integer_like<_Signed128>); + STATIC_ASSERT(SAME_AS, _Unsigned128>); + STATIC_ASSERT(SAME_AS, _Signed128>); +#endif // _HAS_CXX20 && !defined(__EDG__) check_equal(_Signed128{}); check_equal(_Signed128{42}); check_equal(_Signed128{-42}); check_equal(_Signed128{0x11111111'11111111, 0x22222222'22222222}); + check_equal(0x22222222'22222222'11111111'11111111__i128); +#if _HAS_CXX20 check_order(_Signed128{42}, _Signed128{-42}, std::strong_ordering::greater); check_order(_Signed128{0x11111111'11111111, 0x22222222'22222222}, _Signed128{0x01010101'01010101, 0x01010101'01010101}, std::strong_ordering::greater); + check_order(0x22222222'22222222'11111111'11111111__i128, 0x01010101'01010101'01010101'01010101__i128, + std::strong_ordering::greater); check_order(_Signed128{~0ull, ~0ull}, _Signed128{-1}, std::strong_ordering::equal); check_order(_Signed128{-2}, _Signed128{-1}, std::strong_ordering::less); check_order(_Signed128{-2}, _Signed128{1}, std::strong_ordering::less); check_order(_Signed128{2}, _Signed128{-1}, std::strong_ordering::greater); check_order(_Signed128{2}, _Signed128{1}, std::strong_ordering::greater); +#endif // _HAS_CXX20 check_equal(_Signed128{0, 0}); +#if _HAS_CXX20 check_order(_Signed128{0, (1ull << 63)}, _Signed128{0, 0}, std::strong_ordering::less); check_order(_Signed128{0, (1ull << 63)}, _Signed128{0, (1ull << 63)}, std::strong_ordering::equal); check_order(_Signed128{0, 0}, _Signed128{1, 0}, std::strong_ordering::less); @@ -392,6 +471,7 @@ constexpr bool test_signed() { check_order(_Signed128{0, 0}, _Signed128{1, 1}, std::strong_ordering::less); check_order(_Signed128{0, (1ull << 63)}, _Signed128{1, 1}, std::strong_ordering::less); check_order(_Signed128{0, (1ull << 63)}, _Signed128{1, 1 | (1ull << 63)}, std::strong_ordering::less); +#endif // _HAS_CXX20 assert((_Signed128{-2} == _Unsigned128{0ull - 2, ~0ull})); assert((_Unsigned128{_Signed128{-2}} == _Unsigned128{0ull - 2, ~0ull})); @@ -497,16 +577,19 @@ constexpr bool test_signed() { } { auto product = _Signed128{0x01010101'01010101, 0x01010101'01010101} * 5; + assert(product == 0x05050505'05050505'05050505'05050505__i128); assert(product._Word[0] == 0x05050505'05050505); assert(product._Word[1] == 0x05050505'05050505); product = 5 * _Signed128{0x01010101'01010101, 0x01010101'01010101}; + assert(product == 0x05050505'05050505'05050505'05050505__i128); assert(product._Word[0] == 0x05050505'05050505); assert(product._Word[1] == 0x05050505'05050505); } { auto product = _Signed128{0x01010101'01010101, 0x01010101'01010101}; product *= product; + assert(product == 0x100f0e0d'0c0b0a09'08070605'04030201__i128); assert(product._Word[0] == 0x08070605'04030201); assert(product._Word[1] == 0x100f0e0d'0c0b0a09); assert(+product == product); @@ -515,18 +598,21 @@ constexpr bool test_signed() { { auto product = _Signed128{0x01020304'05060708, 0x090a0b0c'0d0e0f00} * _Signed128{0x000f0e0d'0c0b0a09, 0x08070605'04030201}; + assert(product == -0x23e49431'bc3293de'923e71aa'e92b70b8__i128); assert(product._Word[0] == 0x6dc18e55'16d48f48); assert(product._Word[1] == 0xdc1b6bce'43cd6c21); assert(+product == product); assert(-product + product == 0); product <<= 11; + assert(product == -0x24a18de1'949ef491'f38d5749'5b85c000__i128); assert(product._Word[0] == 0x0c72a8b6'a47a4000); assert(product._Word[1] == 0xdb5e721e'6b610b6e); assert(+product == product); assert(-product + product == 0); product >>= 17; + assert(product == -0x00001250'c6f0ca4f'7a48f9c6'aba4adc3__i128); assert(product._Word[0] == 0x85b70639'545b523d); assert(product._Word[1] == 0xffffedaf'390f35b0); assert(+product == product); @@ -566,6 +652,7 @@ constexpr bool test_signed() { assert(q._Word[1] == 0); q = _Signed128{0x01010101'01010101, 0x01010101'01010101} / _Signed128{13}; + assert(q == 0x0013c500'13c50013'c50013c5'0013c500__i128); assert(q._Word[0] == 0xc50013c5'0013c500); assert(q._Word[1] == 0x0013c500'13c50013); @@ -658,16 +745,19 @@ constexpr bool test_signed() { const _Signed128 x{0x01020304'02030405, 0x03040506'04050607}; const _Signed128 y{0x07060504'06050403, 0x05040302'04030101}; assert(((x & y) == _Signed128{0x01020104'02010401, 0x01040102'04010001})); + assert(((x & y) == 0x01040102'04010001'01020104'02010401__i128)); auto tmp = x; tmp &= y; assert(tmp == (x & y)); assert(((x | y) == _Signed128{0x07060704'06070407, 0x07040706'04070707})); + assert(((x | y) == 0x07040706'04070707'07060704'06070407__i128)); tmp = x; tmp |= y; assert(tmp == (x | y)); assert(((x ^ y) == _Signed128{0x06040600'04060006, 0x06000604'00060706})); + assert(((x ^ y) == 0x06000604'00060706'06040600'04060006__i128)); tmp = x; tmp ^= y; assert(tmp == (x ^ y)); @@ -704,6 +794,41 @@ constexpr bool test_signed() { assert(x._Word[1] == static_cast(std::numeric_limits::max())); assert(x == std::numeric_limits<_Signed128>::max()); } + { + STATIC_ASSERT(noexcept(0__i128)); + STATIC_ASSERT(noexcept(42__i128)); + STATIC_ASSERT(noexcept(4'2__i128)); + STATIC_ASSERT(noexcept(052__i128)); + STATIC_ASSERT(noexcept(05'2__i128)); + STATIC_ASSERT(noexcept(0x2a__i128)); + STATIC_ASSERT(noexcept(0X2a__i128)); + STATIC_ASSERT(noexcept(0x2A__i128)); + STATIC_ASSERT(noexcept(0X2A__i128)); + STATIC_ASSERT(noexcept(0x2'A__i128)); + STATIC_ASSERT(noexcept(0b101010__i128)); + STATIC_ASSERT(noexcept(0b1'0101'0__i128)); + STATIC_ASSERT(noexcept(170141183460469231731687303715884105727__i128)); + STATIC_ASSERT(noexcept(0x7fffffff'FFFFFFFF'ffffFFFF'FFFFffff__i128)); + + STATIC_ASSERT(42__i128 == 42); + STATIC_ASSERT(42__i128 == 42); + STATIC_ASSERT(42__i128 == 052__i128); + STATIC_ASSERT(42__i128 == 05'2__i128); + STATIC_ASSERT(42__i128 == 0x2a__i128); + STATIC_ASSERT(42__i128 == 0X2'a__i128); + STATIC_ASSERT(42__i128 == 0b101010__i128); + STATIC_ASSERT(42__i128 == 0b101'010__i128); + STATIC_ASSERT( + 170'1411'8346'0469'2317'3168'7303'7158'8410'5727__i128 == 0x7fffffff'FFFFFFFF'ffffFFFF'FFFFffff__i128); + + STATIC_ASSERT( + 170'141'183'460'469'231'731'687'303'715'884'105'727__i128 == std::numeric_limits<_Signed128>::max()); + STATIC_ASSERT(0x7fffffff'ffffffff'ffffffff'ffffffff__i128 == std::numeric_limits<_Signed128>::max()); + + STATIC_ASSERT( + -170'141'183'460'469'231'731'687'303'715'884'105'727__i128 - 1 == std::numeric_limits<_Signed128>::min()); + STATIC_ASSERT(-0x7fffffff'ffffffff'ffffffff'ffffffff__i128 - 1 == std::numeric_limits<_Signed128>::min()); + } return true; } @@ -711,18 +836,26 @@ constexpr bool test_signed() { template T val() noexcept; +#if _HAS_CXX20 && !defined(__EDG__) // TRANSITION, GH-395 template concept CanConditional = requires { true ? val() : val(); }; +#else // ^^^ has concepts / vvv has no concepts +template +constexpr bool CanConditional = false; + +template +constexpr bool CanConditional() : val())>> = true; +#endif // _HAS_CXX20 && !defined(__EDG__) constexpr bool test_cross() { // Test the behavior of cross-type operations. -#define TEST(expr, result) \ - do { \ - static_assert(std::same_as>); \ - assert((expr) == (result)); \ +#define TEST(expr, result) \ + do { \ + STATIC_ASSERT(SAME_AS>); \ + assert((expr) == (result)); \ } while (0) //////// Mixed integer-class operands @@ -764,14 +897,16 @@ constexpr bool test_cross() { // convertible only to wider types, or types of the same width and // signedness. Consequently, the conditional operator should reject integer- // class operands with the same width but differing signedness. - static_assert(!CanConditional<_Unsigned128, _Signed128>); - static_assert(!CanConditional<_Signed128, _Unsigned128>); + STATIC_ASSERT(!CanConditional<_Unsigned128, _Signed128>); + STATIC_ASSERT(!CanConditional<_Signed128, _Unsigned128>); +#if _HAS_CXX20 && !defined(__EDG__) // TRANSITION, GH-395 // Conversions between integer-class types with the same width and differing // signedness are narrowing, so the three-way comparison operator should // reject mixed operands of such types. - static_assert(!std::three_way_comparable_with<_Unsigned128, _Signed128>); - static_assert(!std::three_way_comparable_with<_Signed128, _Unsigned128>); + STATIC_ASSERT(!std::three_way_comparable_with<_Unsigned128, _Signed128>); + STATIC_ASSERT(!std::three_way_comparable_with<_Signed128, _Unsigned128>); +#endif // _HAS_CXX20 && !defined(__EDG__) // Other comparison operators behave as they do for operands of mixed // integral types; when the operands have the same width, the signed operand @@ -917,6 +1052,7 @@ constexpr bool test_cross() { TEST(true ? 42 : _Signed128{13}, _Signed128{42}); TEST(true ? 42 : _Unsigned128{13}, _Unsigned128{42}); +#if _HAS_CXX20 // (meow <=> 0) here is a hack to get prvalues TEST(4 <=> _Unsigned128{3}, (std::strong_ordering::greater <=> 0)); TEST(4 <=> _Signed128{3}, (std::strong_ordering::greater <=> 0)); @@ -930,6 +1066,7 @@ constexpr bool test_cross() { TEST(-3 <=> _Signed128{3}, (std::strong_ordering::less <=> 0)); TEST(_Signed128{-3} <=> 3, (std::strong_ordering::less <=> 0)); TEST(_Unsigned128{-3} <=> 3, (std::strong_ordering::greater <=> 0)); +#endif // _HAS_CXX20 // Other comparison operators behave as they do for operands of mixed // integral types; when the operands have the same width, the signed operand @@ -1041,9 +1178,9 @@ constexpr bool test_cross() { int main() { test_unsigned(); - static_assert(test_unsigned()); + STATIC_ASSERT(test_unsigned()); test_signed(); - static_assert(test_signed()); + STATIC_ASSERT(test_signed()); test_cross(); - static_assert(test_cross()); + STATIC_ASSERT(test_cross()); } From 67dfc72e4956353205872904ced433104d709538 Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Tue, 16 Aug 2022 14:49:34 +0800 Subject: [PATCH 03/25] Fix a misformatted line --- stl/inc/__msvc_int128.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stl/inc/__msvc_int128.hpp b/stl/inc/__msvc_int128.hpp index 6d73953f048..df3fb5f4a59 100644 --- a/stl/inc/__msvc_int128.hpp +++ b/stl/inc/__msvc_int128.hpp @@ -137,7 +137,7 @@ struct static constexpr void _Knuth_4_3_1_M( const uint32_t (&__u)[__m], const uint32_t (&__v)[__n], uint32_t (&__w)[__n + __m]) noexcept { #ifdef _ENABLE_STL_INTERNAL_CHECK - constexpr auto _Int_max = size_t{(numeric_limits::max) ()}; + constexpr auto _Int_max = size_t{(numeric_limits::max)()}; _STL_INTERNAL_STATIC_ASSERT(__m <= _Int_max); _STL_INTERNAL_STATIC_ASSERT(__n <= _Int_max); #endif // _ENABLE_STL_INTERNAL_CHECK From bf6279041224eaf8774cd027ed31356293041193 Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Tue, 16 Aug 2022 15:36:31 +0800 Subject: [PATCH 04/25] Fixes needed for EDG --- stl/inc/__msvc_int128.hpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/stl/inc/__msvc_int128.hpp b/stl/inc/__msvc_int128.hpp index df3fb5f4a59..4ac203546a6 100644 --- a/stl/inc/__msvc_int128.hpp +++ b/stl/inc/__msvc_int128.hpp @@ -1319,6 +1319,11 @@ struct _Signed128 : _Base128 { return _Signed128{_Result}; } + _TEMPLATE_CLASS_INTEGRAL(_Ty) + _NODISCARD_FRIEND constexpr _Signed128 operator%(_Signed128 _Left, const _Ty _Right) noexcept { + return _Left % _Signed128{_Right}; + } + _TEMPLATE_CLASS_INTEGRAL(_Ty) constexpr _Signed128& operator%=(const _Ty _That) noexcept { *this = *this % _That; @@ -1463,7 +1468,7 @@ inline namespace literals { template _CONSTEVAL _U128_parse_result _Parse_u128_impl() noexcept { - constexpr char _Char_seq[]{_Chars...}; + constexpr char _Char_seq[]{_Chars..., '\0'}; constexpr auto _U128_max = (_STD numeric_limits<_Unsigned128>::max)(); _Unsigned128 _Val{}; From a7f5e33a6d3868012c28fe01e182dfaf76aae7b2 Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Tue, 16 Aug 2022 15:56:56 +0800 Subject: [PATCH 05/25] Cleanup #if !defined(__EDG__) And rerun. --- tests/std/tests/P1522R1_difference_type/test.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/std/tests/P1522R1_difference_type/test.cpp b/tests/std/tests/P1522R1_difference_type/test.cpp index 34a24177844..d0443b76ada 100644 --- a/tests/std/tests/P1522R1_difference_type/test.cpp +++ b/tests/std/tests/P1522R1_difference_type/test.cpp @@ -11,9 +11,9 @@ #if _HAS_CXX20 #include -#if !defined(__EDG__) // TRANSITION, GH-395 +#ifndef __EDG__ // TRANSITION, GH-395 #include -#endif // !defined(__EDG__) +#endif // __EDG__ #endif // _HAS_CXX20 #if _HAS_CXX20 && !defined(__EDG__) // TRANSITION, GH-395 From fc8cbce93e45461a72c816c76b1aea05147298dc Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Tue, 16 Aug 2022 17:58:25 +0800 Subject: [PATCH 06/25] Test digit separators for UDLs instead of built-in ones And rerun. --- tests/std/tests/P1522R1_difference_type/test.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/tests/std/tests/P1522R1_difference_type/test.cpp b/tests/std/tests/P1522R1_difference_type/test.cpp index d0443b76ada..c112469d3e7 100644 --- a/tests/std/tests/P1522R1_difference_type/test.cpp +++ b/tests/std/tests/P1522R1_difference_type/test.cpp @@ -363,13 +363,13 @@ constexpr bool test_unsigned() { STATIC_ASSERT(noexcept(0xffffffff'FFFFFFFF'ffffFFFF'FFFFffff__u128)); STATIC_ASSERT(42__u128 == 42); - STATIC_ASSERT(42__u128 == 42); + STATIC_ASSERT(4'2__u128 == 42); STATIC_ASSERT(42__u128 == 052__u128); - STATIC_ASSERT(42__u128 == 05'2__u128); + STATIC_ASSERT(4'2__u128 == 052__u128); STATIC_ASSERT(42__u128 == 0x2a__u128); - STATIC_ASSERT(42__u128 == 0X2'a__u128); + STATIC_ASSERT(4'2__u128 == 0X2a__u128); STATIC_ASSERT(42__u128 == 0b101010__u128); - STATIC_ASSERT(42__u128 == 0b101'010__u128); + STATIC_ASSERT(4'2__u128 == 0b101010__u128); STATIC_ASSERT( 340'2823'6692'0938'4634'6337'4607'4317'6821'1455__u128 == 0xffffffff'FFFFFFFF'ffffFFFF'FFFFffff__u128); @@ -811,13 +811,13 @@ constexpr bool test_signed() { STATIC_ASSERT(noexcept(0x7fffffff'FFFFFFFF'ffffFFFF'FFFFffff__i128)); STATIC_ASSERT(42__i128 == 42); - STATIC_ASSERT(42__i128 == 42); + STATIC_ASSERT(4'2__i128 == 42); STATIC_ASSERT(42__i128 == 052__i128); - STATIC_ASSERT(42__i128 == 05'2__i128); + STATIC_ASSERT(4'2__i128 == 052__i128); STATIC_ASSERT(42__i128 == 0x2a__i128); - STATIC_ASSERT(42__i128 == 0X2'a__i128); + STATIC_ASSERT(4'2__i128 == 0X2a__i128); STATIC_ASSERT(42__i128 == 0b101010__i128); - STATIC_ASSERT(42__i128 == 0b101'010__i128); + STATIC_ASSERT(4'2__i128 == 0b101010__i128); STATIC_ASSERT( 170'1411'8346'0469'2317'3168'7303'7158'8410'5727__i128 == 0x7fffffff'FFFFFFFF'ffffFFFF'FFFFffff__i128); From c89d2e58c1088fb53c839530b46ee155fc83e0b3 Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Wed, 17 Aug 2022 11:01:33 +0800 Subject: [PATCH 07/25] Address strega-nil-ms's review comments Co-authored-by: nicole mazzuca <83086508+strega-nil-ms@users.noreply.github.com> --- stl/inc/__msvc_int128.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/stl/inc/__msvc_int128.hpp b/stl/inc/__msvc_int128.hpp index 4ac203546a6..d88cc20bae4 100644 --- a/stl/inc/__msvc_int128.hpp +++ b/stl/inc/__msvc_int128.hpp @@ -19,14 +19,14 @@ #include #define _ZERO_OR_NO_INIT #else // ^^^ _HAS_CXX20 / vvv !_HAS_CXX20 -#define _ZERO_OR_NO_INIT = {0} +#define _ZERO_OR_NO_INIT = {0} // Trivial default initialization is not allowed in constexpr functions before C++20. #endif // _HAS_CXX20 #ifdef __cpp_lib_concepts #include -#define _TEMPLATE_CLASS_INTEGRAL(type) template +#define _TEMPLATE_CLASS_INTEGRAL(type) template #else -#define _TEMPLATE_CLASS_INTEGRAL(type) template , int> = 0> +#define _TEMPLATE_CLASS_INTEGRAL(type) template , int> = 0> #endif // __cpp_lib_concepts #pragma pack(push, _CRT_PACKING) From 9dd1bba933223fcba7dd1e8607fb339063467c06 Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Thu, 25 Aug 2022 12:26:10 +0800 Subject: [PATCH 08/25] Address strega-nil-ms's review comments, again Co-authored-by: nicole mazzuca <83086508+strega-nil-ms@users.noreply.github.com> --- stl/inc/__msvc_int128.hpp | 42 +++++++++++++++++++++------------------ 1 file changed, 23 insertions(+), 19 deletions(-) diff --git a/stl/inc/__msvc_int128.hpp b/stl/inc/__msvc_int128.hpp index d88cc20bae4..7ef0d1a06a8 100644 --- a/stl/inc/__msvc_int128.hpp +++ b/stl/inc/__msvc_int128.hpp @@ -19,7 +19,7 @@ #include #define _ZERO_OR_NO_INIT #else // ^^^ _HAS_CXX20 / vvv !_HAS_CXX20 -#define _ZERO_OR_NO_INIT = {0} // Trivial default initialization is not allowed in constexpr functions before C++20. +#define _ZERO_OR_NO_INIT {} // Trivial default initialization is not allowed in constexpr functions before C++20. #endif // _HAS_CXX20 #ifdef __cpp_lib_concepts @@ -1468,26 +1468,30 @@ inline namespace literals { template _CONSTEVAL _U128_parse_result _Parse_u128_impl() noexcept { - constexpr char _Char_seq[]{_Chars..., '\0'}; - constexpr auto _U128_max = (_STD numeric_limits<_Unsigned128>::max)(); - - _Unsigned128 _Val{}; - for (size_t _Ind = 0; _Ind != sizeof...(_Chars); ++_Ind) { - if (_Char_seq[_Ind] == '\'') { - continue; - } - - const unsigned int _Digit = _Char_to_digit(_Char_seq[_Ind]); - if (_Digit == static_cast(-1)) { - return {_U128_parse_status::_Invalid, _Unsigned128{}}; + if constexpr (sizeof...(_Chars) == 0) { + return {_U128_parse_status::_Valid, 0}; + } else { + constexpr char _Char_seq[]{_Chars...}; + constexpr auto _U128_max = (_STD numeric_limits<_Unsigned128>::max)(); + + _Unsigned128 _Val{}; + for (const char _Ch : _Char_seq) { + if (_Ch == '\'') { + continue; + } + + const unsigned int _Digit = _Char_to_digit(_Ch); + if (_Digit == static_cast(-1)) { + return {_U128_parse_status::_Invalid, _Unsigned128{}}; + } + if ((_Val > _U128_max / _Base) || (_Base * _Val > _U128_max - _Digit)) { + return {_U128_parse_status::_Overflow, _Unsigned128{}}; + } + + _Val = _Base * _Val + _Digit; } - if ((_Val > _U128_max / _Base) || (_Base * _Val > _U128_max - _Digit)) { - return {_U128_parse_status::_Overflow, _Unsigned128{}}; - } - - _Val = _Base * _Val + _Digit; + return {_U128_parse_status::_Valid, _Val}; } - return {_U128_parse_status::_Valid, _Val}; } template From 5bd7059a90b966a0ac12d2bbe06c6b1cf6ffb21a Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Thu, 25 Aug 2022 13:36:08 +0800 Subject: [PATCH 09/25] Break line for clang-format --- stl/inc/__msvc_int128.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/stl/inc/__msvc_int128.hpp b/stl/inc/__msvc_int128.hpp index 7ef0d1a06a8..ebca32db669 100644 --- a/stl/inc/__msvc_int128.hpp +++ b/stl/inc/__msvc_int128.hpp @@ -19,7 +19,8 @@ #include #define _ZERO_OR_NO_INIT #else // ^^^ _HAS_CXX20 / vvv !_HAS_CXX20 -#define _ZERO_OR_NO_INIT {} // Trivial default initialization is not allowed in constexpr functions before C++20. +#define _ZERO_OR_NO_INIT \ + {} // Trivial default initialization is not allowed in constexpr functions before C++20. #endif // _HAS_CXX20 #ifdef __cpp_lib_concepts From 2115e43af00172daf5fa5764a51193f87132a3ca Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Thu, 25 Aug 2022 16:44:30 +0800 Subject: [PATCH 10/25] Use alternative order type for pre-C++20 and __cpp_lib_concepts --- .../tests/P1522R1_difference_type/test.cpp | 136 +++++++++--------- 1 file changed, 71 insertions(+), 65 deletions(-) diff --git a/tests/std/tests/P1522R1_difference_type/test.cpp b/tests/std/tests/P1522R1_difference_type/test.cpp index c112469d3e7..87f1d5f322a 100644 --- a/tests/std/tests/P1522R1_difference_type/test.cpp +++ b/tests/std/tests/P1522R1_difference_type/test.cpp @@ -11,16 +11,27 @@ #if _HAS_CXX20 #include -#ifndef __EDG__ // TRANSITION, GH-395 -#include -#endif // __EDG__ +namespace ordtest { + using std::strong_ordering; +} +#else // ^^^ _HAS_CXX20 / vvv !_HAS_CXX20 +namespace ordtest { + enum class strong_ordering : signed char { + less = -1, + equal = 0, + equivalent = 0, + greater = 1, + }; +} #endif // _HAS_CXX20 -#if _HAS_CXX20 && !defined(__EDG__) // TRANSITION, GH-395 +#ifdef __cpp_lib_concepts // TRANSITION, GH-395 +#include + #define SAME_AS std::same_as #else // ^^^ has concepts / vvv has no concepts #define SAME_AS std::is_same_v -#endif // _HAS_CXX20 && !defined(__EDG__) +#endif // __cpp_lib_concepts #define STATIC_ASSERT(...) static_assert(__VA_ARGS__, #__VA_ARGS__) @@ -41,32 +52,33 @@ constexpr void check_equal(const I& x) { #endif // _HAS_CXX20 } -#if _HAS_CXX20 -constexpr void check_order(const auto& x, const auto& y, const std::strong_ordering ord) { - assert((x == y) == (ord == std::strong_ordering::equal)); - assert((x != y) == (ord != std::strong_ordering::equal)); - assert((x < y) == (ord == std::strong_ordering::less)); - assert((x > y) == (ord == std::strong_ordering::greater)); - assert((x <= y) == (ord != std::strong_ordering::greater)); - assert((x >= y) == (ord != std::strong_ordering::less)); - - assert((y == x) == (ord == std::strong_ordering::equal)); - assert((y != x) == (ord != std::strong_ordering::equal)); - assert((y < x) == (ord == std::strong_ordering::greater)); - assert((y > x) == (ord == std::strong_ordering::less)); - assert((y <= x) == (ord != std::strong_ordering::less)); - assert((y >= x) == (ord != std::strong_ordering::greater)); +template +constexpr void check_order(const I1& x, const I2& y, const ordtest::strong_ordering ord) { + assert((x == y) == (ord == ordtest::strong_ordering::equal)); + assert((x != y) == (ord != ordtest::strong_ordering::equal)); + assert((x < y) == (ord == ordtest::strong_ordering::less)); + assert((x > y) == (ord == ordtest::strong_ordering::greater)); + assert((x <= y) == (ord != ordtest::strong_ordering::greater)); + assert((x >= y) == (ord != ordtest::strong_ordering::less)); + + assert((y == x) == (ord == ordtest::strong_ordering::equal)); + assert((y != x) == (ord != ordtest::strong_ordering::equal)); + assert((y < x) == (ord == ordtest::strong_ordering::greater)); + assert((y > x) == (ord == ordtest::strong_ordering::less)); + assert((y <= x) == (ord != ordtest::strong_ordering::less)); + assert((y >= x) == (ord != ordtest::strong_ordering::greater)); +#if _HAS_CXX20 assert((x <=> y) == (ord <=> 0)); assert((y <=> x) == (0 <=> ord)); -} #endif // _HAS_CXX20 +} constexpr bool test_unsigned() { -#if _HAS_CXX20 && !defined(__EDG__) // TRANSITION, GH-395 +#ifdef __cpp_lib_concepts // TRANSITION, GH-395 STATIC_ASSERT(std::regular<_Unsigned128>); - STATIC_ASSERT(std::three_way_comparable<_Unsigned128, std::strong_ordering>); -#endif // _HAS_CXX20 && !defined(__EDG__) + STATIC_ASSERT(std::three_way_comparable<_Unsigned128, ordtest::strong_ordering>); +#endif // __cpp_lib_concepts STATIC_ASSERT(std::numeric_limits<_Unsigned128>::min() == 0); STATIC_ASSERT(std::numeric_limits<_Unsigned128>::max() == ~_Unsigned128{}); @@ -113,13 +125,13 @@ constexpr bool test_unsigned() { STATIC_ASSERT(SAME_AS, _Unsigned128>); STATIC_ASSERT(SAME_AS, _Unsigned128>); -#if _HAS_CXX20 && !defined(__EDG__) // TRANSITION, GH-395 +#ifdef __cpp_lib_concepts // TRANSITION, GH-395 STATIC_ASSERT(std::_Integer_class<_Unsigned128>); STATIC_ASSERT(std::_Integer_like<_Unsigned128>); STATIC_ASSERT(!std::_Signed_integer_like<_Unsigned128>); STATIC_ASSERT(SAME_AS, _Unsigned128>); STATIC_ASSERT(SAME_AS, _Signed128>); -#endif // _HAS_CXX20 && !defined(__EDG__) +#endif // __cpp_lib_concepts check_equal(_Unsigned128{}); check_equal(_Unsigned128{42}); @@ -127,15 +139,13 @@ constexpr bool test_unsigned() { check_equal(_Unsigned128{0x11111111'11111111, 0x22222222'22222222}); check_equal(0x22222222'22222222'11111111'11111111__u128); -#if _HAS_CXX20 - check_order(_Unsigned128{42}, _Unsigned128{-42}, std::strong_ordering::less); - check_order(_Unsigned128{0, 42}, _Unsigned128{0, 52}, std::strong_ordering::less); // ordered only by MSW - check_order(_Unsigned128{42}, _Unsigned128{52}, std::strong_ordering::less); // ordered only by LSW + check_order(_Unsigned128{42}, _Unsigned128{-42}, ordtest::strong_ordering::less); + check_order(_Unsigned128{0, 42}, _Unsigned128{0, 52}, ordtest::strong_ordering::less); // ordered only by MSW + check_order(_Unsigned128{42}, _Unsigned128{52}, ordtest::strong_ordering::less); // ordered only by LSW check_order(_Unsigned128{0x11111111'11111111, 0x22222222'22222222}, - _Unsigned128{0x01010101'01010101, 0x01010101'01010101}, std::strong_ordering::greater); + _Unsigned128{0x01010101'01010101, 0x01010101'01010101}, ordtest::strong_ordering::greater); check_order(0x22222222'22222222'11111111'11111111__u128, 0x01010101'01010101'01010101'01010101__u128, - std::strong_ordering::greater); -#endif // _HAS_CXX20 + ordtest::strong_ordering::greater); { _Unsigned128 u{42}; @@ -382,10 +392,10 @@ constexpr bool test_unsigned() { } constexpr bool test_signed() { -#if _HAS_CXX20 && !defined(__EDG__) // TRANSITION, GH-395 +#ifdef __cpp_lib_concepts // TRANSITION, GH-395 STATIC_ASSERT(std::regular<_Signed128>); - STATIC_ASSERT(std::three_way_comparable<_Signed128, std::strong_ordering>); -#endif // _HAS_CXX20 && !defined(__EDG__) + STATIC_ASSERT(std::three_way_comparable<_Signed128, ordtest::strong_ordering>); +#endif // __cpp_lib_concepts STATIC_ASSERT(std::numeric_limits<_Signed128>::min() == _Signed128{0, 1ull << 63}); STATIC_ASSERT(std::numeric_limits<_Signed128>::max() == _Signed128{~0ull, ~0ull >> 1}); @@ -430,13 +440,13 @@ constexpr bool test_signed() { STATIC_ASSERT(SAME_AS, _Signed128>); STATIC_ASSERT(SAME_AS, _Signed128>); -#if _HAS_CXX20 && !defined(__EDG__) // TRANSITION, GH-395 +#ifdef __cpp_lib_concepts // TRANSITION, GH-395 STATIC_ASSERT(std::_Integer_class<_Signed128>); STATIC_ASSERT(std::_Integer_like<_Signed128>); STATIC_ASSERT(std::_Signed_integer_like<_Signed128>); STATIC_ASSERT(SAME_AS, _Unsigned128>); STATIC_ASSERT(SAME_AS, _Signed128>); -#endif // _HAS_CXX20 && !defined(__EDG__) +#endif // __cpp_lib_concepts check_equal(_Signed128{}); check_equal(_Signed128{42}); @@ -444,34 +454,30 @@ constexpr bool test_signed() { check_equal(_Signed128{0x11111111'11111111, 0x22222222'22222222}); check_equal(0x22222222'22222222'11111111'11111111__i128); -#if _HAS_CXX20 - check_order(_Signed128{42}, _Signed128{-42}, std::strong_ordering::greater); + check_order(_Signed128{42}, _Signed128{-42}, ordtest::strong_ordering::greater); check_order(_Signed128{0x11111111'11111111, 0x22222222'22222222}, - _Signed128{0x01010101'01010101, 0x01010101'01010101}, std::strong_ordering::greater); + _Signed128{0x01010101'01010101, 0x01010101'01010101}, ordtest::strong_ordering::greater); check_order(0x22222222'22222222'11111111'11111111__i128, 0x01010101'01010101'01010101'01010101__i128, - std::strong_ordering::greater); - check_order(_Signed128{~0ull, ~0ull}, _Signed128{-1}, std::strong_ordering::equal); + ordtest::strong_ordering::greater); + check_order(_Signed128{~0ull, ~0ull}, _Signed128{-1}, ordtest::strong_ordering::equal); - check_order(_Signed128{-2}, _Signed128{-1}, std::strong_ordering::less); - check_order(_Signed128{-2}, _Signed128{1}, std::strong_ordering::less); - check_order(_Signed128{2}, _Signed128{-1}, std::strong_ordering::greater); - check_order(_Signed128{2}, _Signed128{1}, std::strong_ordering::greater); -#endif // _HAS_CXX20 + check_order(_Signed128{-2}, _Signed128{-1}, ordtest::strong_ordering::less); + check_order(_Signed128{-2}, _Signed128{1}, ordtest::strong_ordering::less); + check_order(_Signed128{2}, _Signed128{-1}, ordtest::strong_ordering::greater); + check_order(_Signed128{2}, _Signed128{1}, ordtest::strong_ordering::greater); check_equal(_Signed128{0, 0}); -#if _HAS_CXX20 - check_order(_Signed128{0, (1ull << 63)}, _Signed128{0, 0}, std::strong_ordering::less); - check_order(_Signed128{0, (1ull << 63)}, _Signed128{0, (1ull << 63)}, std::strong_ordering::equal); - check_order(_Signed128{0, 0}, _Signed128{1, 0}, std::strong_ordering::less); - check_order(_Signed128{0, (1ull << 63)}, _Signed128{1, 0}, std::strong_ordering::less); - check_order(_Signed128{0, (1ull << 63)}, _Signed128{1, (1ull << 63)}, std::strong_ordering::less); - check_order(_Signed128{0, 0}, _Signed128{0, 1}, std::strong_ordering::less); - check_order(_Signed128{0, (1ull << 63)}, _Signed128{0, 1}, std::strong_ordering::less); - check_order(_Signed128{0, (1ull << 63)}, _Signed128{0, 1 | (1ull << 63)}, std::strong_ordering::less); - check_order(_Signed128{0, 0}, _Signed128{1, 1}, std::strong_ordering::less); - check_order(_Signed128{0, (1ull << 63)}, _Signed128{1, 1}, std::strong_ordering::less); - check_order(_Signed128{0, (1ull << 63)}, _Signed128{1, 1 | (1ull << 63)}, std::strong_ordering::less); -#endif // _HAS_CXX20 + check_order(_Signed128{0, (1ull << 63)}, _Signed128{0, 0}, ordtest::strong_ordering::less); + check_order(_Signed128{0, (1ull << 63)}, _Signed128{0, (1ull << 63)}, ordtest::strong_ordering::equal); + check_order(_Signed128{0, 0}, _Signed128{1, 0}, ordtest::strong_ordering::less); + check_order(_Signed128{0, (1ull << 63)}, _Signed128{1, 0}, ordtest::strong_ordering::less); + check_order(_Signed128{0, (1ull << 63)}, _Signed128{1, (1ull << 63)}, ordtest::strong_ordering::less); + check_order(_Signed128{0, 0}, _Signed128{0, 1}, ordtest::strong_ordering::less); + check_order(_Signed128{0, (1ull << 63)}, _Signed128{0, 1}, ordtest::strong_ordering::less); + check_order(_Signed128{0, (1ull << 63)}, _Signed128{0, 1 | (1ull << 63)}, ordtest::strong_ordering::less); + check_order(_Signed128{0, 0}, _Signed128{1, 1}, ordtest::strong_ordering::less); + check_order(_Signed128{0, (1ull << 63)}, _Signed128{1, 1}, ordtest::strong_ordering::less); + check_order(_Signed128{0, (1ull << 63)}, _Signed128{1, 1 | (1ull << 63)}, ordtest::strong_ordering::less); assert((_Signed128{-2} == _Unsigned128{0ull - 2, ~0ull})); assert((_Unsigned128{_Signed128{-2}} == _Unsigned128{0ull - 2, ~0ull})); @@ -836,7 +842,7 @@ constexpr bool test_signed() { template T val() noexcept; -#if _HAS_CXX20 && !defined(__EDG__) // TRANSITION, GH-395 +#ifdef __cpp_lib_concepts // TRANSITION, GH-395 template concept CanConditional = requires { true ? val() : val(); @@ -847,7 +853,7 @@ constexpr bool CanConditional = false; template constexpr bool CanConditional() : val())>> = true; -#endif // _HAS_CXX20 && !defined(__EDG__) +#endif // __cpp_lib_concepts constexpr bool test_cross() { // Test the behavior of cross-type operations. @@ -900,13 +906,13 @@ constexpr bool test_cross() { STATIC_ASSERT(!CanConditional<_Unsigned128, _Signed128>); STATIC_ASSERT(!CanConditional<_Signed128, _Unsigned128>); -#if _HAS_CXX20 && !defined(__EDG__) // TRANSITION, GH-395 +#ifdef __cpp_lib_concepts // TRANSITION, GH-395 // Conversions between integer-class types with the same width and differing // signedness are narrowing, so the three-way comparison operator should // reject mixed operands of such types. STATIC_ASSERT(!std::three_way_comparable_with<_Unsigned128, _Signed128>); STATIC_ASSERT(!std::three_way_comparable_with<_Signed128, _Unsigned128>); -#endif // _HAS_CXX20 && !defined(__EDG__) +#endif // __cpp_lib_concepts // Other comparison operators behave as they do for operands of mixed // integral types; when the operands have the same width, the signed operand From c5bfa9bd842a095b90322fdef762a0b2a4b3afd1 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Mon, 29 Aug 2022 18:23:22 -0700 Subject: [PATCH 11/25] Consistent preprocessor comments. --- stl/inc/__msvc_int128.hpp | 48 +++++++++---------- .../tests/P1522R1_difference_type/test.cpp | 12 ++--- 2 files changed, 30 insertions(+), 30 deletions(-) diff --git a/stl/inc/__msvc_int128.hpp b/stl/inc/__msvc_int128.hpp index ebca32db669..ec3380e8f6a 100644 --- a/stl/inc/__msvc_int128.hpp +++ b/stl/inc/__msvc_int128.hpp @@ -18,17 +18,17 @@ #include #include #define _ZERO_OR_NO_INIT -#else // ^^^ _HAS_CXX20 / vvv !_HAS_CXX20 +#else // ^^^ _HAS_CXX20 / !_HAS_CXX20 vvv #define _ZERO_OR_NO_INIT \ {} // Trivial default initialization is not allowed in constexpr functions before C++20. -#endif // _HAS_CXX20 +#endif // ^^^ !_HAS_CXX20 ^^^ #ifdef __cpp_lib_concepts #include #define _TEMPLATE_CLASS_INTEGRAL(type) template -#else +#else // ^^^ defined(__cpp_lib_concepts) / !defined(__cpp_lib_concepts) vvv #define _TEMPLATE_CLASS_INTEGRAL(type) template , int> = 0> -#endif // __cpp_lib_concepts +#endif // ^^^ !defined(__cpp_lib_concepts) ^^^ #pragma pack(push, _CRT_PACKING) #pragma warning(push, _STL_WARNING_LEVEL) @@ -249,9 +249,9 @@ struct #if _HAS_CXX20 const auto __d = _STD countl_zero(static_cast(_Div >> 32)); -#else // ^^^ _HAS_CXX20 / vvv !_HAS_CXX20 +#else // ^^^ _HAS_CXX20 / !_HAS_CXX20 vvv const auto __d = _Countl_zero_fallback(static_cast(_Div >> 32)); -#endif // _HAS_CXX20 +#endif // ^^^ !_HAS_CXX20 ^^^ if (__d >= 32) { // _Div < 2^32 auto _Rem = (_High << 32) | (_Low >> 32); auto _Result = _Rem / static_cast(_Div); @@ -318,7 +318,7 @@ struct #if _HAS_CXX20 _NODISCARD_FRIEND constexpr bool operator==(const _Base128&, const _Base128&) noexcept = default; -#else // ^^^ _HAS_CXX20 / vvv !_HAS_CXX20 +#else // ^^^ _HAS_CXX20 / !_HAS_CXX20 vvv _NODISCARD_FRIEND constexpr bool operator==(const _Base128& _Left, const _Base128& _Right) noexcept { return _Left._Word[0] == _Right._Word[0] && _Left._Word[1] == _Right._Word[1]; } @@ -326,7 +326,7 @@ struct _NODISCARD_FRIEND constexpr bool operator!=(const _Base128& _Left, const _Base128& _Right) noexcept { return !(_Left == _Right); } -#endif +#endif // ^^^ !_HAS_CXX20 ^^^ _NODISCARD_FRIEND constexpr bool operator<(const _Base128& _Left, const _Base128& _Right) noexcept { if (_Left._Word[1] < _Right._Word[1]) { @@ -461,9 +461,9 @@ struct // Normalize by shifting both left until _Den's high bit is set (So _Den's high digit is >= b / 2) #if _HAS_CXX20 const auto __d = _STD countl_zero(_Den._Word[1]); -#else // ^^^ _HAS_CXX20 / vvv !_HAS_CXX20 +#else // ^^^ _HAS_CXX20 / !_HAS_CXX20 vvv const auto __d = _Countl_zero_fallback(_Den._Word[1]); -#endif // _HAS_CXX20 +#endif // ^^^ !_HAS_CXX20 ^^^ _Den <<= __d; auto _High_digit = __d == 0 ? 0 : _Num._Word[1] >> (64 - __d); // This creates a third digit for _Num _Num <<= __d; @@ -510,9 +510,9 @@ struct #else // ^^^ 128-bit intrinsics / no such intrinsics vvv #if _HAS_CXX20 auto __d = _STD countl_zero(_Den._Word[1]); -#else // ^^^ _HAS_CXX20 / vvv !_HAS_CXX20 +#else // ^^^ _HAS_CXX20 / !_HAS_CXX20 vvv auto __d = _Countl_zero_fallback(_Den._Word[1]); -#endif // _HAS_CXX20 +#endif // ^^^ !_HAS_CXX20 ^^^ const bool _Three_word_den = __d >= 32; __d &= 31; uint32_t __u[5]{ @@ -594,9 +594,9 @@ struct // Normalize by shifting both left until _Den's high bit is set (So _Den's high digit is >= b / 2) #if _HAS_CXX20 const auto __d = _STD countl_zero(_Den._Word[1]); -#else // ^^^ _HAS_CXX20 / vvv !_HAS_CXX20 +#else // ^^^ _HAS_CXX20 / !_HAS_CXX20 vvv const auto __d = _Countl_zero_fallback(_Den._Word[1]); -#endif // _HAS_CXX20 +#endif // ^^^ !_HAS_CXX20 ^^^ _Den <<= __d; auto _High_digit = __d == 0 ? 0 : _Num._Word[1] >> (64 - __d); // This creates a third digit for _Num _Num <<= __d; @@ -645,9 +645,9 @@ struct #else // ^^^ 128-bit intrinsics / no such intrinsics vvv #if _HAS_CXX20 auto __d = _STD countl_zero(_Den._Word[1]); -#else // ^^^ _HAS_CXX20 / vvv !_HAS_CXX20 +#else // ^^^ _HAS_CXX20 / !_HAS_CXX20 vvv auto __d = _Countl_zero_fallback(_Den._Word[1]); -#endif // _HAS_CXX20 +#endif // ^^^ !_HAS_CXX20 ^^^ const bool _Three_word_den = __d >= 32; __d &= 31; uint32_t __u[5]{ @@ -733,7 +733,7 @@ struct _Unsigned128 : _Base128 { } return _Ord; } -#else // ^^^ _HAS_CXX20 / vvv !_HAS_CXX20 +#else // ^^^ _HAS_CXX20 / !_HAS_CXX20 vvv _NODISCARD_FRIEND constexpr bool operator<(const _Unsigned128& _Left, const _Unsigned128& _Right) noexcept { if (_Left._Word[1] < _Right._Word[1]) return true; @@ -753,7 +753,7 @@ struct _Unsigned128 : _Base128 { _NODISCARD_FRIEND constexpr bool operator>=(const _Unsigned128& _Left, const _Unsigned128& _Right) noexcept { return !(_Left < _Right); } -#endif // _HAS_CXX20 +#endif // ^^^ !_HAS_CXX20 ^^^ _NODISCARD_FRIEND constexpr _Unsigned128 operator<<(const _Unsigned128& _Left, const _Base128& _Right) noexcept { auto _Tmp{_Left}; @@ -1030,12 +1030,12 @@ template struct common_type<_Unsigned128, _Ty> { using type = _Unsigned128; }; -#else // ^^^ defined(__cpp_lib_concepts) / vvv !defined(__cpp_lib_concepts) +#else // ^^^ defined(__cpp_lib_concepts) / !defined(__cpp_lib_concepts) vvv template struct common_type<_Ty, _Unsigned128> : enable_if, _Unsigned128> {}; template struct common_type<_Unsigned128, _Ty> : enable_if, _Unsigned128> {}; -#endif // __cpp_lib_concepts +#endif // ^^^ !defined(__cpp_lib_concepts) ^^^ struct _Signed128 : _Base128 { using _Signed_type = _Signed128; @@ -1062,7 +1062,7 @@ struct _Signed128 : _Base128 { } return _Ord; } -#else // ^^^ _HAS_CXX20 / vvv !_HAS_CXX20 +#else // ^^^ _HAS_CXX20 / !_HAS_CXX20 vvv _NODISCARD_FRIEND constexpr bool operator<(const _Signed128& _Left, const _Signed128& _Right) noexcept { if (static_cast(_Left._Word[1]) < static_cast(_Right._Word[1])) return true; @@ -1082,7 +1082,7 @@ struct _Signed128 : _Base128 { _NODISCARD_FRIEND constexpr bool operator>=(const _Signed128& _Left, const _Signed128& _Right) noexcept { return !(_Left < _Right); } -#endif // _HAS_CXX20 +#endif // ^^^ !_HAS_CXX20 ^^^ _NODISCARD_FRIEND constexpr _Signed128 operator<<(const _Signed128& _Left, const _Base128& _Right) noexcept { auto _Tmp{_Left}; @@ -1427,12 +1427,12 @@ template struct common_type<_Signed128, _Ty> { using type = _Signed128; }; -#else // ^^^ defined(__cpp_lib_concepts) / vvv !defined(__cpp_lib_concepts) +#else // ^^^ defined(__cpp_lib_concepts) / !defined(__cpp_lib_concepts) vvv template struct common_type<_Ty, _Signed128> : enable_if, _Signed128> {}; template struct common_type<_Signed128, _Ty> : enable_if, _Signed128> {}; -#endif // __cpp_lib_concepts +#endif // ^^^ !defined(__cpp_lib_concepts) ^^^ template <> struct common_type<_Signed128, _Unsigned128> { diff --git a/tests/std/tests/P1522R1_difference_type/test.cpp b/tests/std/tests/P1522R1_difference_type/test.cpp index 87f1d5f322a..392470c487f 100644 --- a/tests/std/tests/P1522R1_difference_type/test.cpp +++ b/tests/std/tests/P1522R1_difference_type/test.cpp @@ -14,7 +14,7 @@ namespace ordtest { using std::strong_ordering; } -#else // ^^^ _HAS_CXX20 / vvv !_HAS_CXX20 +#else // ^^^ _HAS_CXX20 / !_HAS_CXX20 vvv namespace ordtest { enum class strong_ordering : signed char { less = -1, @@ -23,15 +23,15 @@ namespace ordtest { greater = 1, }; } -#endif // _HAS_CXX20 +#endif // ^^^ !_HAS_CXX20 ^^^ #ifdef __cpp_lib_concepts // TRANSITION, GH-395 #include #define SAME_AS std::same_as -#else // ^^^ has concepts / vvv has no concepts +#else // ^^^ has concepts / has no concepts vvv #define SAME_AS std::is_same_v -#endif // __cpp_lib_concepts +#endif // ^^^ has no concepts ^^^ #define STATIC_ASSERT(...) static_assert(__VA_ARGS__, #__VA_ARGS__) @@ -847,13 +847,13 @@ template concept CanConditional = requires { true ? val() : val(); }; -#else // ^^^ has concepts / vvv has no concepts +#else // ^^^ has concepts / has no concepts vvv template constexpr bool CanConditional = false; template constexpr bool CanConditional() : val())>> = true; -#endif // __cpp_lib_concepts +#endif // ^^^ has no concepts ^^^ constexpr bool test_cross() { // Test the behavior of cross-type operations. From 71596b7a9b1caab8aac161c801e5ed4acbbcb3af Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Mon, 29 Aug 2022 18:33:38 -0700 Subject: [PATCH 12/25] Always use braces for control flow. --- stl/inc/__msvc_int128.hpp | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/stl/inc/__msvc_int128.hpp b/stl/inc/__msvc_int128.hpp index ec3380e8f6a..c78b9920483 100644 --- a/stl/inc/__msvc_int128.hpp +++ b/stl/inc/__msvc_int128.hpp @@ -735,10 +735,14 @@ struct _Unsigned128 : _Base128 { } #else // ^^^ _HAS_CXX20 / !_HAS_CXX20 vvv _NODISCARD_FRIEND constexpr bool operator<(const _Unsigned128& _Left, const _Unsigned128& _Right) noexcept { - if (_Left._Word[1] < _Right._Word[1]) + if (_Left._Word[1] < _Right._Word[1]) { return true; - if (_Right._Word[1] < _Left._Word[1]) + } + + if (_Right._Word[1] < _Left._Word[1]) { return false; + } + return _Left._Word[0] < _Right._Word[0]; } @@ -1064,10 +1068,14 @@ struct _Signed128 : _Base128 { } #else // ^^^ _HAS_CXX20 / !_HAS_CXX20 vvv _NODISCARD_FRIEND constexpr bool operator<(const _Signed128& _Left, const _Signed128& _Right) noexcept { - if (static_cast(_Left._Word[1]) < static_cast(_Right._Word[1])) + if (static_cast(_Left._Word[1]) < static_cast(_Right._Word[1])) { return true; - if (static_cast(_Right._Word[1]) < static_cast(_Left._Word[1])) + } + + if (static_cast(_Right._Word[1]) < static_cast(_Left._Word[1])) { return false; + } + return _Left._Word[0] < _Right._Word[0]; } @@ -1458,12 +1466,18 @@ inline namespace literals { }; _CONSTEVAL unsigned int _Char_to_digit(const char _Ch) noexcept { - if (_Ch >= '0' && _Ch <= '9') + if (_Ch >= '0' && _Ch <= '9') { return static_cast(_Ch - '0'); - if (_Ch >= 'A' && _Ch <= 'F') + } + + if (_Ch >= 'A' && _Ch <= 'F') { return static_cast(_Ch - 'A' + 10); - if (_Ch >= 'a' && _Ch <= 'f') + } + + if (_Ch >= 'a' && _Ch <= 'f') { return static_cast(_Ch - 'a' + 10); + } + return static_cast(-1); } From 6111252e97aab4db48dfb563745065c8cba8918f Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Mon, 29 Aug 2022 19:04:03 -0700 Subject: [PATCH 13/25] Already constrained for is_integral_v. --- stl/inc/__msvc_int128.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stl/inc/__msvc_int128.hpp b/stl/inc/__msvc_int128.hpp index c78b9920483..6b237599aa2 100644 --- a/stl/inc/__msvc_int128.hpp +++ b/stl/inc/__msvc_int128.hpp @@ -296,7 +296,7 @@ struct #ifdef __cpp_lib_concepts if constexpr (signed_integral<_Ty>) #else - if constexpr (is_integral_v<_Ty> && is_signed_v<_Ty>) + if constexpr (is_signed_v<_Ty>) #endif { if (_Val < 0) { From 492607d2e323679d0b6a5f60b7b80d453fef01d2 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Mon, 29 Aug 2022 19:04:46 -0700 Subject: [PATCH 14/25] Don't need to qualify numeric_limits. --- stl/inc/__msvc_int128.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stl/inc/__msvc_int128.hpp b/stl/inc/__msvc_int128.hpp index 6b237599aa2..b074f74ee7f 100644 --- a/stl/inc/__msvc_int128.hpp +++ b/stl/inc/__msvc_int128.hpp @@ -1487,7 +1487,7 @@ inline namespace literals { return {_U128_parse_status::_Valid, 0}; } else { constexpr char _Char_seq[]{_Chars...}; - constexpr auto _U128_max = (_STD numeric_limits<_Unsigned128>::max)(); + constexpr auto _U128_max = (numeric_limits<_Unsigned128>::max)(); _Unsigned128 _Val{}; for (const char _Ch : _Char_seq) { From a08e07af3fb784341ca0b634ce71303257919a0e Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Mon, 29 Aug 2022 19:05:07 -0700 Subject: [PATCH 15/25] Rename to _Int128_detail. --- stl/inc/__msvc_int128.hpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/stl/inc/__msvc_int128.hpp b/stl/inc/__msvc_int128.hpp index b074f74ee7f..80be8107fa2 100644 --- a/stl/inc/__msvc_int128.hpp +++ b/stl/inc/__msvc_int128.hpp @@ -1453,7 +1453,7 @@ struct common_type<_Unsigned128, _Signed128> { inline namespace literals { inline namespace _Int128_literals { - namespace _Detail { + namespace _Int128_detail { enum class _U128_parse_status : unsigned char { _Valid, _Overflow, @@ -1530,24 +1530,24 @@ inline namespace literals { template _INLINE_VAR constexpr _U128_parse_result _Parsed_u128<'0', _Chars...> = _Parse_u128_impl<8, _Chars...>(); - } // namespace _Detail + } // namespace _Int128_detail template _CONSTEVAL _Unsigned128 operator"" __u128() noexcept { - constexpr const auto& _Parsed_result = _Detail::_Parsed_u128<_Chars...>; - static_assert(_Parsed_result._Status_code != _Detail::_U128_parse_status::_Invalid, + constexpr const auto& _Parsed_result = _Int128_detail::_Parsed_u128<_Chars...>; + static_assert(_Parsed_result._Status_code != _Int128_detail::_U128_parse_status::_Invalid, "Invalid characters in the integer literal"); - static_assert(_Parsed_result._Status_code != _Detail::_U128_parse_status::_Overflow, + static_assert(_Parsed_result._Status_code != _Int128_detail::_U128_parse_status::_Overflow, "The integer literal is too large for an unsigned 128-bit number"); return _Parsed_result._Value; } template _CONSTEVAL _Signed128 operator"" __i128() noexcept { - constexpr const auto& _Parsed_result = _Detail::_Parsed_u128<_Chars...>; - static_assert(_Parsed_result._Status_code != _Detail::_U128_parse_status::_Invalid, + constexpr const auto& _Parsed_result = _Int128_detail::_Parsed_u128<_Chars...>; + static_assert(_Parsed_result._Status_code != _Int128_detail::_U128_parse_status::_Invalid, "Invalid characters in the integer literal"); - static_assert(_Parsed_result._Status_code != _Detail::_U128_parse_status::_Overflow + static_assert(_Parsed_result._Status_code != _Int128_detail::_U128_parse_status::_Overflow && _Parsed_result._Value._Word[1] < (static_cast(1) << 63), "The integer literal is too large for a signed 128-bit number"); return static_cast<_Signed128>(_Parsed_result._Value); From 1a4026bea323acc881d86cfd9de3ca9bd04b4264 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Mon, 29 Aug 2022 19:14:09 -0700 Subject: [PATCH 16/25] Add newline between non-chained if-statements. --- stl/inc/__msvc_int128.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/stl/inc/__msvc_int128.hpp b/stl/inc/__msvc_int128.hpp index 80be8107fa2..37d4216a3ca 100644 --- a/stl/inc/__msvc_int128.hpp +++ b/stl/inc/__msvc_int128.hpp @@ -1499,6 +1499,7 @@ inline namespace literals { if (_Digit == static_cast(-1)) { return {_U128_parse_status::_Invalid, _Unsigned128{}}; } + if ((_Val > _U128_max / _Base) || (_Base * _Val > _U128_max - _Digit)) { return {_U128_parse_status::_Overflow, _Unsigned128{}}; } From 3b69a3eb189cbb500ec4682ef16f1fa88531f5e1 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Mon, 29 Aug 2022 19:16:00 -0700 Subject: [PATCH 17/25] Unnecessary parentheses. --- stl/inc/__msvc_int128.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stl/inc/__msvc_int128.hpp b/stl/inc/__msvc_int128.hpp index 37d4216a3ca..6064d1e0cfe 100644 --- a/stl/inc/__msvc_int128.hpp +++ b/stl/inc/__msvc_int128.hpp @@ -1500,7 +1500,7 @@ inline namespace literals { return {_U128_parse_status::_Invalid, _Unsigned128{}}; } - if ((_Val > _U128_max / _Base) || (_Base * _Val > _U128_max - _Digit)) { + if (_Val > _U128_max / _Base || _Base * _Val > _U128_max - _Digit) { return {_U128_parse_status::_Overflow, _Unsigned128{}}; } From 53d13a9f81a95d5da6ebffcc385c4bf329dcfbc7 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Mon, 29 Aug 2022 19:21:11 -0700 Subject: [PATCH 18/25] _NODISCARD UDLs. --- stl/inc/__msvc_int128.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/stl/inc/__msvc_int128.hpp b/stl/inc/__msvc_int128.hpp index 6064d1e0cfe..951357a6a04 100644 --- a/stl/inc/__msvc_int128.hpp +++ b/stl/inc/__msvc_int128.hpp @@ -1534,7 +1534,7 @@ inline namespace literals { } // namespace _Int128_detail template - _CONSTEVAL _Unsigned128 operator"" __u128() noexcept { + _NODISCARD _CONSTEVAL _Unsigned128 operator"" __u128() noexcept { constexpr const auto& _Parsed_result = _Int128_detail::_Parsed_u128<_Chars...>; static_assert(_Parsed_result._Status_code != _Int128_detail::_U128_parse_status::_Invalid, "Invalid characters in the integer literal"); @@ -1544,7 +1544,7 @@ inline namespace literals { } template - _CONSTEVAL _Signed128 operator"" __i128() noexcept { + _NODISCARD _CONSTEVAL _Signed128 operator"" __i128() noexcept { constexpr const auto& _Parsed_result = _Int128_detail::_Parsed_u128<_Chars...>; static_assert(_Parsed_result._Status_code != _Int128_detail::_U128_parse_status::_Invalid, "Invalid characters in the integer literal"); From 65309f6dd84486c61f22603c5c417eed95c0d7b2 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Mon, 29 Aug 2022 19:24:15 -0700 Subject: [PATCH 19/25] _NODISCARD helper functions. --- stl/inc/__msvc_int128.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/stl/inc/__msvc_int128.hpp b/stl/inc/__msvc_int128.hpp index 951357a6a04..222524e0c4b 100644 --- a/stl/inc/__msvc_int128.hpp +++ b/stl/inc/__msvc_int128.hpp @@ -1465,7 +1465,7 @@ inline namespace literals { _Unsigned128 _Value; }; - _CONSTEVAL unsigned int _Char_to_digit(const char _Ch) noexcept { + _NODISCARD _CONSTEVAL unsigned int _Char_to_digit(const char _Ch) noexcept { if (_Ch >= '0' && _Ch <= '9') { return static_cast(_Ch - '0'); } @@ -1482,7 +1482,7 @@ inline namespace literals { } template - _CONSTEVAL _U128_parse_result _Parse_u128_impl() noexcept { + _NODISCARD _CONSTEVAL _U128_parse_result _Parse_u128_impl() noexcept { if constexpr (sizeof...(_Chars) == 0) { return {_U128_parse_status::_Valid, 0}; } else { From eab9cdf7217fb94594caab5db2867a90ef0db060 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Mon, 29 Aug 2022 19:54:12 -0700 Subject: [PATCH 20/25] Test capital 0B. --- tests/std/tests/P1522R1_difference_type/test.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tests/std/tests/P1522R1_difference_type/test.cpp b/tests/std/tests/P1522R1_difference_type/test.cpp index 392470c487f..3eac0bcf482 100644 --- a/tests/std/tests/P1522R1_difference_type/test.cpp +++ b/tests/std/tests/P1522R1_difference_type/test.cpp @@ -369,6 +369,8 @@ constexpr bool test_unsigned() { STATIC_ASSERT(noexcept(0x2'A__u128)); STATIC_ASSERT(noexcept(0b101010__u128)); STATIC_ASSERT(noexcept(0b1'0101'0__u128)); + STATIC_ASSERT(noexcept(0B101010__u128)); + STATIC_ASSERT(noexcept(0B1'0101'0__u128)); STATIC_ASSERT(noexcept(340282366920938463463374607431768211455__u128)); STATIC_ASSERT(noexcept(0xffffffff'FFFFFFFF'ffffFFFF'FFFFffff__u128)); @@ -380,6 +382,8 @@ constexpr bool test_unsigned() { STATIC_ASSERT(4'2__u128 == 0X2a__u128); STATIC_ASSERT(42__u128 == 0b101010__u128); STATIC_ASSERT(4'2__u128 == 0b101010__u128); + STATIC_ASSERT(42__u128 == 0B101010__u128); + STATIC_ASSERT(4'2__u128 == 0B101010__u128); STATIC_ASSERT( 340'2823'6692'0938'4634'6337'4607'4317'6821'1455__u128 == 0xffffffff'FFFFFFFF'ffffFFFF'FFFFffff__u128); @@ -813,6 +817,8 @@ constexpr bool test_signed() { STATIC_ASSERT(noexcept(0x2'A__i128)); STATIC_ASSERT(noexcept(0b101010__i128)); STATIC_ASSERT(noexcept(0b1'0101'0__i128)); + STATIC_ASSERT(noexcept(0B101010__i128)); + STATIC_ASSERT(noexcept(0B1'0101'0__i128)); STATIC_ASSERT(noexcept(170141183460469231731687303715884105727__i128)); STATIC_ASSERT(noexcept(0x7fffffff'FFFFFFFF'ffffFFFF'FFFFffff__i128)); @@ -824,6 +830,8 @@ constexpr bool test_signed() { STATIC_ASSERT(4'2__i128 == 0X2a__i128); STATIC_ASSERT(42__i128 == 0b101010__i128); STATIC_ASSERT(4'2__i128 == 0b101010__i128); + STATIC_ASSERT(42__i128 == 0B101010__i128); + STATIC_ASSERT(4'2__i128 == 0B101010__i128); STATIC_ASSERT( 170'1411'8346'0469'2317'3168'7303'7158'8410'5727__i128 == 0x7fffffff'FFFFFFFF'ffffFFFF'FFFFffff__i128); From bd95142a005257cb52653f4296e10c59f947a58b Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Mon, 29 Aug 2022 19:58:11 -0700 Subject: [PATCH 21/25] Test capital hexits. --- tests/std/tests/P1522R1_difference_type/test.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/std/tests/P1522R1_difference_type/test.cpp b/tests/std/tests/P1522R1_difference_type/test.cpp index 3eac0bcf482..513797a1291 100644 --- a/tests/std/tests/P1522R1_difference_type/test.cpp +++ b/tests/std/tests/P1522R1_difference_type/test.cpp @@ -371,6 +371,7 @@ constexpr bool test_unsigned() { STATIC_ASSERT(noexcept(0b1'0101'0__u128)); STATIC_ASSERT(noexcept(0B101010__u128)); STATIC_ASSERT(noexcept(0B1'0101'0__u128)); + STATIC_ASSERT(noexcept(0xABCDEF__u128)); STATIC_ASSERT(noexcept(340282366920938463463374607431768211455__u128)); STATIC_ASSERT(noexcept(0xffffffff'FFFFFFFF'ffffFFFF'FFFFffff__u128)); @@ -384,6 +385,7 @@ constexpr bool test_unsigned() { STATIC_ASSERT(4'2__u128 == 0b101010__u128); STATIC_ASSERT(42__u128 == 0B101010__u128); STATIC_ASSERT(4'2__u128 == 0B101010__u128); + STATIC_ASSERT(11259375__u128 == 0xABCDEF__u128); STATIC_ASSERT( 340'2823'6692'0938'4634'6337'4607'4317'6821'1455__u128 == 0xffffffff'FFFFFFFF'ffffFFFF'FFFFffff__u128); @@ -819,6 +821,7 @@ constexpr bool test_signed() { STATIC_ASSERT(noexcept(0b1'0101'0__i128)); STATIC_ASSERT(noexcept(0B101010__i128)); STATIC_ASSERT(noexcept(0B1'0101'0__i128)); + STATIC_ASSERT(noexcept(0xABCDEF__i128)); STATIC_ASSERT(noexcept(170141183460469231731687303715884105727__i128)); STATIC_ASSERT(noexcept(0x7fffffff'FFFFFFFF'ffffFFFF'FFFFffff__i128)); @@ -832,6 +835,7 @@ constexpr bool test_signed() { STATIC_ASSERT(4'2__i128 == 0b101010__i128); STATIC_ASSERT(42__i128 == 0B101010__i128); STATIC_ASSERT(4'2__i128 == 0B101010__i128); + STATIC_ASSERT(11259375__i128 == 0xABCDEF__i128); STATIC_ASSERT( 170'1411'8346'0469'2317'3168'7303'7158'8410'5727__i128 == 0x7fffffff'FFFFFFFF'ffffFFFF'FFFFffff__i128); From dc2a92eef2ece85f0d8598c91d190e259b56c4aa Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Tue, 30 Aug 2022 20:12:20 -0700 Subject: [PATCH 22/25] Add two more occurrences of _ZERO_OR_NO_INIT. --- stl/inc/__msvc_int128.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/stl/inc/__msvc_int128.hpp b/stl/inc/__msvc_int128.hpp index 222524e0c4b..274357fc813 100644 --- a/stl/inc/__msvc_int128.hpp +++ b/stl/inc/__msvc_int128.hpp @@ -534,7 +534,7 @@ struct __v[2] |= _Den._Word[0] >> (64 - __d); } - uint32_t __q[2]; + uint32_t __q[2] _ZERO_OR_NO_INIT; if (_Three_word_den) { // 4-digit by 3-digit base 2^32 division _Knuth_4_3_1_D(__u, 5, __v, 3, __q); @@ -669,7 +669,7 @@ struct __v[2] |= _Den._Word[0] >> (64 - __d); } - uint32_t __q[2]; + uint32_t __q[2] _ZERO_OR_NO_INIT; if (_Three_word_den) { // 4-digit by 3-digit base 2^32 division _Knuth_4_3_1_D(__u, 5, __v, 3, __q); From badc4a3ef4f065ae213c5532fc583271f936d6d2 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Tue, 30 Aug 2022 21:07:16 -0700 Subject: [PATCH 23/25] Avoid variable templates for /clr:pure. --- stl/inc/__msvc_int128.hpp | 70 +++++++++++++++++++-------------------- 1 file changed, 34 insertions(+), 36 deletions(-) diff --git a/stl/inc/__msvc_int128.hpp b/stl/inc/__msvc_int128.hpp index 274357fc813..5a011caccb9 100644 --- a/stl/inc/__msvc_int128.hpp +++ b/stl/inc/__msvc_int128.hpp @@ -1482,60 +1482,58 @@ inline namespace literals { } template - _NODISCARD _CONSTEVAL _U128_parse_result _Parse_u128_impl() noexcept { - if constexpr (sizeof...(_Chars) == 0) { - return {_U128_parse_status::_Valid, 0}; - } else { - constexpr char _Char_seq[]{_Chars...}; - constexpr auto _U128_max = (numeric_limits<_Unsigned128>::max)(); - - _Unsigned128 _Val{}; - for (const char _Ch : _Char_seq) { - if (_Ch == '\'') { - continue; + struct _Parse_u128_impl { + _NODISCARD static _CONSTEVAL _U128_parse_result _Parse() noexcept { + if constexpr (sizeof...(_Chars) == 0) { + return {_U128_parse_status::_Valid, 0}; + } else { + constexpr char _Char_seq[]{_Chars...}; + constexpr auto _U128_max = (numeric_limits<_Unsigned128>::max)(); + + _Unsigned128 _Val{}; + for (const char _Ch : _Char_seq) { + if (_Ch == '\'') { + continue; + } + + const unsigned int _Digit = _Char_to_digit(_Ch); + if (_Digit == static_cast(-1)) { + return {_U128_parse_status::_Invalid, _Unsigned128{}}; + } + + if (_Val > _U128_max / _Base || _Base * _Val > _U128_max - _Digit) { + return {_U128_parse_status::_Overflow, _Unsigned128{}}; + } + + _Val = _Base * _Val + _Digit; } - - const unsigned int _Digit = _Char_to_digit(_Ch); - if (_Digit == static_cast(-1)) { - return {_U128_parse_status::_Invalid, _Unsigned128{}}; - } - - if (_Val > _U128_max / _Base || _Base * _Val > _U128_max - _Digit) { - return {_U128_parse_status::_Overflow, _Unsigned128{}}; - } - - _Val = _Base * _Val + _Digit; + return {_U128_parse_status::_Valid, _Val}; } - return {_U128_parse_status::_Valid, _Val}; } - } + }; template - _INLINE_VAR constexpr _U128_parse_result _Parsed_u128 = _Parse_u128_impl<10, _Chars...>(); + struct _Parse_u128 : _Parse_u128_impl<10, _Chars...> {}; template - _INLINE_VAR constexpr _U128_parse_result - _Parsed_u128<'0', 'X', _Chars...> = _Parse_u128_impl<16, _Chars...>(); + struct _Parse_u128<'0', 'X', _Chars...> : _Parse_u128_impl<16, _Chars...> {}; template - _INLINE_VAR constexpr _U128_parse_result - _Parsed_u128<'0', 'x', _Chars...> = _Parse_u128_impl<16, _Chars...>(); + struct _Parse_u128<'0', 'x', _Chars...> : _Parse_u128_impl<16, _Chars...> {}; template - _INLINE_VAR constexpr _U128_parse_result - _Parsed_u128<'0', 'B', _Chars...> = _Parse_u128_impl<2, _Chars...>(); + struct _Parse_u128<'0', 'B', _Chars...> : _Parse_u128_impl<2, _Chars...> {}; template - _INLINE_VAR constexpr _U128_parse_result - _Parsed_u128<'0', 'b', _Chars...> = _Parse_u128_impl<2, _Chars...>(); + struct _Parse_u128<'0', 'b', _Chars...> : _Parse_u128_impl<2, _Chars...> {}; template - _INLINE_VAR constexpr _U128_parse_result _Parsed_u128<'0', _Chars...> = _Parse_u128_impl<8, _Chars...>(); + struct _Parse_u128<'0', _Chars...> : _Parse_u128_impl<8, _Chars...> {}; } // namespace _Int128_detail template _NODISCARD _CONSTEVAL _Unsigned128 operator"" __u128() noexcept { - constexpr const auto& _Parsed_result = _Int128_detail::_Parsed_u128<_Chars...>; + constexpr auto _Parsed_result = _Int128_detail::_Parse_u128<_Chars...>::_Parse(); static_assert(_Parsed_result._Status_code != _Int128_detail::_U128_parse_status::_Invalid, "Invalid characters in the integer literal"); static_assert(_Parsed_result._Status_code != _Int128_detail::_U128_parse_status::_Overflow, @@ -1545,7 +1543,7 @@ inline namespace literals { template _NODISCARD _CONSTEVAL _Signed128 operator"" __i128() noexcept { - constexpr const auto& _Parsed_result = _Int128_detail::_Parsed_u128<_Chars...>; + constexpr auto _Parsed_result = _Int128_detail::_Parse_u128<_Chars...>::_Parse(); static_assert(_Parsed_result._Status_code != _Int128_detail::_U128_parse_status::_Invalid, "Invalid characters in the integer literal"); static_assert(_Parsed_result._Status_code != _Int128_detail::_U128_parse_status::_Overflow From 0632cd9ba2d80379d1e1dd65f8882d35792ec722 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Wed, 31 Aug 2022 02:33:53 -0700 Subject: [PATCH 24/25] Avoid intrinsics for `/clr:pure`, CUDA, and Intel. --- stl/inc/__msvc_int128.hpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/stl/inc/__msvc_int128.hpp b/stl/inc/__msvc_int128.hpp index 5a011caccb9..bcb3b6e0cab 100644 --- a/stl/inc/__msvc_int128.hpp +++ b/stl/inc/__msvc_int128.hpp @@ -39,17 +39,18 @@ _STL_DISABLE_CLANG_WARNINGS _STD_BEGIN -#if defined(_M_X64) && !defined(_M_ARM64EC) +#if defined(_M_X64) && !defined(_M_ARM64EC) && !defined(_M_CEE_PURE) && !defined(__CUDACC__) \ + && !defined(__INTEL_COMPILER) #define _STL_128_INTRINSICS 1 #ifdef __clang__ // clang doesn't have _udiv128 / _div128 #define _STL_128_DIV_INTRINSICS 0 #else // ^^^ Clang / other vvv #define _STL_128_DIV_INTRINSICS 1 #endif // ^^^ detect _udiv128 / _div128 ^^^ -#else // ^^^ x64 / other vvv +#else // ^^^ intrinsics available / intrinsics unavailable vvv #define _STL_128_INTRINSICS 0 #define _STL_128_DIV_INTRINSICS 0 -#endif // defined(_M_X64) && !defined(_M_ARM64EC) +#endif // ^^^ intrinsics unavailable ^^^ struct #ifndef _M_ARM From 3bb65df6982480c3f16d1ea85e86b3e6a504ba46 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Wed, 31 Aug 2022 02:34:52 -0700 Subject: [PATCH 25/25] Work around `/clr` silent bad codegen. --- tests/std/tests/P1522R1_difference_type/test.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/std/tests/P1522R1_difference_type/test.cpp b/tests/std/tests/P1522R1_difference_type/test.cpp index 513797a1291..3a0cb740e2e 100644 --- a/tests/std/tests/P1522R1_difference_type/test.cpp +++ b/tests/std/tests/P1522R1_difference_type/test.cpp @@ -1152,7 +1152,11 @@ constexpr bool test_cross() { x = -26; TEST(u *= 2, x); y = 12; +#ifdef _M_CEE // TRANSITION, silent bad codegen, not yet reported + i = 12; +#else // ^^^ workaround / no workaround vvv TEST(i *= -2, y); +#endif // ^^^ no workaround ^^^ x = _Unsigned128{0x55555555'5555554c, 0x55555555'55555555}; TEST(u /= 3, x); // Yes, u is still unsigned =)