Fix several float range issues (supersedes #11905) (#12067)

* Fix several float range issues

* address the comments
This commit is contained in:
Andreas Rumpf
2019-08-27 23:19:41 +02:00
committed by GitHub
6 changed files with 27 additions and 3 deletions

View File

@@ -444,6 +444,7 @@ proc semAfterMacroCall(c: PContext, call, macroResult: PNode,
const
errMissingGenericParamsForTemplate = "'$1' has unspecified generic parameters"
errFloatToString = "cannot convert '$1' to '$2'"
proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym,
flags: TExprFlags = {}): PNode =

View File

@@ -513,6 +513,9 @@ proc changeType(c: PContext; n: PNode, newType: PType, check: bool) =
if value < firstOrd(c.config, newType) or value > lastOrd(c.config, newType):
localError(c.config, n.info, "cannot convert " & $value &
" to " & typeToString(newType))
of nkFloatLit..nkFloat64Lit:
if check and not floatRangeCheck(n.floatVal, newType):
localError(c.config, n.info, errFloatToString % [$n.floatVal, typeToString(newType)])
else: discard
n.typ = newType

View File

@@ -292,6 +292,8 @@ proc fitRemoveHiddenConv(c: PContext, typ: PType, n: PNode): PNode =
result = newFloatNode(nkFloatLit, BiggestFloat r1.intVal)
result.info = n.info
result.typ = typ
if not floatRangeCheck(result.floatVal, typ):
localError(c.config, n.info, errFloatToString % [$n.floatVal, typeToString(typ)])
else:
changeType(c, r1, typ, check=true)
result = r1

View File

@@ -10,6 +10,8 @@
# this module does the semantic checking of type declarations
# included from sem.nim
import math
const
errStringOrIdentNodeExpected = "string or ident node expected"
errStringLiteralExpected = "string literal expected"
@@ -236,6 +238,10 @@ proc semRangeAux(c: PContext, n: PNode, prev: PType): PType =
else:
result.n.addSon semConstExpr(c, range[i])
if (result.n[0].kind in {nkFloatLit..nkFloat64Lit} and classify(result.n[0].floatVal) == fcNan) or
(result.n[1].kind in {nkFloatLit..nkFloat64Lit} and classify(result.n[1].floatVal) == fcNan):
localError(c.config, n.info, "NaN is not a valid start or end for a range")
if weakLeValue(result.n[0], result.n[1]) == impNo:
localError(c.config, n.info, "range is empty")

View File

@@ -414,9 +414,10 @@ proc isConvertibleToRange(f, a: PType): bool =
of tyUInt16: result = a.kind in {tyUInt8, tyUInt16, tyUInt}
of tyUInt32: result = a.kind in {tyUInt8, tyUInt16, tyUInt32, tyUInt}
else: result = false
elif f.kind in {tyFloat..tyFloat128} and
a.kind in {tyFloat..tyFloat128}:
result = true
elif f.kind in {tyFloat..tyFloat128}:
# `isIntLit` is correct and should be used above as well, see PR:
# https://github.com/nim-lang/Nim/pull/11197
result = isIntLit(a) or a.kind in {tyFloat..tyFloat128}
proc handleFloatRange(f, a: PType): TTypeRelation =
if a.kind == f.kind:

View File

@@ -118,3 +118,14 @@ block:
x3 = R32(4)
doAssert $x1 & $x2 & $x3 == "444"
block:
var x1: range[0'f..1'f] = 1
const x2: range[0'f..1'f] = 1
var x5: range[0'f32..1'f32] = 1'f64
const x6: range[0'f32..1'f32] = 1'f64
reject:
const x: range[0'f..1'f] = 2'f
reject:
const x: range[0'f..1'f] = 2