Hi! As the P3899R3 paper says, it standardizes the GCC 15 behavior.
The following patch adds tests from the paper. On the second test it seems to report the expected diagnostics starting with PR104389 fix, so I think in cxx-status.html we should say it is supported since GCC 12. The first test obviously needs at least GCC 13 because it uses the extended floating point types. Tested on x86_64-linux and i686-linux, ok for trunk? 2026-06-25 Jakub Jelinek <[email protected]> PR c++/125824 * lib/target-supports.exp (check_effective_target_flt_dbl_ldbl_inf_nan): New. * g++.dg/cpp29/ext-floating1.C: New test. * g++.dg/cpp29/std-floating1.C: New test. --- gcc/testsuite/lib/target-supports.exp.jj 2026-06-25 10:03:50.884435539 +0200 +++ gcc/testsuite/lib/target-supports.exp 2026-06-25 13:31:40.569464336 +0200 @@ -4245,6 +4245,20 @@ proc check_effective_target_has_q_floati } "$opts"] } +# Return 1 if the target supports infinities and NaNs on +# float, double and long double. + +proc check_effective_target_flt_dbl_ldbl_inf_nan { } { + return [check_no_compiler_messages_nocache flt_dbl_ldbl_inf_nan object { + int dummy1[__FLT_HAS_INFINITY__ ? 1 : -1]; + int dummy2[__FLT_HAS_QUIET_NAN__ ? 1 : -1]; + int dummy3[__DBL_HAS_INFINITY__ ? 1 : -1]; + int dummy4[__DBL_HAS_QUIET_NAN__ ? 1 : -1]; + int dummy5[__LDBL_HAS_INFINITY__ ? 1 : -1]; + int dummy6[__LDBL_HAS_QUIET_NAN__ ? 1 : -1]; + }] +} + # Return 1 if the target supports the _FloatN / _FloatNx type # indicated in the function name, 0 otherwise. --- gcc/testsuite/g++.dg/cpp29/ext-floating1.C.jj 2026-06-25 12:30:36.775131918 +0200 +++ gcc/testsuite/g++.dg/cpp29/ext-floating1.C 2026-06-25 13:17:28.140228514 +0200 @@ -0,0 +1,122 @@ +// P3899R3 - Clarify the behavior of floating-point overflow +// { dg-do compile { target c++23 } } +// { dg-options "-fexcess-precision=16" } +// { dg-add-options float16 } +// { dg-add-options float32 } +// { dg-add-options float64 } +// { dg-add-options float128 } +// { dg-add-options bfloat16 } + +#include <stdfloat> +#include <limits> + +#ifdef __STDCPP_FLOAT16_T__ +constexpr std::float16_t min16 = std::numeric_limits<std::float16_t>::min (); +constexpr std::float16_t max16 = std::numeric_limits<std::float16_t>::max (); +constexpr std::float16_t inf16 = std::numeric_limits<std::float16_t>::infinity (); +constexpr std::float16_t nan16 = std::numeric_limits<std::float16_t>::quiet_NaN (); +constexpr std::float16_t snan16 = std::numeric_limits<std::float16_t>::signaling_NaN (); + +// Furthermore, if arithmetic expressions with operands of type std::float16_t +// behave as specified in ISO/IEC 60559 for binary16: +constexpr std::float16_t inf216 = inf16 * 2.0f16; // OK, also positive infinity +constexpr std::float16_t zero16 = min16 / max16; // OK, result cannot be represented, and is rounded to zero +constexpr std::float16_t oflo16 = max16 * 2.0f16; // { dg-error "is not a constant expression" "" { target float16 } } +constexpr std::float16_t nan216 = nan16 * 2.0f16; // OK, propagating a NaN +constexpr std::float16_t udef16 = inf16 * 0.0f16; // { dg-error "is not a constant expression" "" { target float16 } } +constexpr std::float16_t div016 = max16 / 0.0f16; // { dg-error "is not a constant expression" "" { target float16 } } +constexpr std::float16_t zero216 = min16 * min16; +constexpr bool nancmp16 = nan16 < 0.0f16; +constexpr std::float16_t snan216 = snan16 * 2.0f16; +constexpr std::float16_t div0216 = 1.0f16 / 0.0f16; // { dg-error "is not a constant expression" "" { target float16 } } +constexpr std::float16_t div0316 = 0.0f16 / 0.0f16; // { dg-error "is not a constant expression" "" { target float16 } } +#endif + +#ifdef __STDCPP_FLOAT32_T__ +constexpr std::float32_t min32 = std::numeric_limits<std::float32_t>::min (); +constexpr std::float32_t max32 = std::numeric_limits<std::float32_t>::max (); +constexpr std::float32_t inf32 = std::numeric_limits<std::float32_t>::infinity (); +constexpr std::float32_t nan32 = std::numeric_limits<std::float32_t>::quiet_NaN (); +constexpr std::float32_t snan32 = std::numeric_limits<std::float32_t>::signaling_NaN (); + +// Furthermore, if arithmetic expressions with operands of type std::float32_t +// behave as specified in ISO/IEC 60559 for binary32: +constexpr std::float32_t inf232 = inf32 * 2.0f32; // OK, also positive infinity +constexpr std::float32_t zero32 = min32 / max32; // OK, result cannot be represented, and is rounded to zero +constexpr std::float32_t oflo32 = max32 * 2.0f32; // { dg-error "is not a constant expression" "" { target float32 } } +constexpr std::float32_t nan232 = nan32 * 2.0f32; // OK, propagating a NaN +constexpr std::float32_t udef32 = inf32 * 0.0f32; // { dg-error "is not a constant expression" "" { target float32 } } +constexpr std::float32_t div032 = max32 / 0.0f32; // { dg-error "is not a constant expression" "" { target float32 } } +constexpr std::float32_t zero232 = min32 * min32; +constexpr bool nancmp32 = nan32 < 0.0f32; +constexpr std::float32_t snan232 = snan32 * 2.0f32; +constexpr std::float32_t div0232 = 1.0f32 / 0.0f32; // { dg-error "is not a constant expression" "" { target float32 } } +constexpr std::float32_t div0332 = 0.0f32 / 0.0f32; // { dg-error "is not a constant expression" "" { target float32 } } +#endif + +#ifdef __STDCPP_FLOAT64_T__ +constexpr std::float64_t min64 = std::numeric_limits<std::float64_t>::min (); +constexpr std::float64_t max64 = std::numeric_limits<std::float64_t>::max (); +constexpr std::float64_t inf64 = std::numeric_limits<std::float64_t>::infinity (); +constexpr std::float64_t nan64 = std::numeric_limits<std::float64_t>::quiet_NaN (); +constexpr std::float64_t snan64 = std::numeric_limits<std::float64_t>::signaling_NaN (); + +// Furthermore, if arithmetic expressions with operands of type std::float64_t +// behave as specified in ISO/IEC 60559 for binary64: +constexpr std::float64_t inf264 = inf64 * 2.0f64; // OK, also positive infinity +constexpr std::float64_t zero64 = min64 / max64; // OK, result cannot be represented, and is rounded to zero +constexpr std::float64_t oflo64 = max64 * 2.0f64; // { dg-error "is not a constant expression" "" { target float64 } } +constexpr std::float64_t nan264 = nan64 * 2.0f64; // OK, propagating a NaN +constexpr std::float64_t udef64 = inf64 * 0.0f64; // { dg-error "is not a constant expression" "" { target float64 } } +constexpr std::float64_t div064 = max64 / 0.0f64; // { dg-error "is not a constant expression" "" { target float64 } } +constexpr std::float64_t zero264 = min64 * min64; +constexpr bool nancmp64 = nan64 < 0.0f64; +constexpr std::float64_t snan264 = snan64 * 2.0f64; +constexpr std::float64_t div0264 = 1.0f64 / 0.0f64; // { dg-error "is not a constant expression" "" { target float64 } } +constexpr std::float64_t div0364 = 0.0f64 / 0.0f64; // { dg-error "is not a constant expression" "" { target float64 } } +#endif + +#ifdef __STDCPP_FLOAT128_T__ +constexpr std::float128_t min128 = std::numeric_limits<std::float128_t>::min (); +constexpr std::float128_t max128 = std::numeric_limits<std::float128_t>::max (); +constexpr std::float128_t inf128 = std::numeric_limits<std::float128_t>::infinity (); +constexpr std::float128_t nan128 = std::numeric_limits<std::float128_t>::quiet_NaN (); +constexpr std::float128_t snan128 = std::numeric_limits<std::float128_t>::signaling_NaN (); + +// Furthermore, if arithmetic expressions with operands of type std::float128_t +// behave as specified in ISO/IEC 60559 for binary128: +constexpr std::float128_t inf2128 = inf128 * 2.0f128; // OK, also positive infinity +constexpr std::float128_t zero128 = min128 / max128; // OK, result cannot be represented, and is rounded to zero +constexpr std::float128_t oflo128 = max128 * 2.0f128; // { dg-error "is not a constant expression" "" { target float128 } } +constexpr std::float128_t nan2128 = nan128 * 2.0f128; // OK, propagating a NaN +constexpr std::float128_t udef128 = inf128 * 0.0f128; // { dg-error "is not a constant expression" "" { target float128 } } +constexpr std::float128_t div0128 = max128 / 0.0f128; // { dg-error "is not a constant expression" "" { target float128 } } +constexpr std::float128_t zero2128 = min128 * min128; +constexpr bool nancmp128 = nan128 < 0.0f128; +constexpr std::float128_t snan2128 = snan128 * 2.0f128; +constexpr std::float128_t div02128 = 1.0f128 / 0.0f128; // { dg-error "is not a constant expression" "" { target float128 } } +constexpr std::float128_t div03128 = 0.0f128 / 0.0f128; // { dg-error "is not a constant expression" "" { target float128 } } +#endif + +#ifdef __STDCPP_BFLOAT16_T__ +constexpr std::bfloat16_t minb16 = std::numeric_limits<std::bfloat16_t>::min (); +constexpr std::bfloat16_t maxb16 = std::numeric_limits<std::bfloat16_t>::max (); +constexpr std::bfloat16_t infb16 = std::numeric_limits<std::bfloat16_t>::infinity (); +constexpr std::bfloat16_t nanb16 = std::numeric_limits<std::bfloat16_t>::quiet_NaN (); +constexpr std::bfloat16_t snanb16 = std::numeric_limits<std::bfloat16_t>::signaling_NaN (); + +constexpr std::bfloat16_t inf2b16 = infb16 * 2.0bf16; // OK, also positive infinity +constexpr std::bfloat16_t zerob16 = minb16 / maxb16; // OK, result cannot be represented, and is rounded to zero +constexpr std::bfloat16_t oflob16 = maxb16 * 2.0bf16; // { dg-error "is not a constant expression" "" { target bfloat16 } } +constexpr std::bfloat16_t nan2b16 = nanb16 * 2.0bf16; // OK, propagating a NaN +constexpr std::bfloat16_t udefb16 = infb16 * 0.0bf16; // { dg-error "is not a constant expression" "" { target bfloat16 } } +constexpr std::bfloat16_t div0b16 = maxb16 / 0.0bf16; // { dg-error "is not a constant expression" "" { target bfloat16 } } +constexpr std::bfloat16_t zero2b16 = minb16 * minb16; +constexpr bool nancmpb16 = nanb16 < 0.0bf16; +constexpr std::bfloat16_t snan2b16 = snanb16 * 2.0bf16; +constexpr std::bfloat16_t div02b16 = 1.0bf16 / 0.0bf16; // { dg-error "is not a constant expression" "" { target bfloat16 } } +constexpr std::bfloat16_t div03b16 = 0.0bf16 / 0.0bf16; // { dg-error "is not a constant expression" "" { target bfloat16 } } +#endif + +constexpr int div0 = 0 / 0; // { dg-error "division by zero is not a constant expression" } +// { dg-warning "division by zero" "" { target *-*-* } .-1 } --- gcc/testsuite/g++.dg/cpp29/std-floating1.C.jj 2026-06-25 13:32:30.440846439 +0200 +++ gcc/testsuite/g++.dg/cpp29/std-floating1.C 2026-06-25 13:39:01.969021683 +0200 @@ -0,0 +1,57 @@ +// P3899R3 - Clarify the behavior of floating-point overflow +// { dg-do compile { target { c++11 && flt_dbl_ldbl_inf_nan } } } +// { dg-options "" } + +constexpr float minf = __FLT_MIN__; +constexpr float maxf = __FLT_MAX__; +constexpr float inff = __builtin_inff (); +constexpr float nanf = __builtin_nanf (""); +constexpr float snanf = __builtin_nansf (""); + +constexpr float inf2f = inff * 2.0f; // OK, also positive infinity +constexpr float zerof = minf / maxf; // OK, result cannot be represented, and is rounded to zero +constexpr float oflof = maxf * 2.0f; // { dg-error "is not a constant expression" } +constexpr float nan2f = nanf * 2.0f; // OK, propagating a NaN +constexpr float udeff = inff * 0.0f; // { dg-error "is not a constant expression" } +constexpr float div0f = maxf / 0.0f; // { dg-error "is not a constant expression" } +constexpr float zero2f = minf * minf; +constexpr bool nancmpf = nanf < 0.0f; +constexpr float snan2f = snanf * 2.0f; +constexpr float div02f = 1.0f / 0.0f; // { dg-error "is not a constant expression" } +constexpr float div03f = 0.0f / 0.0f; // { dg-error "is not a constant expression" } + +constexpr double mind = __DBL_MIN__; +constexpr double maxd = __DBL_MAX__; +constexpr double infd = __builtin_inf (); +constexpr double nand = __builtin_nan (""); +constexpr double snand = __builtin_nans (""); + +constexpr double inf2d = infd * 2.0; // OK, also positive infinity +constexpr double zerod = mind / maxd; // OK, result cannot be represented, and is rounded to zero +constexpr double oflod = maxd * 2.0; // { dg-error "is not a constant expression" } +constexpr double nan2d = nand * 2.0; // OK, propagating a NaN +constexpr double udefd = infd * 0.0; // { dg-error "is not a constant expression" } +constexpr double div0d = maxd / 0.0; // { dg-error "is not a constant expression" } +constexpr double zero2d = mind * mind; +constexpr bool nancmpd = nand < 0.0; +constexpr double snan2d = snand * 2.0; +constexpr double div02d = 1.0 / 0.0; // { dg-error "is not a constant expression" } +constexpr double div03d = 0.0 / 0.0; // { dg-error "is not a constant expression" } + +constexpr long double minld = __LDBL_MIN__; +constexpr long double maxld = __LDBL_MAX__; +constexpr long double infld = __builtin_infl (); +constexpr long double nanld = __builtin_nanl (""); +constexpr long double snanld = __builtin_nansl (""); + +constexpr long double inf2ld = infld * 2.0L; // OK, also positive infinity +constexpr long double zerold = minld / maxld; // OK, result cannot be represented, and is rounded to zero +constexpr long double oflold = maxld * 2.0L; // { dg-error "is not a constant expression" } +constexpr long double nan2ld = nanld * 2.0L; // OK, propagating a NaN +constexpr long double udefld = infld * 0.0L; // { dg-error "is not a constant expression" } +constexpr long double div0ld = maxld / 0.0L; // { dg-error "is not a constant expression" } +constexpr long double zero2ld = minld * minld; +constexpr bool nancmpld = nanld < 0.0L; +constexpr long double snan2ld = snanld * 2.0L; +constexpr long double div02ld = 1.0L / 0.0L; // { dg-error "is not a constant expression" } +constexpr long double div03ld = 0.0L / 0.0L; // { dg-error "is not a constant expression" } Jakub
