summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--changelog.md11
-rw-r--r--compiler/ast.nim3
-rw-r--r--compiler/ccgstmts.nim2
-rw-r--r--compiler/options.nim3
-rw-r--r--compiler/semfold.nim20
-rw-r--r--compiler/semgnrc.nim2
-rw-r--r--compiler/semstmts.nim2
-rw-r--r--compiler/semtypes.nim2
-rw-r--r--doc/manual/types.txt1
-rw-r--r--lib/impure/db_postgres.nim26
-rw-r--r--lib/impure/db_sqlite.nim2
-rw-r--r--lib/pure/mersenne.nim2
-rw-r--r--lib/pure/strscans.nim4
-rw-r--r--lib/system.nim109
-rw-r--r--lib/system/excpt.nim21
-rw-r--r--tests/arithm/tsubrange.nim2
16 files changed, 138 insertions, 74 deletions
diff --git a/changelog.md b/changelog.md
index 3fdb009ca..77e5a29b5 100644
--- a/changelog.md
+++ b/changelog.md
@@ -63,3 +63,14 @@ This now needs to be written as:
 .. code-block:: nim
 
   t[ti] = (if exp_negative: '-' else: '+'); inc(ti)
+
+- To make Nim even more robust the system iterators ``..`` and ``countup``
+  now only accept a single generic type ``T``. This means the following code
+  doesn't die with an "out of range" error anymore:
+
+.. code-block:: nim
+
+  var b = 5.Natural
+  var a = -5
+  for i in a..b:
+    echo i
diff --git a/compiler/ast.nim b/compiler/ast.nim
index 176c2edca..f48ecab34 100644
--- a/compiler/ast.nim
+++ b/compiler/ast.nim
@@ -744,6 +744,8 @@ type
     OnUnknown,                # location is unknown (stack, heap or static)
     OnStatic,                 # in a static section
     OnStack,                  # location is on hardware stack
+    OnStackShadowDup,         # location is on the stack but also replicated
+                              # on the shadow stack
     OnHeap                    # location is on heap or global
                               # (reference counting needed)
   TLocFlags* = set[TLocFlag]
@@ -753,6 +755,7 @@ type
     flags*: TLocFlags         # location's flags
     lode*: PNode              # Node where the location came from; can be faked
     r*: Rope                  # rope value of location (code generators)
+    dup*: Rope                # duplicated location for precise stack scans
 
   # ---------------- end of backend information ------------------------------
 
diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim
index 9682a0e86..24a376dec 100644
--- a/compiler/ccgstmts.nim
+++ b/compiler/ccgstmts.nim
@@ -165,7 +165,7 @@ proc genGotoState(p: BProc, n: PNode) =
     statesCounter = n[1].intVal
   let prefix = if n.len == 3 and n[2].kind == nkStrLit: n[2].strVal.rope
                else: rope"STATE"
-  for i in 0 .. statesCounter:
+  for i in 0i64 .. statesCounter:
     lineF(p, cpsStmts, "case $2: goto $1$2;$n", [prefix, rope(i)])
   lineF(p, cpsStmts, "}$n", [])
 
diff --git a/compiler/options.nim b/compiler/options.nim
index 86e6006d7..312e4539a 100644
--- a/compiler/options.nim
+++ b/compiler/options.nim
@@ -141,13 +141,14 @@ var
   gEvalExpr* = ""             # expression for idetools --eval
   gLastCmdTime*: float        # when caas is enabled, we measure each command
   gListFullPaths*: bool
-  isServing*: bool = false
+  gPreciseStack*: bool = false
   gNoNimblePath* = false
   gExperimentalMode*: bool
   newDestructors*: bool
 
 proc importantComments*(): bool {.inline.} = gCmd in {cmdDoc, cmdIdeTools}
 proc usesNativeGC*(): bool {.inline.} = gSelectedGC >= gcRefc
+template preciseStack*(): bool = gPreciseStack
 
 template compilationCachePresent*: untyped =
   {optCaasEnabled, optSymbolFiles} * gGlobalOptions != {}
diff --git a/compiler/semfold.nim b/compiler/semfold.nim
index d2824d1a6..089e66abd 100644
--- a/compiler/semfold.nim
+++ b/compiler/semfold.nim
@@ -92,26 +92,6 @@ proc pickIntRange(a, b: PType): PType =
 proc isIntRangeOrLit(t: PType): bool =
   result = isIntRange(t) or isIntLit(t)
 
-proc pickMinInt(n: PNode): BiggestInt =
-  if n.kind in {nkIntLit..nkUInt64Lit}:
-    result = n.intVal
-  elif isIntLit(n.typ):
-    result = n.typ.n.intVal
-  elif isIntRange(n.typ):
-    result = firstOrd(n.typ)
-  else:
-    internalError(n.info, "pickMinInt")
-
-proc pickMaxInt(n: PNode): BiggestInt =
-  if n.kind in {nkIntLit..nkUInt64Lit}:
-    result = n.intVal
-  elif isIntLit(n.typ):
-    result = n.typ.n.intVal
-  elif isIntRange(n.typ):
-    result = lastOrd(n.typ)
-  else:
-    internalError(n.info, "pickMaxInt")
-
 proc makeRange(typ: PType, first, last: BiggestInt): PType =
   let minA = min(first, last)
   let maxA = max(first, last)
diff --git a/compiler/semgnrc.nim b/compiler/semgnrc.nim
index e28a7851f..da2c6fe7f 100644
--- a/compiler/semgnrc.nim
+++ b/compiler/semgnrc.nim
@@ -210,7 +210,7 @@ proc semGenericStmt(c: PContext, n: PNode,
         considerQuotedIdent(fn).id notin ctx.toMixin:
       errorUndeclaredIdentifier(c, n.info, fn.renderTree)
 
-    var first = ord(withinConcept in flags)
+    var first = int ord(withinConcept in flags)
     var mixinContext = false
     if s != nil:
       incl(s.flags, sfUsed)
diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim
index 80fad3f23..c1bf3662f 100644
--- a/compiler/semstmts.nim
+++ b/compiler/semstmts.nim
@@ -1006,7 +1006,7 @@ proc checkForMetaFields(n: PNode) =
     case t.kind
     of tySequence, tySet, tyArray, tyOpenArray, tyVar, tyPtr, tyRef,
        tyProc, tyGenericInvocation, tyGenericInst, tyAlias:
-      let start = ord(t.kind in {tyGenericInvocation, tyGenericInst})
+      let start = int ord(t.kind in {tyGenericInvocation, tyGenericInst})
       for i in start ..< t.sons.len:
         checkMeta(t.sons[i])
     else:
diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim
index 8c4ad81ad..92a36857a 100644
--- a/compiler/semtypes.nim
+++ b/compiler/semtypes.nim
@@ -138,7 +138,7 @@ proc semAnyRef(c: PContext; n: PNode; kind: TTypeKind; prev: PType): PType =
   if n.len < 1:
     result = newConstraint(c, kind)
   else:
-    let isCall = ord(n.kind in nkCallKinds+{nkBracketExpr})
+    let isCall = int ord(n.kind in nkCallKinds+{nkBracketExpr})
     let n = if n[0].kind == nkBracket: n[0] else: n
     checkMinSonsLen(n, 1)
     var t = semTypeNode(c, n.lastSon, nil)
diff --git a/doc/manual/types.txt b/doc/manual/types.txt
index 8361ec1f2..56584f257 100644
--- a/doc/manual/types.txt
+++ b/doc/manual/types.txt
@@ -138,7 +138,6 @@ determined). Assignments from the base type to one of its subrange types
 A subrange type has the same size as its base type (``int`` in the example).
 
 
-
 Pre-defined floating point types
 --------------------------------
 
diff --git a/lib/impure/db_postgres.nim b/lib/impure/db_postgres.nim
index b0d3170f8..1459f0d7e 100644
--- a/lib/impure/db_postgres.nim
+++ b/lib/impure/db_postgres.nim
@@ -74,7 +74,7 @@ type
                        ## converted to nil.
   InstantRow* = object ## a handle that can be
     res: PPGresult     ## used to get a row's
-    line: int          ## column text on demand             
+    line: int          ## column text on demand
   SqlPrepared* = distinct string ## a identifier for the prepared queries
 {.deprecated: [TRow: Row, TDbConn: DbConn, TSqlPrepared: SqlPrepared].}
 
@@ -175,7 +175,7 @@ proc prepare*(db: DbConn; stmtName: string, query: SqlQuery;
   return SqlPrepared(stmtName)
 
 proc setRow(res: PPGresult, r: var Row, line, cols: int32) =
-  for col in 0..cols-1:
+  for col in 0'i32..cols-1:
     setLen(r[col], 0)
     let x = pqgetvalue(res, line, col)
     if x.isNil:
@@ -191,7 +191,7 @@ iterator fastRows*(db: DbConn, query: SqlQuery,
   var res = setupQuery(db, query, args)
   var L = pqnfields(res)
   var result = newRow(L)
-  for i in 0..pqntuples(res)-1:
+  for i in 0'i32..pqntuples(res)-1:
     setRow(res, result, i, L)
     yield result
   pqclear(res)
@@ -202,7 +202,7 @@ iterator fastRows*(db: DbConn, stmtName: SqlPrepared,
   var res = setupQuery(db, stmtName, args)
   var L = pqNfields(res)
   var result = newRow(L)
-  for i in 0..pqNtuples(res)-1:
+  for i in 0'i32..pqNtuples(res)-1:
     setRow(res, result, i, L)
     yield result
   pqClear(res)
@@ -213,7 +213,7 @@ iterator instantRows*(db: DbConn, query: SqlQuery,
   ## same as fastRows but returns a handle that can be used to get column text
   ## on demand using []. Returned handle is valid only within iterator body.
   var res = setupQuery(db, query, args)
-  for i in 0..pqNtuples(res)-1:
+  for i in 0'i32..pqNtuples(res)-1:
     yield InstantRow(res: res, line: i)
   pqClear(res)
 
@@ -223,7 +223,7 @@ iterator instantRows*(db: DbConn, stmtName: SqlPrepared,
   ## same as fastRows but returns a handle that can be used to get column text
   ## on demand using []. Returned handle is valid only within iterator body.
   var res = setupQuery(db, stmtName, args)
-  for i in 0..pqNtuples(res)-1:
+  for i in 0'i32..pqNtuples(res)-1:
     yield InstantRow(res: res, line: i)
   pqClear(res)
 
@@ -240,7 +240,7 @@ proc getColumnType(res: PPGresult, col: int) : DbType =
   of 21:   return DbType(kind: DbTypeKind.dbInt, name: "int2", size: 2)
   of 23:   return DbType(kind: DbTypeKind.dbInt, name: "int4", size: 4)
   of 20:   return DbType(kind: DbTypeKind.dbInt, name: "int8", size: 8)
-  of 1560: return DbType(kind: DbTypeKind.dbBit, name: "bit")  
+  of 1560: return DbType(kind: DbTypeKind.dbBit, name: "bit")
   of 1562: return DbType(kind: DbTypeKind.dbInt, name: "varbit")
 
   of 18:   return DbType(kind: DbTypeKind.dbFixedChar, name: "char")
@@ -254,7 +254,7 @@ proc getColumnType(res: PPGresult, col: int) : DbType =
   of 700: return DbType(kind: DbTypeKind.dbFloat, name: "float4")
   of 701: return DbType(kind: DbTypeKind.dbFloat, name: "float8")
 
-  of 790:  return DbType(kind: DbTypeKind.dbDecimal, name: "money")  
+  of 790:  return DbType(kind: DbTypeKind.dbDecimal, name: "money")
   of 1700: return DbType(kind: DbTypeKind.dbDecimal, name: "numeric")
 
   of 704:  return DbType(kind: DbTypeKind.dbTimeInterval, name: "tinterval")
@@ -277,12 +277,12 @@ proc getColumnType(res: PPGresult, col: int) : DbType =
   of 603: return DbType(kind: DbTypeKind.dbBox, name: "box")
   of 604: return DbType(kind: DbTypeKind.dbPolygon, name: "polygon")
   of 628: return DbType(kind: DbTypeKind.dbLine, name: "line")
-  of 718: return DbType(kind: DbTypeKind.dbCircle, name: "circle")  
+  of 718: return DbType(kind: DbTypeKind.dbCircle, name: "circle")
 
   of 650: return DbType(kind: DbTypeKind.dbInet, name: "cidr")
   of 829: return DbType(kind: DbTypeKind.dbMacAddress, name: "macaddr")
   of 869: return DbType(kind: DbTypeKind.dbInet, name: "inet")
-  
+
   of 2950: return DbType(kind: DbTypeKind.dbVarchar, name: "uuid")
   of 3614: return DbType(kind: DbTypeKind.dbVarchar, name: "tsvector")
   of 3615: return DbType(kind: DbTypeKind.dbVarchar, name: "tsquery")
@@ -364,11 +364,11 @@ proc getColumnType(res: PPGresult, col: int) : DbType =
 
 proc setColumnInfo(columns: var DbColumns; res: PPGresult; L: int32) =
   setLen(columns, L)
-  for i in 0..<L:
+  for i in 0'i32..<L:
     columns[i].name = $pqfname(res, i)
     columns[i].typ = getColumnType(res, i)
     columns[i].tableName = $(pqftable(res, i)) ## Returns the OID of the table from which the given column was fetched.
-                                               ## Query the system table pg_class to determine exactly which table is referenced.  
+                                               ## Query the system table pg_class to determine exactly which table is referenced.
     #columns[i].primaryKey = libpq does not have a function for that
     #columns[i].foreignKey = libpq does not have a function for that
 
@@ -377,7 +377,7 @@ iterator instantRows*(db: DbConn; columns: var DbColumns; query: SqlQuery;
                       {.tags: [ReadDbEffect].} =
   var res = setupQuery(db, query, args)
   setColumnInfo(columns, res, pqnfields(res))
-  for i in 0..<pqntuples(res):
+  for i in 0'i32..<pqntuples(res):
     yield InstantRow(res: res, line: i)
   pqClear(res)
 
diff --git a/lib/impure/db_sqlite.nim b/lib/impure/db_sqlite.nim
index 53dafdda7..21049571f 100644
--- a/lib/impure/db_sqlite.nim
+++ b/lib/impure/db_sqlite.nim
@@ -148,7 +148,7 @@ proc setupQuery(db: DbConn, query: SqlQuery,
   if prepare_v2(db, q, q.len.cint, result, nil) != SQLITE_OK: dbError(db)
 
 proc setRow(stmt: Pstmt, r: var Row, cols: cint) =
-  for col in 0..cols-1:
+  for col in 0'i32..cols-1:
     setLen(r[col], column_bytes(stmt, col)) # set capacity
     setLen(r[col], 0)
     let x = column_text(stmt, col)
diff --git a/lib/pure/mersenne.nim b/lib/pure/mersenne.nim
index f18cf5b90..6ac0c4e56 100644
--- a/lib/pure/mersenne.nim
+++ b/lib/pure/mersenne.nim
@@ -17,7 +17,7 @@ type
 proc newMersenneTwister*(seed: uint32): MersenneTwister =
   result.index = 0
   result.mt[0] = seed
-  for i in 1..623'u32:
+  for i in 1'u32 .. 623'u32:
     result.mt[i] = (0x6c078965'u32 * (result.mt[i-1] xor (result.mt[i-1] shr 30'u32)) + i)
 
 proc generateNumbers(m: var MersenneTwister) =
diff --git a/lib/pure/strscans.nim b/lib/pure/strscans.nim
index a54556915..f33e7451f 100644
--- a/lib/pure/strscans.nim
+++ b/lib/pure/strscans.nim
@@ -563,12 +563,12 @@ macro scanp*(input, idx: typed; pattern: varargs[untyped]): bool =
     of nnkCurlyExpr:
       if it.len == 3 and it[1].kind == nnkIntLit and it[2].kind == nnkIntLit:
         var h = newTree(nnkPar, it[0])
-        for count in 2..it[1].intVal: h.add(it[0])
+        for count in 2i64 .. it[1].intVal: h.add(it[0])
         for count in it[1].intVal .. it[2].intVal-1: h.add(newTree(nnkPrefix, ident"?", it[0]))
         result = atm(h, input, idx, attached)
       elif it.len == 2 and it[1].kind == nnkIntLit:
         var h = newTree(nnkPar, it[0])
-        for count in 2..it[1].intVal: h.add(it[0])
+        for count in 2i64 .. it[1].intVal: h.add(it[0])
         result = atm(h, input, idx, attached)
       else:
         error("invalid pattern")
diff --git a/lib/system.nim b/lib/system.nim
index c29a756ed..00dd00bc0 100644
--- a/lib/system.nim
+++ b/lib/system.nim
@@ -322,7 +322,7 @@ proc `..`*[T, U](a: T, b: U): HSlice[T, U] {.noSideEffect, inline, magic: "DotDo
   result.b = b
 
 proc `..`*[T](b: T): HSlice[int, T] {.noSideEffect, inline, magic: "DotDot".} =
-  ## `slice`:idx: operator that constructs an interval ``[default(T), b]``
+  ## `slice`:idx: operator that constructs an interval ``[default(int), b]``
   result.b = b
 
 when not defined(niminheritable):
@@ -1985,35 +1985,81 @@ iterator countdown*[T](a, b: T, step = 1): T {.inline.} =
       yield res
       dec(res, step)
 
-iterator countup*[S, T](a: S, b: T, step = 1): T {.inline.} =
-  ## Counts from ordinal value `a` up to `b` (inclusive) with the given
-  ## step count. `S`, `T` may be any ordinal type, `step` may only
-  ## be positive. **Note**: This fails to count to ``high(int)`` if T = int for
-  ## efficiency reasons.
-  when T is IntLikeForCount:
-    var res = int(a)
-    while res <= int(b):
-      yield T(res)
-      inc(res, step)
-  else:
-    var res: T = T(a)
+when defined(nimNewRoof):
+  iterator countup*[T](a, b: T, step = 1): T {.inline.} =
+    ## Counts from ordinal value `a` up to `b` (inclusive) with the given
+    ## step count. `S`, `T` may be any ordinal type, `step` may only
+    ## be positive. **Note**: This fails to count to ``high(int)`` if T = int for
+    ## efficiency reasons.
+    when T is IntLikeForCount:
+      var res = int(a)
+      while res <= int(b):
+        yield T(res)
+        inc(res, step)
+    else:
+      var res: T = T(a)
+      while res <= b:
+        yield res
+        inc(res, step)
+
+  iterator `..`*[T](a, b: T): T {.inline.} =
+    ## An alias for `countup`.
+    when T is IntLikeForCount:
+      var res = int(a)
+      while res <= int(b):
+        yield T(res)
+        inc(res)
+    else:
+      var res: T = T(a)
+      while res <= b:
+        yield res
+        inc(res)
+
+  iterator `..`*(a, b: int64): int64 {.inline.} =
+    ## A special version of ``..`` for ``int64`` only.
+    var res = a
     while res <= b:
       yield res
-      inc(res, step)
-
-iterator `..`*[S, T](a: S, b: T): T {.inline.} =
-  ## An alias for `countup`.
-  when T is IntLikeForCount:
-    var res = int(a)
-    while res <= int(b):
-      yield T(res)
       inc(res)
-  else:
-    var res: T = T(a)
+
+  iterator `..`*(a, b: int32): int32 {.inline.} =
+    ## A special version of ``..`` for ``int32`` only.
+    var res = a
     while res <= b:
       yield res
       inc(res)
 
+else:
+  iterator countup*[S, T](a: S, b: T, step = 1): T {.inline.} =
+    ## Counts from ordinal value `a` up to `b` (inclusive) with the given
+    ## step count. `S`, `T` may be any ordinal type, `step` may only
+    ## be positive. **Note**: This fails to count to ``high(int)`` if T = int for
+    ## efficiency reasons.
+    when T is IntLikeForCount:
+      var res = int(a)
+      while res <= int(b):
+        yield T(res)
+        inc(res, step)
+    else:
+      var res: T = T(a)
+      while res <= b:
+        yield res
+        inc(res, step)
+
+  iterator `..`*[S, T](a: S, b: T): T {.inline.} =
+    ## An alias for `countup`.
+    when T is IntLikeForCount:
+      var res = int(a)
+      while res <= int(b):
+        yield T(res)
+        inc(res)
+    else:
+      var res: T = T(a)
+      while res <= b:
+        yield res
+        inc(res)
+
+
 iterator `||`*[S, T](a: S, b: T, annotation=""): T {.
   inline, magic: "OmpParFor", sideEffect.} =
   ## parallel loop iterator. Same as `..` but the loop may run in parallel.
@@ -3433,11 +3479,18 @@ template `..<`*(a, b: untyped): untyped =
   ## a shortcut for 'a..pred(b)'.
   a .. pred(b)
 
-iterator `..<`*[S,T](a: S, b: T): T =
-  var i = T(a)
-  while i < b:
-    yield i
-    inc i
+when defined(nimNewRoof):
+  iterator `..<`*[T](a, b: T): T =
+    var i = T(a)
+    while i < b:
+      yield i
+      inc i
+else:
+  iterator `..<`*[S, T](a: S, b: T): T =
+    var i = T(a)
+    while i < b:
+      yield i
+      inc i
 
 template spliceImpl(s, a, L, b: untyped): untyped =
   # make room for additional elements or cut:
diff --git a/lib/system/excpt.nim b/lib/system/excpt.nim
index 950981227..f2b5997cc 100644
--- a/lib/system/excpt.nim
+++ b/lib/system/excpt.nim
@@ -38,20 +38,29 @@ proc chckRange(i, a, b: int): int {.inline, compilerproc, benign.}
 proc chckRangeF(x, a, b: float): float {.inline, compilerproc, benign.}
 proc chckNil(p: pointer) {.noinline, compilerproc, benign.}
 
+type
+  GcFrame = ptr GcFrameHeader
+  GcFrameHeader {.compilerproc.} = object
+    len: int
+    prev: ptr GcFrameHeader
+
 var
   framePtr {.threadvar.}: PFrame
   excHandler {.threadvar.}: PSafePoint
     # list of exception handlers
     # a global variable for the root of all try blocks
   currException {.threadvar.}: ref Exception
+  gcFramePtr {.threadvar.}: GcFrame
 
 type
-  FrameState = tuple[framePtr: PFrame, excHandler: PSafePoint, currException: ref Exception]
+  FrameState = tuple[gcFramePtr: GcFrame, framePtr: PFrame,
+                     excHandler: PSafePoint, currException: ref Exception]
 
 proc getFrameState*(): FrameState {.compilerRtl, inl.} =
-  return (framePtr, excHandler, currException)
+  return (gcFramePtr, framePtr, excHandler, currException)
 
 proc setFrameState*(state: FrameState) {.compilerRtl, inl.} =
+  gcFramePtr = state.gcFramePtr
   framePtr = state.framePtr
   excHandler = state.excHandler
   currException = state.currException
@@ -64,6 +73,14 @@ proc popFrame {.compilerRtl, inl.} =
 proc setFrame*(s: PFrame) {.compilerRtl, inl.} =
   framePtr = s
 
+proc getGcFrame*(): GcFrame {.compilerRtl, inl.} = gcFramePtr
+proc popGcFrame*() {.compilerRtl, inl.} = gcFramePtr = gcFramePtr.prev
+proc setGcFrame*(s: GcFrame) {.compilerRtl, inl.} = gcFramePtr = s
+proc pushGcFrame*(s: GcFrame) {.compilerRtl, inl.} =
+  s.prev = gcFramePtr
+  zeroMem(cast[pointer](cast[int](s)+%sizeof(GcFrameHeader)), s.len*sizeof(pointer))
+  gcFramePtr = s
+
 proc pushSafePoint(s: PSafePoint) {.compilerRtl, inl.} =
   s.hasRaiseAction = false
   s.prev = excHandler
diff --git a/tests/arithm/tsubrange.nim b/tests/arithm/tsubrange.nim
index 6c6daebe2..9d60dbd1a 100644
--- a/tests/arithm/tsubrange.nim
+++ b/tests/arithm/tsubrange.nim
@@ -10,4 +10,4 @@ var level: n16 = 1
 let maxLevel: n16 = 1
 
 level = min(level + 2, maxLevel)
-echo level
\ No newline at end of file
+echo level