On Wed, Dec 10, 2025 at 10:37:20AM +0100, Jakub Jelinek wrote: > Though, now that I think about it, for _Float16 and decltype (0.0bf16) > everything could be maybe representable even in _Decimal32.
Here is a variant of the patch which returns -2 for _Float16 vs. decltype (0.0DL) (i.e. that the latter has greater conversion rank than the former), while returning 3 for all the other extended floating point vs. dfp pairs. 2025-12-10 Jakub Jelinek <[email protected]> PR c++/122834 * typeck.cc (cp_compare_floating_point_conversion_ranks): Return 3 if fmt2->b is 10 except for _Float16 vs. _Decimal128, in that case return -2. * g++.dg/dfp/pr122834-1.C: New test. * g++.dg/dfp/pr122834-2.C: New test. --- gcc/cp/typeck.cc.jj 2025-11-24 09:02:57.279720286 +0100 +++ gcc/cp/typeck.cc 2025-12-10 11:57:52.305351179 +0100 @@ -305,7 +305,30 @@ cp_compare_floating_point_conversion_ran const struct real_format *fmt1 = REAL_MODE_FORMAT (TYPE_MODE (t1)); const struct real_format *fmt2 = REAL_MODE_FORMAT (TYPE_MODE (t2)); - gcc_assert (fmt1->b == 2 && fmt2->b == 2); + /* Currently, extended floating point types are only binary, and + they never have a proper subset or superset of values with + decimal floating point types except for the _Float16 vs. _Decimal128 + pair, so return 3 for unordered conversion ranks. */ + gcc_assert (fmt1->b == 2); + if (fmt2->b == 10) + { + /* _Float16 needs at most 21 decimal digits (e.g. + 0x1.a3cp-14f16 is exactly 0.000100076198577880859375DL), + so it is not a proper subset of _Decimal64 but is subset + of _Decimal128. While std::bfloat16_t needs at most 96 + decimal digits, so even _Decimal128 doesn't cover it. + _Float32 has at least one value which needs 112 decimal + digits, _Float64 at least 767 decimal digits. */ + if (fmt1->emin == -13 + && fmt1->emax == 16 + && fmt1->p == 11 + && fmt2->emin == -6142 + && fmt2->emax == 6145 + && fmt2->p == 34) + return -2; + return 3; + } + gcc_assert (fmt2->b == 2); /* For {ibm,mips}_extended_format formats, the type has variable precision up to ~2150 bits when the first double is around maximum representable double and second double is subnormal minimum. --- gcc/testsuite/g++.dg/dfp/pr122834-1.C.jj 2025-12-09 16:23:05.743444612 +0100 +++ gcc/testsuite/g++.dg/dfp/pr122834-1.C 2025-12-09 16:22:51.467689226 +0100 @@ -0,0 +1,17 @@ +// PR c++/122834 +// { dg-do compile { target { c++11 && float128 } } } +// { dg-options "" } +// { dg-add-options float128 } + +typedef decltype (0.0DL) A; +typedef _Float128 B; +void bar (A); // { dg-message "initializing argument 1 of" } + +void +foo (B x) +{ + bar (x); // { dg-warning "with unordered conversion rank" } +} + +auto a = 0.0DL + 1.0F128; // { dg-error "invalid operands to binary \\\+" } +auto b = 1.0F128 + 0.0DL; // { dg-error "invalid operands to binary \\\+" } --- gcc/testsuite/g++.dg/dfp/pr122834-2.C.jj 2025-12-10 11:45:31.423032991 +0100 +++ gcc/testsuite/g++.dg/dfp/pr122834-2.C 2025-12-10 11:47:55.976558883 +0100 @@ -0,0 +1,19 @@ +// PR c++/122834 +// { dg-do compile { target { c++11 && float16 } } } +// { dg-options "" } +// { dg-add-options float16 } + +typedef decltype (0.0DL) A; +typedef _Float16 B; +void bar (A); + +void +foo (B x) +{ + bar (x); +} + +auto a = 0.0DL + 1.0F16; +auto b = 1.0F16 + 0.0DL; +static_assert (__is_same_as (decltype (0.0DL + 1.0F16), decltype (0.0DL))); +static_assert (__is_same_as (decltype (1.0F16 + 0.0DL), decltype (0.0DL))); Jakub
