From 19b148c40b064afad86094e2e1537cb7458d5008 Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Fri, 29 Mar 2024 02:42:29 +0800 Subject: [PATCH 01/12] Complete additional overloads in `` Also partially implement P0533R9 for these overloads --- stl/inc/cmath | 82 +++++++++- tests/std/test.lst | 1 + .../GH_000519_cmath_int_overloads/env.lst | 4 + .../GH_000519_cmath_int_overloads/test.cpp | 142 ++++++++++++++++++ 4 files changed, 228 insertions(+), 1 deletion(-) create mode 100644 tests/std/tests/GH_000519_cmath_int_overloads/env.lst create mode 100644 tests/std/tests/GH_000519_cmath_int_overloads/test.cpp diff --git a/stl/inc/cmath b/stl/inc/cmath index 8bb994af15b..91b14053f01 100644 --- a/stl/inc/cmath +++ b/stl/inc/cmath @@ -594,6 +594,48 @@ _STD _Common_float_type_t<_Ty1, _Ty2> remquo(_Ty1 _Left, _Ty2 _Right, int* _Pquo } } +// TRANSITION, GH-519, should be provided by UCRT +template , int> = 0> +_Check_return_ _CONSTEXPR23 int fpclassify(_In_ const _Ty _Ix) noexcept /* strengthened */ { + return _Ix ? FP_NORMAL : FP_ZERO; +} + +// TRANSITION, GH-519, should be provided by UCRT +template , int> = 0> +_Check_return_ _CONSTEXPR23 bool signbit(_In_ const _Ty _Ix) noexcept /* strengthened */ { + if constexpr (static_cast<_Ty>(-1) < _Ty{}) { + return _Ix < 0; + } else { + return false; + } +} + +// TRANSITION, GH-519, additional overloads are not templated to avoid ambiguity with the major overload in UCRT +#define _GENERIC_MATH_ISNORMAL(TYPE) \ + _NODISCARD _Check_return_ _CONSTEXPR23 bool isnormal(_In_ const TYPE _Ix) noexcept /* strengthened */ { \ + return _Ix != 0; \ + } + +_GENERIC_MATH_ISNORMAL(signed char) +_GENERIC_MATH_ISNORMAL(unsigned char) +_GENERIC_MATH_ISNORMAL(short) +_GENERIC_MATH_ISNORMAL(unsigned short) +_GENERIC_MATH_ISNORMAL(int) +_GENERIC_MATH_ISNORMAL(unsigned int) +_GENERIC_MATH_ISNORMAL(long) +_GENERIC_MATH_ISNORMAL(unsigned long) +_GENERIC_MATH_ISNORMAL(long long) +_GENERIC_MATH_ISNORMAL(unsigned long long) +_GENERIC_MATH_ISNORMAL(bool) +_GENERIC_MATH_ISNORMAL(char) +#ifdef __cpp_char8_t +_GENERIC_MATH_ISNORMAL(char8_t) +#endif // defined(__cpp_char8_t) +_GENERIC_MATH_ISNORMAL(char16_t) +_GENERIC_MATH_ISNORMAL(char32_t) +_GENERIC_MATH_ISNORMAL(wchar_t) +#undef _GENERIC_MATH_ISNORMAL + #define _GENERIC_MATH1_BASE(NAME, RET, FUN) \ template , int> = 0> \ _NODISCARD RET NAME(_Ty _Left) noexcept /* strengthened */ { \ @@ -640,6 +682,36 @@ _STD _Common_float_type_t<_Ty1, _Ty2> remquo(_Ty1 _Left, _Ty2 _Right, int* _Pquo #define _GENERIC_MATH2I(FUN, CLANG_INTRIN, MSVC_INTRIN) _GENERIC_MATH2_BASE(FUN, _CSTD FUN) #endif // ^^^ intrinsics unavailable ^^^ +// TRANSITION, GH-519, additional overloads are not templated to avoid ambiguity with the major overload in UCRT +#define _GENERIC_MATH_CLASSIFY1_PER_TYPE_RETV(FUN, TYPE, RETV) \ + _NODISCARD _Check_return_ _CONSTEXPR23 bool FUN(_In_ TYPE) noexcept /* strengthened */ { \ + return RETV; \ + } + +#ifdef __cpp_char8_t +#define _GENERIC_MATH_CLASSIFY1_RETV_CHAR8_T(FUN, RETV) _GENERIC_MATH_CLASSIFY1_PER_TYPE_RETV(FUN, char8_t, RETV) +#else // ^^^ defined(__cpp_char8_t) / !defined(__cpp_char8_t) vvv +#define _GENERIC_MATH_CLASSIFY1_RETV_CHAR8_T(FUN, RETV) +#endif // ^^^ !defined(__cpp_char8_t) ^^^ + +#define _GENERIC_MATH_CLASSIFY1_RETV(FUN, RETV) \ + _GENERIC_MATH_CLASSIFY1_PER_TYPE_RETV(FUN, signed char, RETV) \ + _GENERIC_MATH_CLASSIFY1_PER_TYPE_RETV(FUN, unsigned char, RETV) \ + _GENERIC_MATH_CLASSIFY1_PER_TYPE_RETV(FUN, short, RETV) \ + _GENERIC_MATH_CLASSIFY1_PER_TYPE_RETV(FUN, unsigned short, RETV) \ + _GENERIC_MATH_CLASSIFY1_PER_TYPE_RETV(FUN, int, RETV) \ + _GENERIC_MATH_CLASSIFY1_PER_TYPE_RETV(FUN, unsigned int, RETV) \ + _GENERIC_MATH_CLASSIFY1_PER_TYPE_RETV(FUN, long, RETV) \ + _GENERIC_MATH_CLASSIFY1_PER_TYPE_RETV(FUN, unsigned long, RETV) \ + _GENERIC_MATH_CLASSIFY1_PER_TYPE_RETV(FUN, long long, RETV) \ + _GENERIC_MATH_CLASSIFY1_PER_TYPE_RETV(FUN, unsigned long long, RETV) \ + _GENERIC_MATH_CLASSIFY1_PER_TYPE_RETV(FUN, bool, RETV) \ + _GENERIC_MATH_CLASSIFY1_PER_TYPE_RETV(FUN, char, RETV) \ + _GENERIC_MATH_CLASSIFY1_RETV_CHAR8_T(FUN, RETV) \ + _GENERIC_MATH_CLASSIFY1_PER_TYPE_RETV(FUN, char16_t, RETV) \ + _GENERIC_MATH_CLASSIFY1_PER_TYPE_RETV(FUN, char32_t, RETV) \ + _GENERIC_MATH_CLASSIFY1_PER_TYPE_RETV(FUN, wchar_t, RETV) + // The following order matches N4950 [cmath.syn]. _GENERIC_MATH1(acos) _GENERIC_MATH1(asin) @@ -701,7 +773,12 @@ _GENERIC_MATH2(fmax) _GENERIC_MATH2(fmin) // fma() is hand-crafted // lerp() is hand-crafted -// The "classification/comparison functions" (fpclassify(), etc.) are exempt, LWG-1327 +// fpclassify() is hand-crafted +_GENERIC_MATH_CLASSIFY1_RETV(isfinite, true) +_GENERIC_MATH_CLASSIFY1_RETV(isinf, false) +_GENERIC_MATH_CLASSIFY1_RETV(isnan, false) +// isnormal() is half-hand-crafted +// signbit() is hand-crafted #undef _GENERIC_MATH1_BASE #undef _GENERIC_MATH1R @@ -711,6 +788,9 @@ _GENERIC_MATH2(fmin) #undef _GENERIC_MATH2_BASE #undef _GENERIC_MATH2 #undef _GENERIC_MATH2I +#undef _GENERIC_MATH_CLASSIFY1_PER_TYPE_RETV +#undef _GENERIC_MATH_CLASSIFY1_RETV_CHAR8_T +#undef _GENERIC_MATH_CLASSIFY1_RETV #undef _HAS_CMATH_INTRINSICS _END_EXTERN_CXX_WORKAROUND diff --git a/tests/std/test.lst b/tests/std/test.lst index cf8d9bf3ef1..a3ec79e1268 100644 --- a/tests/std/test.lst +++ b/tests/std/test.lst @@ -168,6 +168,7 @@ tests\GH_000431_lex_compare_family tests\GH_000431_lex_compare_memcmp_classify tests\GH_000442_random_subtract_with_carry_engine_io tests\GH_000457_system_error_message +tests\GH_000519_cmath_int_overloads tests\GH_000527_remove_allocator_void tests\GH_000545_include_compare tests\GH_000625_vector_bool_optimization diff --git a/tests/std/tests/GH_000519_cmath_int_overloads/env.lst b/tests/std/tests/GH_000519_cmath_int_overloads/env.lst new file mode 100644 index 00000000000..19f025bd0e6 --- /dev/null +++ b/tests/std/tests/GH_000519_cmath_int_overloads/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\usual_matrix.lst diff --git a/tests/std/tests/GH_000519_cmath_int_overloads/test.cpp b/tests/std/tests/GH_000519_cmath_int_overloads/test.cpp new file mode 100644 index 00000000000..02a9eb2e3c7 --- /dev/null +++ b/tests/std/tests/GH_000519_cmath_int_overloads/test.cpp @@ -0,0 +1,142 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include + +// Also test the partial implemention of P0533R9 "constexpr for cmath and cstdlib" +#if _HAS_CXX23 +#define CONSTEXPR23 constexpr +#else // ^^^ _HAS_CXX23 / !_HAS_CXX23 vvv +#define CONSTEXPR23 inline +#endif // ^^^ !_HAS_CXX23 ^^^ + +CONSTEXPR23 void test_bool_overloads() { + // test overloads in std + + assert(std::fpclassify(false) == FP_ZERO); + assert(std::fpclassify(true) == FP_NORMAL); + + assert(std::isfinite(false)); + assert(std::isfinite(true)); + + assert(!std::isnan(false)); + assert(!std::isnan(true)); + + assert(!std::isinf(false)); + assert(!std::isinf(true)); + + assert(!std::isnormal(false)); + assert(std::isnormal(true)); + + assert(!std::signbit(false)); + assert(!std::signbit(true)); + + // test overloads in the global namespace + + assert(fpclassify(false) == FP_ZERO); + assert(fpclassify(true) == FP_NORMAL); + + assert(isfinite(false)); + assert(isfinite(true)); + + assert(!isnan(false)); + assert(!isnan(true)); + + assert(!isinf(false)); + assert(!isinf(true)); + + assert(!isnormal(false)); + assert(isnormal(true)); + + assert(!signbit(false)); + assert(!signbit(true)); +} + +template +CONSTEXPR23 void test_other_integral_overloads() { + // test overloads in std + + assert(std::fpclassify(I{}) == FP_ZERO); + assert(std::fpclassify(static_cast(42)) == FP_NORMAL); + assert(std::fpclassify(static_cast(-42)) == FP_NORMAL); + + assert(std::isfinite(I{})); + assert(std::isfinite(static_cast(42))); + assert(std::isfinite(static_cast(-42))); + + assert(!std::isnan(I{})); + assert(!std::isnan(static_cast(42))); + assert(!std::isnan(static_cast(-42))); + + assert(!std::isinf(I{})); + assert(!std::isinf(static_cast(42))); + assert(!std::isinf(static_cast(-42))); + + assert(!std::isnormal(I{})); + assert(std::isnormal(static_cast(42))); + assert(std::isnormal(static_cast(-42))); + + assert(!std::signbit(I{})); + assert(!std::signbit(static_cast(42))); + assert(std::signbit(static_cast(-42)) == std::is_signed_v); + + // test overloads in the global namespace + + assert(fpclassify(I{}) == FP_ZERO); + assert(fpclassify(static_cast(42)) == FP_NORMAL); + assert(fpclassify(static_cast(-42)) == FP_NORMAL); + + assert(isfinite(I{})); + assert(isfinite(static_cast(42))); + assert(isfinite(static_cast(-42))); + + assert(!isnan(I{})); + assert(!isnan(static_cast(42))); + assert(!isnan(static_cast(-42))); + + assert(!isinf(I{})); + assert(!isinf(static_cast(42))); + assert(!isinf(static_cast(-42))); + + assert(!isnormal(I{})); + assert(isnormal(static_cast(42))); + assert(isnormal(static_cast(-42))); + + assert(!signbit(I{})); + assert(!signbit(static_cast(42))); + assert(signbit(static_cast(-42)) == std::is_signed_v); +} + +CONSTEXPR23 bool test_all_integral_overloads() { + test_bool_overloads(); + test_other_integral_overloads(); + test_other_integral_overloads(); + test_other_integral_overloads(); + test_other_integral_overloads(); + test_other_integral_overloads(); + test_other_integral_overloads(); + test_other_integral_overloads(); + test_other_integral_overloads(); + test_other_integral_overloads(); + test_other_integral_overloads(); + test_other_integral_overloads(); +#ifdef __cpp_char8_t + test_other_integral_overloads(); +#endif // defined(__cpp_char8_t) + test_other_integral_overloads(); + test_other_integral_overloads(); + test_other_integral_overloads(); + + return true; +} + +#if _HAS_CXX23 +static_assert(test_all_integral_overloads()); +#endif // _HAS_CXX23 + +int main() { + test_all_integral_overloads(); +} From 7025003a05f63e2c817aeb2b97c7b04c73468185 Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Fri, 29 Mar 2024 03:26:00 +0800 Subject: [PATCH 02/12] Handle `/Zc:wchar_t-` mode --- stl/inc/cmath | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/stl/inc/cmath b/stl/inc/cmath index 91b14053f01..ca402eee7e1 100644 --- a/stl/inc/cmath +++ b/stl/inc/cmath @@ -633,7 +633,9 @@ _GENERIC_MATH_ISNORMAL(char8_t) #endif // defined(__cpp_char8_t) _GENERIC_MATH_ISNORMAL(char16_t) _GENERIC_MATH_ISNORMAL(char32_t) +#ifdef _NATIVE_WCHAR_T_DEFINED _GENERIC_MATH_ISNORMAL(wchar_t) +#endif // #ifdef _NATIVE_WCHAR_T_DEFINED #undef _GENERIC_MATH_ISNORMAL #define _GENERIC_MATH1_BASE(NAME, RET, FUN) \ @@ -694,6 +696,12 @@ _GENERIC_MATH_ISNORMAL(wchar_t) #define _GENERIC_MATH_CLASSIFY1_RETV_CHAR8_T(FUN, RETV) #endif // ^^^ !defined(__cpp_char8_t) ^^^ +#ifdef _NATIVE_WCHAR_T_DEFINED +#define _GENERIC_MATH_CLASSIFY1_RETV_WCHAR_T(FUN, RETV) _GENERIC_MATH_CLASSIFY1_PER_TYPE_RETV(FUN, wchar_t, RETV) +#else // ^^^ defined(__cpp_char8_t) / !defined(__cpp_char8_t) vvv +#define _GENERIC_MATH_CLASSIFY1_RETV_WCHAR_T(FUN, RETV) +#endif // ^^^ !defined(_NATIVE_WCHAR_T_DEFINED) ^^^ + #define _GENERIC_MATH_CLASSIFY1_RETV(FUN, RETV) \ _GENERIC_MATH_CLASSIFY1_PER_TYPE_RETV(FUN, signed char, RETV) \ _GENERIC_MATH_CLASSIFY1_PER_TYPE_RETV(FUN, unsigned char, RETV) \ @@ -710,7 +718,7 @@ _GENERIC_MATH_ISNORMAL(wchar_t) _GENERIC_MATH_CLASSIFY1_RETV_CHAR8_T(FUN, RETV) \ _GENERIC_MATH_CLASSIFY1_PER_TYPE_RETV(FUN, char16_t, RETV) \ _GENERIC_MATH_CLASSIFY1_PER_TYPE_RETV(FUN, char32_t, RETV) \ - _GENERIC_MATH_CLASSIFY1_PER_TYPE_RETV(FUN, wchar_t, RETV) + _GENERIC_MATH_CLASSIFY1_RETV_WCHAR_T(FUN, RETV) // The following order matches N4950 [cmath.syn]. _GENERIC_MATH1(acos) From 93b1f5c64971ea41d8bc71b83a99b520e08b459b Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Fri, 29 Mar 2024 03:27:50 +0800 Subject: [PATCH 03/12] Unblock two libcxx tests - std/depr/depr.c.headers/math_h.pass.cpp - std/numerics/c.math/cmath.pass.cpp --- tests/libcxx/expected_results.txt | 4 ---- 1 file changed, 4 deletions(-) diff --git a/tests/libcxx/expected_results.txt b/tests/libcxx/expected_results.txt index ba26ae5bc1f..5211f2ab232 100644 --- a/tests/libcxx/expected_results.txt +++ b/tests/libcxx/expected_results.txt @@ -484,10 +484,6 @@ std/utilities/expected/expected.void/equality/equality.other_expected.pass.cpp:2 # *** STL BUGS *** -# GH-519 : signbit() misses overloads for integer types -std/depr/depr.c.headers/math_h.pass.cpp FAIL -std/numerics/c.math/cmath.pass.cpp FAIL - # GH-784 : aligned_storage has incorrect alignment defaults std/utilities/meta/meta.trans/meta.trans.other/aligned_storage.pass.cpp FAIL From 5eac5663957c5234462adcd39c42f9956d3f0794 Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Fri, 29 Mar 2024 03:30:35 +0800 Subject: [PATCH 04/12] Missed `#undef` --- stl/inc/cmath | 1 + 1 file changed, 1 insertion(+) diff --git a/stl/inc/cmath b/stl/inc/cmath index ca402eee7e1..2a21fe3c9b3 100644 --- a/stl/inc/cmath +++ b/stl/inc/cmath @@ -797,6 +797,7 @@ _GENERIC_MATH_CLASSIFY1_RETV(isnan, false) #undef _GENERIC_MATH2 #undef _GENERIC_MATH2I #undef _GENERIC_MATH_CLASSIFY1_PER_TYPE_RETV +#undef _GENERIC_MATH_CLASSIFY1_RETV_WCHAR_T #undef _GENERIC_MATH_CLASSIFY1_RETV_CHAR8_T #undef _GENERIC_MATH_CLASSIFY1_RETV #undef _HAS_CMATH_INTRINSICS From aebd17d8abbf2fad81e2b1b64930ae5ef3e5ac38 Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Fri, 29 Mar 2024 09:25:28 +0800 Subject: [PATCH 05/12] Fix comment for `_NATIVE_WCHAR_T_DEFINED` --- stl/inc/cmath | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stl/inc/cmath b/stl/inc/cmath index 2a21fe3c9b3..1a0eb7051db 100644 --- a/stl/inc/cmath +++ b/stl/inc/cmath @@ -635,7 +635,7 @@ _GENERIC_MATH_ISNORMAL(char16_t) _GENERIC_MATH_ISNORMAL(char32_t) #ifdef _NATIVE_WCHAR_T_DEFINED _GENERIC_MATH_ISNORMAL(wchar_t) -#endif // #ifdef _NATIVE_WCHAR_T_DEFINED +#endif // defined(_NATIVE_WCHAR_T_DEFINED) #undef _GENERIC_MATH_ISNORMAL #define _GENERIC_MATH1_BASE(NAME, RET, FUN) \ From ca6b251b85708639a69fdb37adc75542779cf535 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Mon, 8 Apr 2024 09:27:57 -0700 Subject: [PATCH 06/12] Fix comment typos and nitpicks. --- stl/inc/cmath | 2 +- tests/std/tests/GH_000519_cmath_int_overloads/test.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/stl/inc/cmath b/stl/inc/cmath index 1a0eb7051db..991149a4632 100644 --- a/stl/inc/cmath +++ b/stl/inc/cmath @@ -698,7 +698,7 @@ _GENERIC_MATH_ISNORMAL(wchar_t) #ifdef _NATIVE_WCHAR_T_DEFINED #define _GENERIC_MATH_CLASSIFY1_RETV_WCHAR_T(FUN, RETV) _GENERIC_MATH_CLASSIFY1_PER_TYPE_RETV(FUN, wchar_t, RETV) -#else // ^^^ defined(__cpp_char8_t) / !defined(__cpp_char8_t) vvv +#else // ^^^ defined(_NATIVE_WCHAR_T_DEFINED) / !defined(_NATIVE_WCHAR_T_DEFINED) vvv #define _GENERIC_MATH_CLASSIFY1_RETV_WCHAR_T(FUN, RETV) #endif // ^^^ !defined(_NATIVE_WCHAR_T_DEFINED) ^^^ diff --git a/tests/std/tests/GH_000519_cmath_int_overloads/test.cpp b/tests/std/tests/GH_000519_cmath_int_overloads/test.cpp index 02a9eb2e3c7..017c94675c3 100644 --- a/tests/std/tests/GH_000519_cmath_int_overloads/test.cpp +++ b/tests/std/tests/GH_000519_cmath_int_overloads/test.cpp @@ -6,7 +6,7 @@ #include #include -// Also test the partial implemention of P0533R9 "constexpr for cmath and cstdlib" +// Also test the partial implementation of P0533R9 "constexpr For And " #if _HAS_CXX23 #define CONSTEXPR23 constexpr #else // ^^^ _HAS_CXX23 / !_HAS_CXX23 vvv From 49974b85a6ddfca2c65379bee6a2a8fe64d443b8 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Mon, 8 Apr 2024 09:30:30 -0700 Subject: [PATCH 07/12] Add `::` global qualification. --- .../GH_000519_cmath_int_overloads/test.cpp | 60 +++++++++---------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/tests/std/tests/GH_000519_cmath_int_overloads/test.cpp b/tests/std/tests/GH_000519_cmath_int_overloads/test.cpp index 017c94675c3..9b9a69bd736 100644 --- a/tests/std/tests/GH_000519_cmath_int_overloads/test.cpp +++ b/tests/std/tests/GH_000519_cmath_int_overloads/test.cpp @@ -36,23 +36,23 @@ CONSTEXPR23 void test_bool_overloads() { // test overloads in the global namespace - assert(fpclassify(false) == FP_ZERO); - assert(fpclassify(true) == FP_NORMAL); + assert(::fpclassify(false) == FP_ZERO); + assert(::fpclassify(true) == FP_NORMAL); - assert(isfinite(false)); - assert(isfinite(true)); + assert(::isfinite(false)); + assert(::isfinite(true)); - assert(!isnan(false)); - assert(!isnan(true)); + assert(!::isnan(false)); + assert(!::isnan(true)); - assert(!isinf(false)); - assert(!isinf(true)); + assert(!::isinf(false)); + assert(!::isinf(true)); - assert(!isnormal(false)); - assert(isnormal(true)); + assert(!::isnormal(false)); + assert(::isnormal(true)); - assert(!signbit(false)); - assert(!signbit(true)); + assert(!::signbit(false)); + assert(!::signbit(true)); } template @@ -85,29 +85,29 @@ CONSTEXPR23 void test_other_integral_overloads() { // test overloads in the global namespace - assert(fpclassify(I{}) == FP_ZERO); - assert(fpclassify(static_cast(42)) == FP_NORMAL); - assert(fpclassify(static_cast(-42)) == FP_NORMAL); + assert(::fpclassify(I{}) == FP_ZERO); + assert(::fpclassify(static_cast(42)) == FP_NORMAL); + assert(::fpclassify(static_cast(-42)) == FP_NORMAL); - assert(isfinite(I{})); - assert(isfinite(static_cast(42))); - assert(isfinite(static_cast(-42))); + assert(::isfinite(I{})); + assert(::isfinite(static_cast(42))); + assert(::isfinite(static_cast(-42))); - assert(!isnan(I{})); - assert(!isnan(static_cast(42))); - assert(!isnan(static_cast(-42))); + assert(!::isnan(I{})); + assert(!::isnan(static_cast(42))); + assert(!::isnan(static_cast(-42))); - assert(!isinf(I{})); - assert(!isinf(static_cast(42))); - assert(!isinf(static_cast(-42))); + assert(!::isinf(I{})); + assert(!::isinf(static_cast(42))); + assert(!::isinf(static_cast(-42))); - assert(!isnormal(I{})); - assert(isnormal(static_cast(42))); - assert(isnormal(static_cast(-42))); + assert(!::isnormal(I{})); + assert(::isnormal(static_cast(42))); + assert(::isnormal(static_cast(-42))); - assert(!signbit(I{})); - assert(!signbit(static_cast(42))); - assert(signbit(static_cast(-42)) == std::is_signed_v); + assert(!::signbit(I{})); + assert(!::signbit(static_cast(42))); + assert(::signbit(static_cast(-42)) == std::is_signed_v); } CONSTEXPR23 bool test_all_integral_overloads() { From 876462045592cafddac5d464858ef28561aea62d Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Mon, 8 Apr 2024 09:56:41 -0700 Subject: [PATCH 08/12] Add `_NODISCARD`. --- stl/inc/cmath | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/stl/inc/cmath b/stl/inc/cmath index 991149a4632..30ddd870b3e 100644 --- a/stl/inc/cmath +++ b/stl/inc/cmath @@ -596,13 +596,13 @@ _STD _Common_float_type_t<_Ty1, _Ty2> remquo(_Ty1 _Left, _Ty2 _Right, int* _Pquo // TRANSITION, GH-519, should be provided by UCRT template , int> = 0> -_Check_return_ _CONSTEXPR23 int fpclassify(_In_ const _Ty _Ix) noexcept /* strengthened */ { +_NODISCARD _Check_return_ _CONSTEXPR23 int fpclassify(_In_ const _Ty _Ix) noexcept /* strengthened */ { return _Ix ? FP_NORMAL : FP_ZERO; } // TRANSITION, GH-519, should be provided by UCRT template , int> = 0> -_Check_return_ _CONSTEXPR23 bool signbit(_In_ const _Ty _Ix) noexcept /* strengthened */ { +_NODISCARD _Check_return_ _CONSTEXPR23 bool signbit(_In_ const _Ty _Ix) noexcept /* strengthened */ { if constexpr (static_cast<_Ty>(-1) < _Ty{}) { return _Ix < 0; } else { From b78356699238d1cf7d540065be3bae1f591eb2db Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Mon, 8 Apr 2024 10:02:54 -0700 Subject: [PATCH 09/12] Avoid directly testing integers. --- stl/inc/cmath | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stl/inc/cmath b/stl/inc/cmath index 30ddd870b3e..19deeffa18e 100644 --- a/stl/inc/cmath +++ b/stl/inc/cmath @@ -597,7 +597,7 @@ _STD _Common_float_type_t<_Ty1, _Ty2> remquo(_Ty1 _Left, _Ty2 _Right, int* _Pquo // TRANSITION, GH-519, should be provided by UCRT template , int> = 0> _NODISCARD _Check_return_ _CONSTEXPR23 int fpclassify(_In_ const _Ty _Ix) noexcept /* strengthened */ { - return _Ix ? FP_NORMAL : FP_ZERO; + return _Ix == 0 ? FP_ZERO : FP_NORMAL; } // TRANSITION, GH-519, should be provided by UCRT From 9ef3c4a10edd924bbba1f7c7499d53a450050f81 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Mon, 8 Apr 2024 10:16:41 -0700 Subject: [PATCH 10/12] Test `isinf()` before `isnan()` to follow Standard order. --- .../GH_000519_cmath_int_overloads/test.cpp | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/tests/std/tests/GH_000519_cmath_int_overloads/test.cpp b/tests/std/tests/GH_000519_cmath_int_overloads/test.cpp index 9b9a69bd736..ee00b3161b0 100644 --- a/tests/std/tests/GH_000519_cmath_int_overloads/test.cpp +++ b/tests/std/tests/GH_000519_cmath_int_overloads/test.cpp @@ -22,12 +22,12 @@ CONSTEXPR23 void test_bool_overloads() { assert(std::isfinite(false)); assert(std::isfinite(true)); - assert(!std::isnan(false)); - assert(!std::isnan(true)); - assert(!std::isinf(false)); assert(!std::isinf(true)); + assert(!std::isnan(false)); + assert(!std::isnan(true)); + assert(!std::isnormal(false)); assert(std::isnormal(true)); @@ -42,12 +42,12 @@ CONSTEXPR23 void test_bool_overloads() { assert(::isfinite(false)); assert(::isfinite(true)); - assert(!::isnan(false)); - assert(!::isnan(true)); - assert(!::isinf(false)); assert(!::isinf(true)); + assert(!::isnan(false)); + assert(!::isnan(true)); + assert(!::isnormal(false)); assert(::isnormal(true)); @@ -67,14 +67,14 @@ CONSTEXPR23 void test_other_integral_overloads() { assert(std::isfinite(static_cast(42))); assert(std::isfinite(static_cast(-42))); - assert(!std::isnan(I{})); - assert(!std::isnan(static_cast(42))); - assert(!std::isnan(static_cast(-42))); - assert(!std::isinf(I{})); assert(!std::isinf(static_cast(42))); assert(!std::isinf(static_cast(-42))); + assert(!std::isnan(I{})); + assert(!std::isnan(static_cast(42))); + assert(!std::isnan(static_cast(-42))); + assert(!std::isnormal(I{})); assert(std::isnormal(static_cast(42))); assert(std::isnormal(static_cast(-42))); @@ -93,14 +93,14 @@ CONSTEXPR23 void test_other_integral_overloads() { assert(::isfinite(static_cast(42))); assert(::isfinite(static_cast(-42))); - assert(!::isnan(I{})); - assert(!::isnan(static_cast(42))); - assert(!::isnan(static_cast(-42))); - assert(!::isinf(I{})); assert(!::isinf(static_cast(42))); assert(!::isinf(static_cast(-42))); + assert(!::isnan(I{})); + assert(!::isnan(static_cast(42))); + assert(!::isnan(static_cast(-42))); + assert(!::isnormal(I{})); assert(::isnormal(static_cast(42))); assert(::isnormal(static_cast(-42))); From fb8547354e9a138b2d59da5767e96d2fbef1aa7e Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Mon, 8 Apr 2024 10:35:40 -0700 Subject: [PATCH 11/12] Rename to `_GENERIC_MATH_CLASSIFY1_RETV_INTEGER`. Regex: `_GENERIC_MATH_CLASSIFY1_PER_TYPE_RETV\(FUN, (.+), RETV\)` => `_GENERIC_MATH_CLASSIFY1_RETV_INTEGER(FUN, RETV, $1)` Plus a manual rename for the `#undef`. --- stl/inc/cmath | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/stl/inc/cmath b/stl/inc/cmath index 19deeffa18e..f4e0ae7072d 100644 --- a/stl/inc/cmath +++ b/stl/inc/cmath @@ -685,39 +685,39 @@ _GENERIC_MATH_ISNORMAL(wchar_t) #endif // ^^^ intrinsics unavailable ^^^ // TRANSITION, GH-519, additional overloads are not templated to avoid ambiguity with the major overload in UCRT -#define _GENERIC_MATH_CLASSIFY1_PER_TYPE_RETV(FUN, TYPE, RETV) \ +#define _GENERIC_MATH_CLASSIFY1_RETV_INTEGER(FUN, RETV, TYPE) \ _NODISCARD _Check_return_ _CONSTEXPR23 bool FUN(_In_ TYPE) noexcept /* strengthened */ { \ return RETV; \ } #ifdef __cpp_char8_t -#define _GENERIC_MATH_CLASSIFY1_RETV_CHAR8_T(FUN, RETV) _GENERIC_MATH_CLASSIFY1_PER_TYPE_RETV(FUN, char8_t, RETV) +#define _GENERIC_MATH_CLASSIFY1_RETV_CHAR8_T(FUN, RETV) _GENERIC_MATH_CLASSIFY1_RETV_INTEGER(FUN, RETV, char8_t) #else // ^^^ defined(__cpp_char8_t) / !defined(__cpp_char8_t) vvv #define _GENERIC_MATH_CLASSIFY1_RETV_CHAR8_T(FUN, RETV) #endif // ^^^ !defined(__cpp_char8_t) ^^^ #ifdef _NATIVE_WCHAR_T_DEFINED -#define _GENERIC_MATH_CLASSIFY1_RETV_WCHAR_T(FUN, RETV) _GENERIC_MATH_CLASSIFY1_PER_TYPE_RETV(FUN, wchar_t, RETV) +#define _GENERIC_MATH_CLASSIFY1_RETV_WCHAR_T(FUN, RETV) _GENERIC_MATH_CLASSIFY1_RETV_INTEGER(FUN, RETV, wchar_t) #else // ^^^ defined(_NATIVE_WCHAR_T_DEFINED) / !defined(_NATIVE_WCHAR_T_DEFINED) vvv #define _GENERIC_MATH_CLASSIFY1_RETV_WCHAR_T(FUN, RETV) #endif // ^^^ !defined(_NATIVE_WCHAR_T_DEFINED) ^^^ -#define _GENERIC_MATH_CLASSIFY1_RETV(FUN, RETV) \ - _GENERIC_MATH_CLASSIFY1_PER_TYPE_RETV(FUN, signed char, RETV) \ - _GENERIC_MATH_CLASSIFY1_PER_TYPE_RETV(FUN, unsigned char, RETV) \ - _GENERIC_MATH_CLASSIFY1_PER_TYPE_RETV(FUN, short, RETV) \ - _GENERIC_MATH_CLASSIFY1_PER_TYPE_RETV(FUN, unsigned short, RETV) \ - _GENERIC_MATH_CLASSIFY1_PER_TYPE_RETV(FUN, int, RETV) \ - _GENERIC_MATH_CLASSIFY1_PER_TYPE_RETV(FUN, unsigned int, RETV) \ - _GENERIC_MATH_CLASSIFY1_PER_TYPE_RETV(FUN, long, RETV) \ - _GENERIC_MATH_CLASSIFY1_PER_TYPE_RETV(FUN, unsigned long, RETV) \ - _GENERIC_MATH_CLASSIFY1_PER_TYPE_RETV(FUN, long long, RETV) \ - _GENERIC_MATH_CLASSIFY1_PER_TYPE_RETV(FUN, unsigned long long, RETV) \ - _GENERIC_MATH_CLASSIFY1_PER_TYPE_RETV(FUN, bool, RETV) \ - _GENERIC_MATH_CLASSIFY1_PER_TYPE_RETV(FUN, char, RETV) \ - _GENERIC_MATH_CLASSIFY1_RETV_CHAR8_T(FUN, RETV) \ - _GENERIC_MATH_CLASSIFY1_PER_TYPE_RETV(FUN, char16_t, RETV) \ - _GENERIC_MATH_CLASSIFY1_PER_TYPE_RETV(FUN, char32_t, RETV) \ +#define _GENERIC_MATH_CLASSIFY1_RETV(FUN, RETV) \ + _GENERIC_MATH_CLASSIFY1_RETV_INTEGER(FUN, RETV, signed char) \ + _GENERIC_MATH_CLASSIFY1_RETV_INTEGER(FUN, RETV, unsigned char) \ + _GENERIC_MATH_CLASSIFY1_RETV_INTEGER(FUN, RETV, short) \ + _GENERIC_MATH_CLASSIFY1_RETV_INTEGER(FUN, RETV, unsigned short) \ + _GENERIC_MATH_CLASSIFY1_RETV_INTEGER(FUN, RETV, int) \ + _GENERIC_MATH_CLASSIFY1_RETV_INTEGER(FUN, RETV, unsigned int) \ + _GENERIC_MATH_CLASSIFY1_RETV_INTEGER(FUN, RETV, long) \ + _GENERIC_MATH_CLASSIFY1_RETV_INTEGER(FUN, RETV, unsigned long) \ + _GENERIC_MATH_CLASSIFY1_RETV_INTEGER(FUN, RETV, long long) \ + _GENERIC_MATH_CLASSIFY1_RETV_INTEGER(FUN, RETV, unsigned long long) \ + _GENERIC_MATH_CLASSIFY1_RETV_INTEGER(FUN, RETV, bool) \ + _GENERIC_MATH_CLASSIFY1_RETV_INTEGER(FUN, RETV, char) \ + _GENERIC_MATH_CLASSIFY1_RETV_CHAR8_T(FUN, RETV) \ + _GENERIC_MATH_CLASSIFY1_RETV_INTEGER(FUN, RETV, char16_t) \ + _GENERIC_MATH_CLASSIFY1_RETV_INTEGER(FUN, RETV, char32_t) \ _GENERIC_MATH_CLASSIFY1_RETV_WCHAR_T(FUN, RETV) // The following order matches N4950 [cmath.syn]. @@ -796,7 +796,7 @@ _GENERIC_MATH_CLASSIFY1_RETV(isnan, false) #undef _GENERIC_MATH2_BASE #undef _GENERIC_MATH2 #undef _GENERIC_MATH2I -#undef _GENERIC_MATH_CLASSIFY1_PER_TYPE_RETV +#undef _GENERIC_MATH_CLASSIFY1_RETV_INTEGER #undef _GENERIC_MATH_CLASSIFY1_RETV_WCHAR_T #undef _GENERIC_MATH_CLASSIFY1_RETV_CHAR8_T #undef _GENERIC_MATH_CLASSIFY1_RETV From 03c0f87b176cf7a572c3c07a5cc724bfc9d2da7f Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Mon, 8 Apr 2024 11:05:26 -0700 Subject: [PATCH 12/12] Also test `isgreater()` etc. --- .../GH_000519_cmath_int_overloads/test.cpp | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/tests/std/tests/GH_000519_cmath_int_overloads/test.cpp b/tests/std/tests/GH_000519_cmath_int_overloads/test.cpp index ee00b3161b0..8954620c506 100644 --- a/tests/std/tests/GH_000519_cmath_int_overloads/test.cpp +++ b/tests/std/tests/GH_000519_cmath_int_overloads/test.cpp @@ -34,6 +34,18 @@ CONSTEXPR23 void test_bool_overloads() { assert(!std::signbit(false)); assert(!std::signbit(true)); +#if _HAS_CXX23 // TRANSITION, UCRT should implement P0533R9 "constexpr For And " + if (!std::is_constant_evaluated()) +#endif // ^^^ _HAS_CXX23 ^^^ + { + assert(!std::isgreater(false, true)); + assert(!std::isgreaterequal(false, true)); + assert(std::isless(false, true)); + assert(std::islessequal(false, true)); + assert(std::islessgreater(false, true)); + assert(!std::isunordered(false, true)); + } + // test overloads in the global namespace assert(::fpclassify(false) == FP_ZERO); @@ -53,6 +65,18 @@ CONSTEXPR23 void test_bool_overloads() { assert(!::signbit(false)); assert(!::signbit(true)); + +#if _HAS_CXX23 // TRANSITION, UCRT should implement P0533R9 "constexpr For And " + if (!std::is_constant_evaluated()) +#endif // ^^^ _HAS_CXX23 ^^^ + { + assert(!::isgreater(false, true)); + assert(!::isgreaterequal(false, true)); + assert(::isless(false, true)); + assert(::islessequal(false, true)); + assert(::islessgreater(false, true)); + assert(!::isunordered(false, true)); + } } template @@ -83,6 +107,18 @@ CONSTEXPR23 void test_other_integral_overloads() { assert(!std::signbit(static_cast(42))); assert(std::signbit(static_cast(-42)) == std::is_signed_v); +#if _HAS_CXX23 // TRANSITION, UCRT should implement P0533R9 "constexpr For And " + if (!std::is_constant_evaluated()) +#endif // ^^^ _HAS_CXX23 ^^^ + { + assert(!std::isgreater(static_cast(17), static_cast(29))); + assert(!std::isgreaterequal(static_cast(17), static_cast(29))); + assert(std::isless(static_cast(17), static_cast(29))); + assert(std::islessequal(static_cast(17), static_cast(29))); + assert(std::islessgreater(static_cast(17), static_cast(29))); + assert(!std::isunordered(static_cast(17), static_cast(29))); + } + // test overloads in the global namespace assert(::fpclassify(I{}) == FP_ZERO); @@ -108,6 +144,18 @@ CONSTEXPR23 void test_other_integral_overloads() { assert(!::signbit(I{})); assert(!::signbit(static_cast(42))); assert(::signbit(static_cast(-42)) == std::is_signed_v); + +#if _HAS_CXX23 // TRANSITION, UCRT should implement P0533R9 "constexpr For And " + if (!std::is_constant_evaluated()) +#endif // ^^^ _HAS_CXX23 ^^^ + { + assert(!::isgreater(static_cast(17), static_cast(29))); + assert(!::isgreaterequal(static_cast(17), static_cast(29))); + assert(::isless(static_cast(17), static_cast(29))); + assert(::islessequal(static_cast(17), static_cast(29))); + assert(::islessgreater(static_cast(17), static_cast(29))); + assert(!::isunordered(static_cast(17), static_cast(29))); + } } CONSTEXPR23 bool test_all_integral_overloads() {