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

Reply via email to