fixes #7179; Floats are not range checked (#25050)

fixes #7179


```nim
var f = 751.0
echo f.int8
```

In this case, `int8(float)` yields different numbers for different
optimization levels, since float to int conversions are undefined
behaviors. In this PR, it mitigates this problem by conversions to same
size integers before converting to the final type: i.e.
`int8(int64(float))`, which has UB problems but is better than before
This commit is contained in:
ringabout
2025-07-19 03:30:50 +08:00
committed by GitHub
parent 5b5cd7fa67
commit 08d51e5c88
2 changed files with 57 additions and 1 deletions

View File

@@ -552,7 +552,34 @@ proc transformConv(c: PTransf, n: PNode): PNode =
# we don't include uint and uint64 here as these are no ordinal types ;-)
if not isOrdinalType(source):
# float -> int conversions. ugh.
result = transformSons(c, n)
# generate a range check:
if dest.kind in tyInt..tyInt64:
if dest.kind == tyInt64 or source.kind == tyInt64:
result = newTransNode(nkChckRange64, n, 3)
else:
result = newTransNode(nkChckRange, n, 3)
dest = skipTypes(n.typ, abstractVar)
if dest.size < source.size:
let intType =
if source.size == 4:
getSysType(c.graph, n.info, tyInt32)
else:
getSysType(c.graph, n.info, tyInt64)
result[0] =
newTreeIT(n.kind, n.info, n.typ, n[0],
newTreeIT(nkConv, n.info, intType,
newNodeIT(nkType, n.info, intType), transform(c, n[1]))
)
else:
result[0] = transformSons(c, n)
result[1] = newIntTypeNode(firstOrd(c.graph.config, dest), dest)
result[2] = newIntTypeNode(lastOrd(c.graph.config, dest), dest)
else:
result = transformSons(c, n)
elif firstOrd(c.graph.config, n.typ) <= firstOrd(c.graph.config, n[1].typ) and
lastOrd(c.graph.config, n[1].typ) <= lastOrd(c.graph.config, n.typ):
# BUGFIX: simply leave n as it is; we need a nkConv node,

View File

@@ -245,3 +245,32 @@ proc bar2() =
static: bar2()
bar2()
when not defined(js):
proc foo =
block:
var s1:int = -10
doAssertRaises(RangeDefect):
var n2:Natural = s1.Natural
block:
var f = 751.0
let m = f.int8
block:
var s2:float = -10
doAssertRaises(RangeDefect):
var n2:Natural = s2.Natural
block:
type A = range[0..10]
let f = 156.0
doAssertRaises(RangeDefect):
let a = f.A
echo a # 156
foo()