← board

A wide unsigned literal boxed into a Variant stores the wrapped value

v := 18446744073709551615 stores -1. fpc 3.2.2 stores 18446744073709551615. Silent, no diagnostic, plausible number.

Repro

program vbox;
var v: Variant;
begin
  v := 18446744073709551615; writeln(v);   { pxx: -1        fpc: 18446744073709551615 }
  v := 9223372036854775808;  writeln(v);   { pxx: -9223...  fpc: 9223372036854775808  }
  v := 9223372036854775807;  writeln(v);   { both correct — outside the band }
end.

Measured at compiler b31b9b1821c1, both compilers on the same source. Confined to the band [2^63, 2^64): below it the Int64 reading is right, and at or above 2^64 the literal keeps tyInt64, stays in IsWideIntLit, and routes through the promo runtime correctly.

Only the ASSIGNMENT differs. v + 0 answers -1 under both compilers, so the operand path is not in scope here.

Cause

Same one as regression-test-core-test-promoint-bitwise: 10e670503 retags every decimal in [2^63, 2^64) to tyUInt64 at the literal's creation site, which takes it out of IsWideIntLit, which is what the variant boxing arm (compiler/ir.inc, the IR_VAR_BOX operand arms and the assignment arm above them) asks before routing a wide literal through PXXPromoBoxedVariantAddr instead of boxing the wrapped machine int. A variant carries no unsignedness, so tyUInt64 as the source kind does not save it.

Why the obvious fix is wrong, measured

Widening those arms to the digits-only predicate (WideLitHasDigits, added 2026-09-06) makes an ordinary Pascal program that never mentions PromoInt fail to compile:

pascal26:7: error: promotable int: runtime helper PXXPromoFromStr not found
                   (promocore unit not loaded)

Measured — I wrote that fix, built it, and reverted it. That is a worse answer than the wrong value and it is the exact condition 10e670503 exists to remove. Above 2^64 the same routing is worth it because no 64-bit reading exists at all; inside the band one does.

So the repair belongs on the variant side, not in the predicate — either a variant that carries unsignedness, or a box-by-source-kind that honours tyUInt64. Both are Track A design calls beyond the predicate split.

Trap for whoever takes it

A probe for this MUST NOT declare a PromoInt anywhere. Doing so loads promocore and the promo-runtime route silently starts working, so the broken fix above reads as correct. That is how it got past me: my band probe declared p: PromoInt for unrelated rows and certified an arm that fails in every program without one.

Found while fixing regression-test-core-test-promoint-bitwise; not a regression in the sense of a working thing broken — before 10e670503 this shape did not compile at all.