================ @@ -67,6 +68,69 @@ void B<int>::g() requires true; } // namespace cwg2847 +namespace cwg2851 { // cwg2851: 19 + +#if __cplusplus >= 202002L +template<typename T, T v> struct Val { static constexpr T value = v; }; + + +// Floating-point promotions + +static_assert(Val<long double, 0.0>::value == 0.0L); +static_assert(Val<long double, 0.0f>::value == 0.0L); +static_assert(Val<double, 0.0f>::value == 0.0); +static_assert(Val<long double, -0.0>::value == -0.0L); + +static_assert(!__is_same(Val<long double, -0.0>, Val<long double, 0.0L>)); +static_assert(__is_same(Val<long double, 0.5>, Val<long double, 0.5L>)); + +static_assert(__is_same(Val<long double, __builtin_inff()>, Val<long double, __builtin_infl()>)); + +static_assert(__is_same(Val<long double, __builtin_nanf("")>, Val<long double, static_cast<long double>(__builtin_nanf(""))>)); +static_assert(__is_same(Val<long double, __builtin_nansf("")>, Val<long double, static_cast<long double>(__builtin_nansf(""))>)); +static_assert(__is_same(Val<long double, __builtin_nanf("0x1")>, Val<long double, static_cast<long double>(__builtin_nanf("0x1"))>)); +static_assert(__is_same(Val<long double, __builtin_nansf("0x1")>, Val<long double, static_cast<long double>(__builtin_nansf("0x1"))>)); + + +// Floating-point conversions where the source value can be represented exactly in the destination type + +static_assert(Val<float, 0.0L>::value == 0.0L); +static_assert(__is_same(Val<float, 0.0>, Val<float, 0.0L>)); +static_assert(__is_same(Val<float, 0.0>, Val<float, 0.0f>)); +static_assert(!__is_same(Val<float, -0.0L>, Val<float, 0.0f>)); +static_assert(__is_same(Val<float, 0.5L>, Val<float, 0.5f>)); +static_assert(__is_same(Val<float, 0.5L>, Val<float, 0.5f>)); + +static_assert(__is_same(Val<float, double{__FLT_DENORM_MIN__}>, Val<float, __FLT_DENORM_MIN__>)); +Val<float, double{__FLT_DENORM_MIN__} / 2.0> _1; +// since-cxx20-error-re@-1 {{non-type template argument evaluates to {{.+}} which cannot be exactly represented in type 'float'}} +Val<float, static_cast<long double>(__FLT_DENORM_MIN__) / 2.0L> _2; +// since-cxx20-error-re@-1 {{non-type template argument evaluates to {{.+}} which cannot be exactly represented in type 'float'}} +Val<float, __DBL_MAX__> _3; +// since-cxx20-error-re@-1 {{non-type template argument evaluates to {{.+}} which cannot be exactly represented in type 'float'}} + +static_assert(__is_same(Val<float, __builtin_infl()>, Val<float, __builtin_inff()>)); + +static_assert(__is_same(Val<float, __builtin_nanl("")>, Val<float, static_cast<float>(__builtin_nanl(""))>)); +static_assert(__is_same(Val<float, __builtin_nansl("")>, Val<float, static_cast<float>(__builtin_nansl(""))>)); +#if __SIZEOF_LONG_DOUBLE__ > 8 +// since-cxx20-error@-2 {{non-type template argument evaluates to nan which cannot be exactly represented in type 'float'}} +#endif +// Payload is shifted right so these payloads will be preserved +static_assert(__is_same(Val<float, __builtin_nan("0xFF00000000")>, Val<float, static_cast<float>(__builtin_nan("0xFF00000000"))>)); +static_assert(__is_same(Val<float, __builtin_nans("0xFF00000000")>, Val<float, static_cast<float>(__builtin_nans("0xFF00000000"))>)); +static_assert(__is_same(Val<float, __builtin_nanl("0x1")>, Val<float, static_cast<float>(__builtin_nanl("0x1"))>)); ---------------- MitalAshok wrote:
I'm not sure how exactly we plan to deal with `NaN`. How `APFloat::convert` seems to work is that when converting to a smaller type, only the most significant bits of the payload are used, so that 1 is cut off (thus lossy). This has the side effect that `Val<float, (long double) __builtin_nansf(payload)>` and `Val<float, (long double) __builtin_nanf(payload)>` always work, because `(long double) __builtin_nanf(payload)` is like `__builtin_nanl(payload << (difference in number of fraction bits between long double and float))`, and anything with the lower bits set counts as "lossy". Anything implicitly converted to a larger type can be converted back in a converted constant expression. See also: IEEE754 6.2.3 "NaN propagation" CWG2864 is about narrowing conversions. For sure `float{__builtin_nanl("0x1")}` isn't a narrowing conversion because it's not finite, but it does lose the payload entirely (`float{__builtin_nanl("0x1")}` and `float{__builtin_nanl("0x0")}` have the same bit pattern, even though the source long doubles don't). But maybe we should consider all NaNs to have the same "value" and this should work? https://github.com/llvm/llvm-project/pull/90387 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits