Merge branch 'devel' into uint-range-checks

This commit is contained in:
Andreas Rumpf
2019-09-02 22:03:10 +02:00
18 changed files with 123 additions and 51 deletions

View File

@@ -608,7 +608,6 @@ type
mAddF64, mSubF64, mMulF64, mDivF64,
mShrI, mShlI, mAshrI, mBitandI, mBitorI, mBitxorI,
mMinI, mMaxI,
mMinF64, mMaxF64,
mAddU, mSubU, mMulU, mDivU, mModU,
mEqI, mLeI, mLtI,
mEqF64, mLeF64, mLtF64,
@@ -621,7 +620,7 @@ type
mXor, mEqCString, mEqProc,
mUnaryMinusI, mUnaryMinusI64, mAbsI, mNot,
mUnaryPlusI, mBitnotI,
mUnaryPlusF64, mUnaryMinusF64, mAbsF64,
mUnaryPlusF64, mUnaryMinusF64,
mCharToStr, mBoolToStr, mIntToStr, mInt64ToStr, mFloatToStr, mCStrToStr,
mStrToStr, mEnumToStr,
mAnd, mOr,
@@ -678,7 +677,6 @@ const
mAddF64, mSubF64, mMulF64, mDivF64,
mShrI, mShlI, mBitandI, mBitorI, mBitxorI,
mMinI, mMaxI,
mMinF64, mMaxF64,
mAddU, mSubU, mMulU, mDivU, mModU,
mEqI, mLeI, mLtI,
mEqF64, mLeF64, mLtF64,
@@ -689,7 +687,7 @@ const
mEqB, mLeB, mLtB,
mEqRef, mEqProc, mEqUntracedRef, mLePtr, mLtPtr, mEqCString, mXor,
mUnaryMinusI, mUnaryMinusI64, mAbsI, mNot, mUnaryPlusI, mBitnotI,
mUnaryPlusF64, mUnaryMinusF64, mAbsF64,
mUnaryPlusF64, mUnaryMinusF64,
mCharToStr, mBoolToStr, mIntToStr, mInt64ToStr, mFloatToStr, mCStrToStr,
mStrToStr, mEnumToStr,
mAnd, mOr,

View File

@@ -77,7 +77,6 @@ proc idNodeTablePut*(t: var TIdNodeTable, key: PIdObj, val: PNode)
# ---------------------------------------------------------------------------
proc getSymFromList*(list: PNode, ident: PIdent, start: int = 0): PSym
proc lookupInRecord*(n: PNode, field: PIdent): PSym
proc mustRehash*(length, counter: int): bool
proc nextTry*(h, maxHash: Hash): Hash {.inline.}
@@ -174,7 +173,7 @@ proc getModule*(s: PSym): PSym =
assert((result.kind == skModule) or (result.owner != result))
while result != nil and result.kind != skModule: result = result.owner
proc getSymFromList(list: PNode, ident: PIdent, start: int = 0): PSym =
proc getSymFromList*(list: PNode, ident: PIdent, start: int = 0): PSym =
for i in start ..< sonsLen(list):
if list.sons[i].kind == nkSym:
result = list.sons[i].sym
@@ -182,6 +181,45 @@ proc getSymFromList(list: PNode, ident: PIdent, start: int = 0): PSym =
else: return nil
result = nil
proc sameIgnoreBacktickGensymInfo(a, b: string): bool =
if a[0] != b[0]: return false
var last = a.len - 1
while last > 0 and a[last] != '`': dec(last)
var i = 1
var j = 1
while true:
while i < last and a[i] == '_': inc i
while j < b.len and b[j] == '_': inc j
var aa = if i < last: toLowerAscii(a[i]) else: '\0'
var bb = if j < b.len: toLowerAscii(b[j]) else: '\0'
if aa != bb: return false
# the characters are identical:
if i >= last:
# both cursors at the end:
if j >= b.len: return true
# not yet at the end of 'b':
return false
elif j >= b.len:
return false
inc i
inc j
proc getNamedParamFromList*(list: PNode, ident: PIdent): PSym =
## Named parameters are special because a named parameter can be
## gensym'ed and then they have '`<number>' suffix that we need to
## ignore, see compiler / evaltempl.nim, snippet:
##
## .. code-block:: nim
##
## result.add newIdentNode(getIdent(c.ic, x.name.s & "`gensym" & $x.id),
## if c.instLines: actual.info else: templ.info)
for i in 1 ..< len(list):
let it = list[i].sym
if it.name.id == ident.id or
sameIgnoreBacktickGensymInfo(it.name.s, ident.s): return it
proc hashNode(p: RootRef): Hash =
result = hash(cast[pointer](p))

View File

@@ -588,8 +588,6 @@ proc binaryArith(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
of mBitxorI: applyFormat("($4)($1 ^ $2)")
of mMinI: applyFormat("(($1 <= $2) ? $1 : $2)")
of mMaxI: applyFormat("(($1 >= $2) ? $1 : $2)")
of mMinF64: applyFormat("(($1 <= $2) ? $1 : $2)")
of mMaxF64: applyFormat("(($1 >= $2) ? $1 : $2)")
of mAddU: applyFormat("($4)((NU$3)($1) + (NU$3)($2))")
of mSubU: applyFormat("($4)((NU$3)($1) - (NU$3)($2))")
of mMulU: applyFormat("($4)((NU$3)($1) * (NU$3)($2))")
@@ -663,9 +661,6 @@ proc unaryArith(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
applyFormat("$1")
of mUnaryMinusF64:
applyFormat("-($1)")
of mAbsF64:
applyFormat("($1 < 0? -($1) : ($1))")
# BUGFIX: fabs() makes problems for Tiny C
else:
assert false, $op
@@ -2086,7 +2081,7 @@ proc genEnumToStr(p: BProc, e: PNode, d: var TLoc) =
proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
case op
of mOr, mAnd: genAndOr(p, e, d, op)
of mNot..mAbsF64: unaryArith(p, e, d, op)
of mNot..mUnaryMinusF64: unaryArith(p, e, d, op)
of mUnaryMinusI..mAbsI: unaryArithOverflow(p, e, d, op)
of mAddF64..mDivF64: binaryFloatArith(p, e, d, op)
of mShrI..mXor: binaryArith(p, e, d, op)

View File

@@ -35,8 +35,8 @@ const
someMul = {mMulI, mMulF64}
someDiv = {mDivI, mDivF64}
someMod = {mModI}
someMax = {mMaxI, mMaxF64}
someMin = {mMinI, mMinF64}
someMax = {mMaxI}
someMin = {mMinI}
someBinaryOp = someAdd+someSub+someMul+someMax+someMin
proc isValue(n: PNode): bool = n.kind in {nkCharLit..nkNilLit}

View File

@@ -389,8 +389,6 @@ const # magic checked op; magic unchecked op;
["", ""], # BitxorI
["nimMin", "nimMin"], # MinI
["nimMax", "nimMax"], # MaxI
["nimMin", "nimMin"], # MinF64
["nimMax", "nimMax"], # MaxF64
["", ""], # addU
["", ""], # subU
["", ""], # mulU
@@ -430,7 +428,6 @@ const # magic checked op; magic unchecked op;
["", ""], # BitnotI
["", ""], # UnaryPlusF64
["", ""], # UnaryMinusF64
["", ""], # AbsF64
["nimCharToStr", "nimCharToStr"],
["nimBoolToStr", "nimBoolToStr"],
["cstrToNimstr", "cstrToNimstr"],
@@ -566,8 +563,6 @@ proc arithAux(p: PProc, n: PNode, r: var TCompRes, op: TMagic) =
of mBitxorI: applyFormat("($1 ^ $2)", "($1 ^ $2)")
of mMinI: applyFormat("nimMin($1, $2)", "nimMin($1, $2)")
of mMaxI: applyFormat("nimMax($1, $2)", "nimMax($1, $2)")
of mMinF64: applyFormat("nimMin($1, $2)", "nimMin($1, $2)")
of mMaxF64: applyFormat("nimMax($1, $2)", "nimMax($1, $2)")
of mAddU: applyFormat("", "")
of mSubU: applyFormat("", "")
of mMulU: applyFormat("", "")
@@ -607,7 +602,6 @@ proc arithAux(p: PProc, n: PNode, r: var TCompRes, op: TMagic) =
of mBitnotI: applyFormat("~($1)", "~($1)")
of mUnaryPlusF64: applyFormat("+($1)", "+($1)")
of mUnaryMinusF64: applyFormat("-($1)", "-($1)")
of mAbsF64: applyFormat("Math.abs($1)", "Math.abs($1)")
of mCharToStr: applyFormat("nimCharToStr($1)", "nimCharToStr($1)")
of mBoolToStr: applyFormat("nimBoolToStr($1)", "nimBoolToStr($1)")
of mIntToStr: applyFormat("cstrToNimstr(($1)+\"\")", "cstrToNimstr(($1)+\"\")")

View File

@@ -224,14 +224,14 @@ proc isAssignable*(owner: PSym, n: PNode; isUnsafeAddr=false): TAssignableResult
result = arLocalLValue
else:
result = arLValue
elif n.sym.kind == skParam and n.sym.typ.kind == tyVar:
elif n.sym.kind == skParam and n.sym.typ.kind in {tyVar, tySink}:
result = arLValue
elif n.sym.kind == skType:
let t = n.sym.typ.skipTypes({tyTypeDesc})
if t.kind == tyVar: result = arStrange
of nkDotExpr:
let t = skipTypes(n.sons[0].typ, abstractInst-{tyTypeDesc})
if t.kind in {tyVar, tyPtr, tyRef}:
if t.kind in {tyVar, tySink, tyPtr, tyRef}:
result = arLValue
elif isUnsafeAddr and t.kind == tyLent:
result = arLValue
@@ -242,7 +242,7 @@ proc isAssignable*(owner: PSym, n: PNode; isUnsafeAddr=false): TAssignableResult
result = arDiscriminant
of nkBracketExpr:
let t = skipTypes(n.sons[0].typ, abstractInst-{tyTypeDesc})
if t.kind in {tyVar, tyPtr, tyRef}:
if t.kind in {tyVar, tySink, tyPtr, tyRef}:
result = arLValue
elif isUnsafeAddr and t.kind == tyLent:
result = arLValue

View File

@@ -197,7 +197,6 @@ proc evalOp(m: TMagic, n, a, b, c: PNode; g: ModuleGraph): PNode =
result = newIntNodeT(toInt128(sonsLen(a)), n, g)
of mUnaryPlusI, mUnaryPlusF64: result = a # throw `+` away
# XXX: Hides overflow/underflow
of mAbsF64: result = newFloatNodeT(abs(getFloat(a)), n, g)
of mAbsI: result = foldAbs(getInt(a), n, g)
of mUnaryLt: result = foldSub(getOrdValue(a), One, n, g)
of mSucc: result = foldAdd(getOrdValue(a), getInt(b), n, g)
@@ -277,12 +276,6 @@ proc evalOp(m: TMagic, n, a, b, c: PNode; g: ModuleGraph): PNode =
of mMulF64: result = newFloatNodeT(getFloat(a) * getFloat(b), n, g)
of mDivF64:
result = newFloatNodeT(getFloat(a) / getFloat(b), n, g)
of mMaxF64:
if getFloat(a) > getFloat(b): result = newFloatNodeT(getFloat(a), n, g)
else: result = newFloatNodeT(getFloat(b), n, g)
of mMinF64:
if getFloat(a) > getFloat(b): result = newFloatNodeT(getFloat(b), n, g)
else: result = newFloatNodeT(getFloat(a), n, g)
of mIsNil: result = newIntNodeT(ord(a.kind == nkNilLit), n, g)
of mLtI, mLtB, mLtEnum, mLtCh:
result = newIntNodeT(ord(getOrdValue(a) < getOrdValue(b)), n, g)

View File

@@ -80,6 +80,7 @@ proc symChoice(c: PContext, n: PNode, s: PSym, r: TSymChoiceRule;
while a != nil:
if a.kind != skModule and (not isField or sfGenSym notin s.flags):
incl(a.flags, sfUsed)
markOwnerModuleAsUsed(c, a)
addSon(result, newSymNode(a, info))
onUse(info, a)
a = nextOverloadIter(o, c, n)

View File

@@ -108,6 +108,7 @@ const
isNilConversion = isConvertible # maybe 'isIntConv' fits better?
proc markUsed*(c: PContext; info: TLineInfo, s: PSym)
proc markOwnerModuleAsUsed*(c: PContext; s: PSym)
template hasFauxMatch*(c: TCandidate): bool = c.fauxMatch != tyNone
@@ -380,7 +381,7 @@ proc handleRange(f, a: PType, min, max: TTypeKind): TTypeRelation =
isIntLit(ab) and getInt(ab.n) >= firstOrd(nil, f) and
getInt(ab.n) <= lastOrd(nil, f):
# passing 'nil' to firstOrd/lastOrd here as type checking rules should
# not depent on the target integer size configurations!
# not depend on the target integer size configurations!
# integer literal in the proper range; we want ``i16 + 4`` to stay an
# ``int16`` operation so we declare the ``4`` pseudo-equal to int16
result = isFromIntLit
@@ -396,7 +397,7 @@ proc handleRange(f, a: PType, min, max: TTypeKind): TTypeRelation =
f.kind in {tyUInt8..tyUInt32} and a[0].kind in {tyUInt8..tyInt32}) and
a.n[0].intVal >= firstOrd(nil, f) and a.n[1].intVal <= lastOrd(nil, f):
# passing 'nil' to firstOrd/lastOrd here as type checking rules should
# not depent on the target integer size configurations!
# not depend on the target integer size configurations!
result = isConvertible
else: result = isNone
@@ -408,13 +409,13 @@ proc isConvertibleToRange(f, a: PType): bool =
of tyInt16: result = isIntLit(a) or a.kind in {tyInt8, tyInt16}
of tyInt32: result = isIntLit(a) or a.kind in {tyInt8, tyInt16, tyInt32}
# This is wrong, but seems like there's a lot of code that relies on it :(
of tyInt: result = true
of tyInt, tyUInt, tyUInt64: result = true
of tyInt64: result = isIntLit(a) or a.kind in {tyInt8, tyInt16, tyInt32, tyInt, tyInt64}
of tyUInt8: result = isIntLit(a) or a.kind in {tyUInt8}
of tyUInt16: result = isIntLit(a) or a.kind in {tyUInt8, tyUInt16}
of tyUInt32: result = isIntLit(a) or a.kind in {tyUInt8, tyUInt16, tyUInt32}
of tyUInt: result = isIntLit(a) or a.kind in {tyUInt8, tyUInt16, tyUInt32, tyUInt}
of tyUInt64: result = isIntLit(a) or a.kind in {tyUInt8, tyUInt16, tyUInt32, tyUInt, tyUInt64}
#of tyUInt: result = isIntLit(a) or a.kind in {tyUInt8, tyUInt16, tyUInt32, tyUInt}
#of tyUInt64: result = isIntLit(a) or a.kind in {tyUInt8, tyUInt16, tyUInt32, tyUInt, tyUInt64}
else: result = false
elif f.kind in {tyFloat..tyFloat128}:
# `isIntLit` is correct and should be used above as well, see PR:
@@ -2362,7 +2363,7 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
localError(c.config, n.sons[a].info, "named parameter has to be an identifier")
noMatch()
return
formal = getSymFromList(m.callee.n, n.sons[a].sons[0].ident, 1)
formal = getNamedParamFromList(m.callee.n, n.sons[a].sons[0].ident)
if formal == nil:
# no error message!
noMatch()

View File

@@ -1309,7 +1309,7 @@ proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind,
tyNone, tyForward, tyFromExpr:
result = t
of tyNil:
if kind != skConst and kind != skParam and kind != skResult: result = t
if kind != skConst and kind != skParam: result = t
of tyString, tyBool, tyChar, tyEnum, tyInt..tyUInt64, tyCString, tyPointer:
result = nil
of tyOrdinal:

View File

@@ -1288,7 +1288,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
if dest < 0: dest = c.getTemp(n.typ)
c.gABC(n, opcCallSite, dest)
of mNGenSym: genBinaryABC(c, n, dest, opcGenSym)
of mMinI, mMaxI, mAbsF64, mMinF64, mMaxF64, mAbsI, mDotDot:
of mMinI, mMaxI, mAbsI, mDotDot:
c.genCall(n, dest)
of mExpandToAst:
if n.len != 2:

View File

@@ -14,6 +14,9 @@
when not defined(profiler) and not defined(memProfiler):
{.error: "Profiling support is turned off! Enable profiling by passing `--profiler:on --stackTrace:on` to the compiler (see the Nim Compiler User Guide for more options).".}
when defined(nimHasUsed):
{.used.}
# We don't want to profile the profiling code ...
{.push profiler: off.}

View File

@@ -2880,17 +2880,21 @@ proc max*[T](x: openArray[T]): T =
for i in 1..high(x):
if result < x[i]: result = x[i]
proc abs*(x: float): float {.magic: "AbsF64", noSideEffect.} =
proc abs*(x: float64): float64 {.noSideEffect, inline.} =
if x < 0.0: -x else: x
proc min*(x, y: float): float {.magic: "MinF64", noSideEffect.} =
proc abs*(x: float32): float32 {.noSideEffect, inline.} =
if x < 0.0: -x else: x
proc min*(x, y: float32): float32 {.noSideEffect, inline.} =
if x <= y or y != y: x else: y
proc min*(x, y: float64): float64 {.noSideEffect, inline.} =
if x <= y or y != y: x else: y
proc max*(x, y: float32): float32 {.noSideEffect, inline.} =
if y <= x or y != y: x else: y
proc max*(x, y: float64): float64 {.noSideEffect, inline.} =
if y <= x or y != y: x else: y
proc min*[T: not SomeFloat](x, y: T): T {.inline.} =
if x <= y: x else: y
proc max*(x, y: float): float {.magic: "MaxF64", noSideEffect.} =
if y <= x: x else: y
proc min*[T](x, y: T): T {.inline.}=
if x <= y: x else: y
proc max*[T](x, y: T): T {.inline.}=
proc max*[T: not SomeFloat](x, y: T): T {.inline.} =
if y <= x: x else: y
{.pop.}

View File

@@ -13,6 +13,3 @@ f3(typeof(nil))
proc f4[T](_: T) = discard
f4(nil)
proc f5(): typeof(nil) = nil
discard f5()

View File

@@ -85,3 +85,16 @@ testWrongAt()
let (a, d) = allocCounters()
discard cprintf("%ld new: %ld\n", a - unpairedEnvAllocs() - d, allocs)
#-------------------------------------------------
type
Table[A, B] = object
x: seq[(A, B)]
proc toTable[A,B](p: sink openArray[(A, B)]): Table[A, B] =
for zz in mitems(p):
result.x.add move(zz)
let table = {"a": new(int)}.toTable()

View File

@@ -136,3 +136,9 @@ block:
const x11: range[0'f..1'f] = 2'f
reject:
const x12: range[0'f..1'f] = 2
# ensure unsigned array indexing is remains lenient:
var a: array[4'u, string]
for i in 0..<a.len:
a[i] = "foo"

View File

@@ -160,7 +160,6 @@ block: # `$`*[T: tuple|object](x: T)
doAssert $Foo(x:2) == "(x: 2, x2: 0.0)"
doAssert $() == "()"
# this is a call indirection to prevent `toInt` to be resolved at compile time.
proc testToInt(arg: float64, a: int, b: BiggestInt) =
doAssert toInt(arg) == a
@@ -174,3 +173,14 @@ testToInt(13.37, 13, 13) # should round towards 0
testToInt(-13.37, -13, -13) # should round towards 0
testToInt(7.8, 8, 8) # should round away from 0
testToInt(-7.8, -8, -8) # should round away from 0
# test min/max for correct NaN handling
proc testMinMax(a,b: float32) =
doAssert max(float32(a),float32(b)) == 0'f32
doAssert min(float32(a),float32(b)) == 0'f32
doAssert max(float64(a),float64(b)) == 0'f64
doAssert min(float64(a),float64(b)) == 0'f64
testMinMax(0.0, NaN)
testMinMax(NaN, 0.0)

View File

@@ -9,6 +9,11 @@ output: '''
2
3
wth
3
2
1
0
(total: 6)
'''
"""
# bug #1915
@@ -145,3 +150,17 @@ macro m(): untyped =
let meh = m()
meh("wth")
macro foo(body: untyped): untyped =
result = body
template baz(): untyped =
foo:
proc bar2(b: int): int =
echo b
if b > 0: b + bar2(b = b - 1)
else: 0
echo (total: bar2(3))
baz()