summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--compiler/ast.nim1
-rw-r--r--compiler/ccgtypes.nim2
-rw-r--r--compiler/extccomp.nim25
-rw-r--r--compiler/pragmas.nim7
-rw-r--r--compiler/vm.nim2
-rw-r--r--compiler/vmgen.nim15
-rw-r--r--compiler/wordrecg.nim2
-rw-r--r--doc/manual/pragmas.txt18
-rw-r--r--examples/curlex.nim10
-rw-r--r--examples/filterex.nim2
-rw-r--r--examples/iupex1.nim37
-rw-r--r--lib/pure/ospaths.nim8
-rw-r--r--lib/pure/osproc.nim7
-rw-r--r--lib/pure/rationals.nim7
-rw-r--r--lib/pure/streams.nim11
-rw-r--r--lib/system.nim2
-rw-r--r--lib/system/alloc.nim11
-rw-r--r--tests/pragmas/tbitsize.nim22
-rw-r--r--tests/rational/trat_float.nim9
-rw-r--r--tests/rational/trat_init.nim10
-rw-r--r--tests/stdlib/tmemfiles2.nim2
-rw-r--r--tests/template/sunset.tmpl2
-rw-r--r--tests/testament/categories.nim4
-rw-r--r--tests/testament/tester.nim8
-rw-r--r--tests/vm/tsimpleglobals.nim16
-rw-r--r--tests/vm/twrongconst.nim2
-rw-r--r--tools/niminst/buildbat.tmpl2
-rw-r--r--tools/niminst/buildsh.tmpl2
-rw-r--r--tools/niminst/deinstall.tmpl2
-rw-r--r--tools/niminst/inno.tmpl2
-rw-r--r--tools/niminst/install.tmpl2
-rw-r--r--tools/niminst/makefile.tmpl2
-rw-r--r--tools/niminst/nsis.tmpl2
-rw-r--r--web/news.txt2
34 files changed, 161 insertions, 97 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim
index 4001e896e..25958f580 100644
--- a/compiler/ast.nim
+++ b/compiler/ast.nim
@@ -784,6 +784,7 @@ type
       tab*: TStrTable         # interface table for modules
     of skLet, skVar, skField, skForVar:
       guard*: PSym
+      bitsize*: int
     else: nil
     magic*: TMagic
     typ*: PType
diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim
index 84d02d1da..1ed9ce113 100644
--- a/compiler/ccgtypes.nim
+++ b/compiler/ccgtypes.nim
@@ -441,6 +441,8 @@ proc genRecordFieldsAux(m: BModule, n: PNode,
       elif fieldType.kind == tySequence:
         # we need to use a weak dependency here for trecursive_table.
         addf(result, "$1 $2;$n", [getTypeDescWeak(m, field.loc.t, check), sname])
+      elif field.bitsize != 0:
+        addf(result, "$1 $2:$3;$n", [getTypeDescAux(m, field.loc.t, check), sname, rope($field.bitsize)])
       else:
         # don't use fieldType here because we need the
         # tyGenericInst for C++ template support
diff --git a/compiler/extccomp.nim b/compiler/extccomp.nim
index 29aa03c94..3882bdd03 100644
--- a/compiler/extccomp.nim
+++ b/compiler/extccomp.nim
@@ -14,7 +14,7 @@
 
 import
   lists, ropes, os, strutils, osproc, platform, condsyms, options, msgs,
-  securehash
+  securehash, streams
 
 type
   TSystemCC* = enum
@@ -672,6 +672,12 @@ proc callCCompiler*(projectfile: string) =
   var prettyCmds: TStringSeq = @[]
   let prettyCb = proc (idx: int) =
     echo prettyCmds[idx]
+  let runCb = proc (idx: int, p: Process) =
+    let exitCode = p.peekExitCode
+    if exitCode != 0:
+      rawMessage(errGenerated, "execution of an external compiler program '" &
+        cmds[idx] & "' failed with exit code: " & $exitCode & "\n\n" &
+        p.outputStream.readAll.strip)
   compileCFile(toCompile, script, cmds, prettyCmds, false)
   compileCFile(externalToCompile, script, cmds, prettyCmds, true)
   if optCompileOnly notin gGlobalOptions:
@@ -682,22 +688,17 @@ proc callCCompiler*(projectfile: string) =
         res = execWithEcho(cmds[i])
         if res != 0: rawMessage(errExecutionOfProgramFailed, cmds[i])
     elif optListCmd in gGlobalOptions or gVerbosity > 1:
-      res = execProcesses(cmds, {poEchoCmd, poUsePath, poParentStreams},
-                          gNumberOfProcessors)
+      res = execProcesses(cmds, {poEchoCmd, poStdErrToStdOut, poUsePath, poParentStreams},
+                          gNumberOfProcessors, afterRunEvent=runCb)
     elif gVerbosity == 1:
-      res = execProcesses(cmds, {poUsePath, poParentStreams},
-                          gNumberOfProcessors, prettyCb)
+      res = execProcesses(cmds, {poStdErrToStdOut, poUsePath, poParentStreams},
+                          gNumberOfProcessors, prettyCb, afterRunEvent=runCb)
     else:
-      res = execProcesses(cmds, {poUsePath, poParentStreams},
-                          gNumberOfProcessors)
+      res = execProcesses(cmds, {poStdErrToStdOut, poUsePath, poParentStreams},
+                          gNumberOfProcessors, afterRunEvent=runCb)
     if res != 0:
       if gNumberOfProcessors <= 1:
         rawMessage(errExecutionOfProgramFailed, cmds.join())
-      else:
-        rawMessage(errGenerated,
-                   " execution of an external compiler program failed: " &
-                   cmds.join() & "; " &
-                   "rerun with --parallelBuild:1 to see the error message")
   if optNoLinking notin gGlobalOptions:
     # call the linker:
     var it = PStrEntry(toLink.head)
diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim
index 1c51251fe..ba05b2792 100644
--- a/compiler/pragmas.nim
+++ b/compiler/pragmas.nim
@@ -56,7 +56,7 @@ const
     wInheritable, wGensym, wInject, wRequiresInit, wUnchecked, wUnion, wPacked,
     wBorrow, wGcSafe}
   fieldPragmas* = {wImportc, wExportc, wDeprecated, wExtern,
-    wImportCpp, wImportObjC, wError, wGuard}
+    wImportCpp, wImportObjC, wError, wGuard, wBitsize}
   varPragmas* = {wImportc, wExportc, wVolatile, wRegister, wThreadVar, wNodecl,
     wMagic, wHeader, wDeprecated, wCompilerproc, wDynlib, wExtern,
     wImportCpp, wImportObjC, wError, wNoInit, wCompileTime, wGlobal,
@@ -844,6 +844,11 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
         if sym == nil: pragmaLockStmt(c, it)
         elif sym.typ == nil: invalidPragma(it)
         else: sym.typ.lockLevel = pragmaLocks(c, it)
+      of wBitsize:
+        if sym == nil or sym.kind != skField or it.kind != nkExprColonExpr:
+          invalidPragma(it)
+        else:
+          sym.bitsize = expectIntLit(c, it)
       of wGuard:
         if sym == nil or sym.kind notin {skVar, skLet, skField}:
           invalidPragma(it)
diff --git a/compiler/vm.nim b/compiler/vm.nim
index 4dd3b5232..ad4aa1017 100644
--- a/compiler/vm.nim
+++ b/compiler/vm.nim
@@ -311,7 +311,7 @@ proc opConv*(dest: var TFullReg, src: TFullReg, desttyp, srctyp: PType): bool =
           if f.position == x:
             dest.node.strVal = if f.ast.isNil: f.name.s else: f.ast.strVal
             return
-        internalError("opConv for enum")
+        dest.node.strVal = styp.sym.name.s & " " & $x
     of tyInt..tyInt64:
       dest.node.strVal = $src.intVal
     of tyUInt..tyUInt64:
diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim
index 0559acc88..92db0d513 100644
--- a/compiler/vmgen.nim
+++ b/compiler/vmgen.nim
@@ -37,7 +37,7 @@ when hasFFI:
   import evalffi
 
 type
-  TGenFlag = enum gfNone, gfAddrOf
+  TGenFlag = enum gfAddrOf, gfFieldAccess
   TGenFlags = set[TGenFlag]
 
 proc debugInfo(info: TLineInfo): string =
@@ -535,7 +535,7 @@ proc genIndex(c: PCtx; n: PNode; arr: PType): TRegister =
 proc genAsgnPatch(c: PCtx; le: PNode, value: TRegister) =
   case le.kind
   of nkBracketExpr:
-    let dest = c.genx(le.sons[0], {gfAddrOf})
+    let dest = c.genx(le.sons[0], {gfAddrOf, gfFieldAccess})
     let idx = c.genIndex(le.sons[1], le.sons[0].typ)
     c.gABC(le, opcWrArr, dest, idx, value)
     c.freeTemp(dest)
@@ -543,7 +543,7 @@ proc genAsgnPatch(c: PCtx; le: PNode, value: TRegister) =
   of nkDotExpr, nkCheckedFieldExpr:
     # XXX field checks here
     let left = if le.kind == nkDotExpr: le else: le.sons[0]
-    let dest = c.genx(left.sons[0], {gfAddrOf})
+    let dest = c.genx(left.sons[0], {gfAddrOf, gfFieldAccess})
     let idx = genField(left.sons[1])
     c.gABC(left, opcWrObj, dest, idx, value)
     c.freeTemp(dest)
@@ -1216,7 +1216,7 @@ proc preventFalseAlias(c: PCtx; n: PNode; opc: TOpcode;
 proc genAsgn(c: PCtx; le, ri: PNode; requiresCopy: bool) =
   case le.kind
   of nkBracketExpr:
-    let dest = c.genx(le.sons[0], {gfAddrOf})
+    let dest = c.genx(le.sons[0], {gfAddrOf, gfFieldAccess})
     let idx = c.genIndex(le.sons[1], le.sons[0].typ)
     let tmp = c.genx(ri)
     if le.sons[0].typ.skipTypes(abstractVarRange-{tyTypeDesc}).kind in {
@@ -1228,7 +1228,7 @@ proc genAsgn(c: PCtx; le, ri: PNode; requiresCopy: bool) =
   of nkDotExpr, nkCheckedFieldExpr:
     # XXX field checks here
     let left = if le.kind == nkDotExpr: le else: le.sons[0]
-    let dest = c.genx(left.sons[0], {gfAddrOf})
+    let dest = c.genx(left.sons[0], {gfAddrOf, gfFieldAccess})
     let idx = genField(left.sons[1])
     let tmp = c.genx(ri)
     c.preventFalseAlias(left, opcWrObj, dest, idx, tmp)
@@ -1321,7 +1321,7 @@ proc genRdVar(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags) =
       c.gABx(n, opcLdGlobal, cc, s.position)
       c.gABC(n, opcNodeToReg, dest, cc)
       c.freeTemp(cc)
-    elif gfAddrOf in flags:
+    elif {gfAddrOf, gfFieldAccess} * flags == {gfAddrOf}:
       c.gABx(n, opcLdGlobalAddr, dest, s.position)
     else:
       c.gABx(n, opcLdGlobal, dest, s.position)
@@ -1773,6 +1773,9 @@ proc genExpr*(c: PCtx; n: PNode, requiresValue = true): int =
     d = 0
   c.gABC(n, opcEof, d)
 
+  #echo renderTree(n)
+  #c.echoCode(result)
+
 proc genParams(c: PCtx; params: PNode) =
   # res.sym.position is already 0
   c.prc.slots[0] = (inUse: true, kind: slotFixedVar)
diff --git a/compiler/wordrecg.nim b/compiler/wordrecg.nim
index 23f012ea5..d1e5438f3 100644
--- a/compiler/wordrecg.nim
+++ b/compiler/wordrecg.nim
@@ -82,6 +82,7 @@ type
     wStdIn, wStdOut, wStdErr,
 
     wInOut, wByCopy, wByRef, wOneWay,
+    wBitsize,
 
   TSpecialWords* = set[TSpecialWord]
 
@@ -168,6 +169,7 @@ const
     "stdin", "stdout", "stderr",
 
     "inout", "bycopy", "byref", "oneway",
+    "bitsize",
     ]
 
 proc findStr*(a: openArray[string], s: string): int =
diff --git a/doc/manual/pragmas.txt b/doc/manual/pragmas.txt
index 68a88f865..f89194c9a 100644
--- a/doc/manual/pragmas.txt
+++ b/doc/manual/pragmas.txt
@@ -531,6 +531,24 @@ Implementation Specific Pragmas
 This section describes additional pragmas that the current Nim implementation
 supports but which should not be seen as part of the language specification.
 
+Bitsize pragma
+--------------
+
+The ``bitsize`` pragma is for object field members. It declares the field as
+a bitfield in C/C++.
+
+.. code-block:: Nim
+  type
+    mybitfield = object
+      flag {.bitsize:1.}: cuint
+
+generates:
+
+.. code-block:: C
+  struct mybitfield {
+    unsigned int flag:1;
+  };
+
 
 Volatile pragma
 ---------------
diff --git a/examples/curlex.nim b/examples/curlex.nim
deleted file mode 100644
index 21786a6ee..000000000
--- a/examples/curlex.nim
+++ /dev/null
@@ -1,10 +0,0 @@
-import
-  libcurl
-
-var hCurl = easy_init()
-if hCurl != nil:
-  discard easy_setopt(hCurl, OPT_VERBOSE, true)
-  discard easy_setopt(hCurl, OPT_URL, "http://nim-lang.org/")
-  discard easy_perform(hCurl)
-  easy_cleanup(hCurl)
-
diff --git a/examples/filterex.nim b/examples/filterex.nim
index d9bfb6782..083945254 100644
--- a/examples/filterex.nim
+++ b/examples/filterex.nim
@@ -1,4 +1,4 @@
-#! stdtmpl | standard
+#? stdtmpl | standard
 #proc generateHTMLPage(title, currentTab, content: string,
 #                      tabs: openArray[string]): string =
 #  result = ""
diff --git a/examples/iupex1.nim b/examples/iupex1.nim
deleted file mode 100644
index f768fb23f..000000000
--- a/examples/iupex1.nim
+++ /dev/null
@@ -1,37 +0,0 @@
-# Example IUP program
-
-# iupTabs: Creates a iupTabs control.
-
-import iup
-
-discard iup.open(nil, nil)
-
-var vbox1 = iup.vbox(iup.label("Inside Tab A"), iup.button("Button A", ""), nil)
-var vbox2 = iup.vbox(iup.label("Inside Tab B"), iup.button("Button B", ""), nil)
-
-iup.setAttribute(vbox1, "TABTITLE", "Tab A")
-iup.setAttribute(vbox2, "TABTITLE", "Tab B")
-
-var tabs1 = iup.tabs(vbox1, vbox2, nil)
-
-vbox1 = iup.vbox(iup.label("Inside Tab C"), iup.button("Button C", ""), nil)
-vbox2 = iup.vbox(iup.label("Inside Tab D"), iup.button("Button D", ""), nil)
-
-iup.setAttribute(vbox1, "TABTITLE", "Tab C")
-iup.setAttribute(vbox2, "TABTITLE", "Tab D")
-
-var tabs2 = iup.tabs(vbox1, vbox2, nil)
-iup.setAttribute(tabs2, "TABTYPE", "LEFT")
-
-var box = iup.hbox(tabs1, tabs2, nil)
-iup.setAttribute(box, "MARGIN", "10x10")
-iup.setAttribute(box, "GAP", "10")
-
-var dlg = iup.dialog(box)
-iup.setAttribute(dlg, "TITLE", "iupTabs")
-iup.setAttribute(dlg, "SIZE", "200x100")
-
-discard showXY(dlg, IUP_CENTER, IUP_CENTER)
-discard mainLoop()
-close()
-
diff --git a/lib/pure/ospaths.nim b/lib/pure/ospaths.nim
index 99f6bcd4d..dcc710193 100644
--- a/lib/pure/ospaths.nim
+++ b/lib/pure/ospaths.nim
@@ -496,7 +496,7 @@ when defined(nimdoc) and not declared(os):
   proc existsFile(x: string): bool = discard
 
 when declared(getEnv) or defined(nimscript):
-  proc getHomeDir*(): string {.rtl, extern: "nos$1", tags: [ReadEnvEffect].} =
+  proc getHomeDir*(): string {.rtl, extern: "nos$1", tags: [ReadEnvEffect, ReadIOEffect].} =
     ## Returns the home directory of the current user.
     ##
     ## This proc is wrapped by the expandTilde proc for the convenience of
@@ -504,7 +504,7 @@ when declared(getEnv) or defined(nimscript):
     when defined(windows): return string(getEnv("USERPROFILE")) & "\\"
     else: return string(getEnv("HOME")) & "/"
 
-  proc getConfigDir*(): string {.rtl, extern: "nos$1", tags: [ReadEnvEffect].} =
+  proc getConfigDir*(): string {.rtl, extern: "nos$1", tags: [ReadEnvEffect, ReadIOEffect].} =
     ## Returns the config directory of the current user for applications.
     when defined(windows): return string(getEnv("APPDATA")) & "\\"
     else: return string(getEnv("HOME")) & "/.config/"
@@ -515,7 +515,7 @@ when declared(getEnv) or defined(nimscript):
     when defined(windows): return string(getEnv("TEMP")) & "\\"
     else: return "/tmp/"
 
-  proc expandTilde*(path: string): string {.tags: [ReadEnvEffect].} =
+  proc expandTilde*(path: string): string {.tags: [ReadEnvEffect, ReadIOEffect].} =
     ## Expands a path starting with ``~/`` to a full path.
     ##
     ## If `path` starts with the tilde character and is followed by `/` or `\\`
@@ -545,7 +545,7 @@ when declared(getEnv) or defined(nimscript):
           yield substr(s, first, last-1)
           inc(last)
 
-  proc findExe*(exe: string): string {.tags: [ReadDirEffect, ReadEnvEffect].} =
+  proc findExe*(exe: string): string {.tags: [ReadDirEffect, ReadEnvEffect, ReadIOEffect].} =
     ## Searches for `exe` in the current working directory and then
     ## in directories listed in the ``PATH`` environment variable.
     ## Returns "" if the `exe` cannot be found. On DOS-like platforms, `exe`
diff --git a/lib/pure/osproc.nim b/lib/pure/osproc.nim
index bc73f7119..c23126be9 100644
--- a/lib/pure/osproc.nim
+++ b/lib/pure/osproc.nim
@@ -248,7 +248,8 @@ proc countProcessors*(): int {.rtl, extern: "nosp$1".} =
 proc execProcesses*(cmds: openArray[string],
                     options = {poStdErrToStdOut, poParentStreams},
                     n = countProcessors(),
-                    beforeRunEvent: proc(idx: int) = nil): int
+                    beforeRunEvent: proc(idx: int) = nil,
+                    afterRunEvent: proc(idx: int, p: Process) = nil): int
                     {.rtl, extern: "nosp$1",
                     tags: [ExecIOEffect, TimeEffect, ReadEnvEffect, RootEffect]} =
   ## executes the commands `cmds` in parallel. Creates `n` processes
@@ -278,6 +279,7 @@ proc execProcesses*(cmds: openArray[string],
             err.add("\n")
           echo(err)
         result = max(waitForExit(q[r]), result)
+        if afterRunEvent != nil: afterRunEvent(r, q[r])
         if q[r] != nil: close(q[r])
         if beforeRunEvent != nil:
           beforeRunEvent(i)
@@ -291,6 +293,7 @@ proc execProcesses*(cmds: openArray[string],
           if not running(q[r]):
             #echo(outputStream(q[r]).readLine())
             result = max(waitForExit(q[r]), result)
+            if afterRunEvent != nil: afterRunEvent(r, q[r])
             if q[r] != nil: close(q[r])
             if beforeRunEvent != nil:
               beforeRunEvent(i)
@@ -299,6 +302,7 @@ proc execProcesses*(cmds: openArray[string],
             if i > high(cmds): break
     for j in 0..m-1:
       result = max(waitForExit(q[j]), result)
+      if afterRunEvent != nil: afterRunEvent(j, q[j])
       if q[j] != nil: close(q[j])
   else:
     for i in 0..high(cmds):
@@ -306,6 +310,7 @@ proc execProcesses*(cmds: openArray[string],
         beforeRunEvent(i)
       var p = startProcess(cmds[i], options=options + {poEvalCommand})
       result = max(waitForExit(p), result)
+      if afterRunEvent != nil: afterRunEvent(i, p)
       close(p)
 
 proc select*(readfds: var seq[Process], timeout = 500): int {.benign.}
diff --git a/lib/pure/rationals.nim b/lib/pure/rationals.nim
index 60d09c71a..7d9241412 100644
--- a/lib/pure/rationals.nim
+++ b/lib/pure/rationals.nim
@@ -18,8 +18,9 @@ type Rational*[T] = object
   ## a rational number, consisting of a numerator and denominator
   num*, den*: T
 
-proc initRational*[T](num, den: T): Rational[T] =
+proc initRational*[T:SomeInteger](num, den: T): Rational[T] =
   ## Create a new rational number.
+  assert(den != 0, "a denominator of zero value is invalid")
   result.num = num
   result.den = den
 
@@ -33,7 +34,7 @@ proc `$`*[T](x: Rational[T]): string =
   ## Turn a rational number into a string.
   result = $x.num & "/" & $x.den
 
-proc toRational*[T](x: T): Rational[T] =
+proc toRational*[T:SomeInteger](x: T): Rational[T] =
   ## Convert some integer `x` to a rational number.
   result.num = x
   result.den = 1
@@ -47,7 +48,7 @@ proc toInt*[T](x: Rational[T]): int =
   ## `x` does not contain an integer value.
   x.num div x.den
 
-proc reduce*[T](x: var Rational[T]) =
+proc reduce*[T:SomeInteger](x: var Rational[T]) =
   ## Reduce rational `x`.
   let common = gcd(x.num, x.den)
   if x.den > 0:
diff --git a/lib/pure/streams.nim b/lib/pure/streams.nim
index 68f31e9fe..38e91fee4 100644
--- a/lib/pure/streams.nim
+++ b/lib/pure/streams.nim
@@ -103,15 +103,16 @@ proc readData*(s: Stream, buffer: pointer, bufLen: int): int =
 
 proc readAll*(s: Stream): string =
   ## Reads all available data.
-  result = newString(1000)
+  const bufferSize = 1000
+  result = newString(bufferSize)
   var r = 0
   while true:
-    let readBytes = readData(s, addr(result[r]), 1000)
-    if readBytes < 1000:
+    let readBytes = readData(s, addr(result[r]), bufferSize)
+    if readBytes < bufferSize:
       setLen(result, r+readBytes)
       break
-    inc r, 1000
-    setLen(result, r+1000)
+    inc r, bufferSize
+    setLen(result, r+bufferSize)
 
 proc readData*(s, unused: Stream, buffer: pointer,
                bufLen: int): int {.deprecated.} =
diff --git a/lib/system.nim b/lib/system.nim
index 59d0d04b7..1d2ca6a9a 100644
--- a/lib/system.nim
+++ b/lib/system.nim
@@ -1256,7 +1256,7 @@ proc compileOption*(option, arg: string): bool {.
   ##     echo "compiled with optimization for size and uses Boehm's GC"
 
 const
-  hasThreadSupport = compileOption("threads")
+  hasThreadSupport = compileOption("threads") and not defined(nimscript)
   hasSharedHeap = defined(boehmgc) or defined(gogc) # don't share heaps; every thread has its own
   taintMode = compileOption("taintmode")
 
diff --git a/lib/system/alloc.nim b/lib/system/alloc.nim
index 13a10e46f..3a1d7b666 100644
--- a/lib/system/alloc.nim
+++ b/lib/system/alloc.nim
@@ -27,8 +27,11 @@ sysAssert(roundup(65, 8) == 72, "roundup broken 2")
 # some platforms have really weird unmap behaviour: unmap(blockStart, PageSize)
 # really frees the whole block. Happens for Linux/PowerPC for example. Amd64
 # and x86 are safe though; Windows is special because MEM_RELEASE can only be
-# used with a size of 0:
-const weirdUnmap = not (defined(amd64) or defined(i386)) or defined(windows)
+# used with a size of 0. We also allow unmapping to be turned off with
+# -d:nimAllocNoUnmap:
+const doNotUnmap = not (defined(amd64) or defined(i386)) or
+                   defined(windows) or defined(nimAllocNoUnmap)
+
 
 when defined(posix):
   const
@@ -478,7 +481,7 @@ proc freeBigChunk(a: var MemRegion, c: PBigChunk) =
           excl(a.chunkStarts, pageIndex(c))
           c = cast[PBigChunk](le)
 
-  if c.size < ChunkOsReturn or weirdUnmap:
+  if c.size < ChunkOsReturn or doNotUnmap:
     incl(a, a.chunkStarts, pageIndex(c))
     updatePrevSize(a, c, c.size)
     listAdd(a.freeChunksList, c)
@@ -762,7 +765,7 @@ proc deallocOsPages(a: var MemRegion) =
   # we free every 'ordinarily' allocated page by iterating over the page bits:
   for p in elements(a.chunkStarts):
     var page = cast[PChunk](p shl PageShift)
-    when not weirdUnmap:
+    when not doNotUnmap:
       var size = if page.size < PageSize: PageSize else: page.size
       osDeallocPages(page, size)
     else:
diff --git a/tests/pragmas/tbitsize.nim b/tests/pragmas/tbitsize.nim
new file mode 100644
index 000000000..7a44944d2
--- /dev/null
+++ b/tests/pragmas/tbitsize.nim
@@ -0,0 +1,22 @@
+discard """
+ccodeCheck: "\\i @'unsigned int flag:1;' .*"
+"""
+
+type
+  bits* = object
+    flag* {.bitsize: 1.}: cuint
+    opts* {.bitsize: 4.}: cint
+
+var
+  b: bits
+
+assert b.flag == 0
+b.flag = 1
+assert b.flag == 1
+b.flag = 2
+assert b.flag == 0
+
+b.opts = 7
+assert b.opts == 7
+b.opts = 9
+assert b.opts == -7
diff --git a/tests/rational/trat_float.nim b/tests/rational/trat_float.nim
new file mode 100644
index 000000000..24797c4a0
--- /dev/null
+++ b/tests/rational/trat_float.nim
@@ -0,0 +1,9 @@
+discard """
+  file: "trat_float.nim"
+  line: "9,19"
+  errormsg: '''type mismatch: got'''
+"""
+import rationals
+var
+  # this fails - no floats as num or den
+  r = initRational(1.0'f, 1.0'f)
diff --git a/tests/rational/trat_init.nim b/tests/rational/trat_init.nim
new file mode 100644
index 000000000..df29ff6e3
--- /dev/null
+++ b/tests/rational/trat_init.nim
@@ -0,0 +1,10 @@
+discard """
+  file: "trat_init.nim"
+  exitcode: "1"
+"""
+import rationals
+var
+  z = Rational[int](num: 0, den: 1)
+  o = initRational(num=1, den=1)
+  a = initRational(1, 2)
+  r = initRational(1, 0)  # this fails - no zero denominator
diff --git a/tests/stdlib/tmemfiles2.nim b/tests/stdlib/tmemfiles2.nim
index 28af3296a..026443e93 100644
--- a/tests/stdlib/tmemfiles2.nim
+++ b/tests/stdlib/tmemfiles2.nim
@@ -1,8 +1,10 @@
 discard """
   file: "tmemfiles2.nim"
+  disabled: true
   output: '''Full read size: 20
 Half read size: 10 Data: Hello'''
 """
+# doesn't work on windows. fmReadWrite doesn't create a file.
 import memfiles, os
 var
   mm, mm_full, mm_half: MemFile
diff --git a/tests/template/sunset.tmpl b/tests/template/sunset.tmpl
index 6475bac4e..465b12a5e 100644
--- a/tests/template/sunset.tmpl
+++ b/tests/template/sunset.tmpl
@@ -1,4 +1,4 @@
-#! stdtmpl
+#? stdtmpl
 #proc sunsetTemplate*(current, ticker, content: string,
 #                     tabs: openarray[array[0..1, string]]): string = 
 #  result = ""
diff --git a/tests/testament/categories.nim b/tests/testament/categories.nim
index 4de1edeee..afc4a616f 100644
--- a/tests/testament/categories.nim
+++ b/tests/testament/categories.nim
@@ -339,7 +339,7 @@ proc `&?.`(a, b: string): string =
   # candidate for the stdlib?
   result = if a.endswith(b): a else: a & b
 
-proc processCategory(r: var TResults, cat: Category, options: string) =
+proc processCategory(r: var TResults, cat: Category, options: string, fileGlob: string = "t*.nim") =
   case cat.string.normalize
   of "rodfiles":
     discard # Disabled for now
@@ -376,5 +376,5 @@ proc processCategory(r: var TResults, cat: Category, options: string) =
   of "nimble-all":
     testNimblePackages(r, cat, pfAll)
   else:
-    for name in os.walkFiles("tests" & DirSep &.? cat.string / "t*.nim"):
+    for name in os.walkFiles("tests" & DirSep &.? cat.string / fileGlob):
       testSpec r, makeTest(name, options, cat)
diff --git a/tests/testament/tester.nim b/tests/testament/tester.nim
index b138c9909..e52988682 100644
--- a/tests/testament/tester.nim
+++ b/tests/testament/tester.nim
@@ -23,6 +23,7 @@ const
 Command:
   all                         run all tests
   c|category <category>       run all the tests of a certain category
+  r|run <test>                run single test file
   html [commit]               generate $1 from the database; uses the latest
                               commit or a specific one (use -1 for the commit
                               before latest etc)
@@ -212,6 +213,8 @@ proc compilerOutputTests(test: TTest, given: var TSpec, expected: TSpec;
       expectedmsg = expected.nimout
       givenmsg = given.nimout.strip
       nimoutCheck(test, expectedmsg, given)
+  else:
+    givenmsg = given.nimout.strip
   if given.err == reSuccess: inc(r.passed)
   r.addResult(test, expectedmsg, givenmsg, given.err)
 
@@ -376,6 +379,11 @@ proc main() =
     var cat = Category(p.key)
     p.next
     processCategory(r, cat, p.cmdLineRest.string)
+  of "r", "run":
+    let (dir, file) = splitPath(p.key.string)
+    let (_, subdir) = splitPath(dir)
+    var cat = Category(subdir)
+    processCategory(r, cat, p.cmdLineRest.string, file)
   of "html":
     var commit = 0
     discard parseInt(p.cmdLineRest.string, commit)
diff --git a/tests/vm/tsimpleglobals.nim b/tests/vm/tsimpleglobals.nim
new file mode 100644
index 000000000..27bfdce50
--- /dev/null
+++ b/tests/vm/tsimpleglobals.nim
@@ -0,0 +1,16 @@
+discard """
+  msg: "abc xyz bb"
+"""
+
+# bug #2473
+type
+  Test = tuple[a,b: string]
+
+static:
+  var s:seq[Test] = @[(a:"a", b:"b")]
+  s[0] = (a:"aa", b:"bb")
+
+  var x: Test
+  x.a = "abc"
+  x.b = "xyz"
+  echo x.a, " ", x.b, " ", s[0].b
diff --git a/tests/vm/twrongconst.nim b/tests/vm/twrongconst.nim
index 68ab2757c..424ed080e 100644
--- a/tests/vm/twrongconst.nim
+++ b/tests/vm/twrongconst.nim
@@ -1,6 +1,6 @@
 discard """
   errormsg: "cannot evaluate at compile time: x"
-  line: 9
+  line: 7
 """
 
 var x: array[100, char]
diff --git a/tools/niminst/buildbat.tmpl b/tools/niminst/buildbat.tmpl
index 2c6a2b5a8..2a8da144d 100644
--- a/tools/niminst/buildbat.tmpl
+++ b/tools/niminst/buildbat.tmpl
@@ -1,4 +1,4 @@
-#! stdtmpl(subsChar='?') | standard
+#? stdtmpl(subsChar='?') | standard
 #proc generateBuildBatchScript(c: ConfigData, winIndex, cpuIndex: int): string = 
 #  result = "@echo off\nREM Generated by niminst\n"
 SET CC=gcc
diff --git a/tools/niminst/buildsh.tmpl b/tools/niminst/buildsh.tmpl
index 52da351be..463a1ad52 100644
--- a/tools/niminst/buildsh.tmpl
+++ b/tools/niminst/buildsh.tmpl
@@ -1,4 +1,4 @@
-#! stdtmpl(subsChar='?') | standard
+#? stdtmpl(subsChar='?') | standard
 #proc generateBuildShellScript(c: ConfigData): string = 
 #  result = "#! /bin/sh\n# Generated from niminst\n" &
 #           "# Template is in tools/niminst/buildsh.tmpl\n" &
diff --git a/tools/niminst/deinstall.tmpl b/tools/niminst/deinstall.tmpl
index c4717a257..7349abcb4 100644
--- a/tools/niminst/deinstall.tmpl
+++ b/tools/niminst/deinstall.tmpl
@@ -1,4 +1,4 @@
-#! stdtmpl(subsChar='?') | standard
+#? stdtmpl(subsChar='?') | standard
 #proc generateDeinstallScript(c: ConfigData): string = 
 #  result = "#! /bin/sh\n# Generated by niminst\n"
 #  var proj = c.name.toLower
diff --git a/tools/niminst/inno.tmpl b/tools/niminst/inno.tmpl
index 4acf0557c..ef2da8a75 100644
--- a/tools/niminst/inno.tmpl
+++ b/tools/niminst/inno.tmpl
@@ -1,4 +1,4 @@
-#! stdtmpl | standard
+#? stdtmpl | standard
 #proc generateInnoSetup(c: ConfigData): string =
 #  result = ""
 ; Default Template for NimInst
diff --git a/tools/niminst/install.tmpl b/tools/niminst/install.tmpl
index 3ec42c287..14d88e07d 100644
--- a/tools/niminst/install.tmpl
+++ b/tools/niminst/install.tmpl
@@ -1,4 +1,4 @@
-#! stdtmpl(subsChar = '?') | standard
+#? stdtmpl(subsChar = '?') | standard
 #proc generateInstallScript(c: ConfigData): string = 
 #  result = "#! /bin/sh\n# Generated by niminst\n"
 #  var proj = c.name.toLower
diff --git a/tools/niminst/makefile.tmpl b/tools/niminst/makefile.tmpl
index 8ab3b89d1..6615ddc02 100644
--- a/tools/niminst/makefile.tmpl
+++ b/tools/niminst/makefile.tmpl
@@ -1,4 +1,4 @@
-#! stdtmpl(subsChar='?') | standard
+#? stdtmpl(subsChar='?') | standard
 #proc generateMakefile(c: ConfigData): string = 
 #  result = "# Generated from niminst\n" &
 #           "# Template is in tools/niminst/makefile.tmpl\n" &
diff --git a/tools/niminst/nsis.tmpl b/tools/niminst/nsis.tmpl
index 843a8cf44..abf462388 100644
--- a/tools/niminst/nsis.tmpl
+++ b/tools/niminst/nsis.tmpl
@@ -1,4 +1,4 @@
-#! stdtmpl(subsChar='?') | standard
+#? stdtmpl(subsChar='?') | standard
 #proc generateNsisSetup(c: ConfigData): string =
 #  result = "; NSIS script generated by niminst\n" &
 #           "; To regenerate run ``niminst nsis`` or ``koch nsis``\n"
diff --git a/web/news.txt b/web/news.txt
index cfa40c65c..33ceac49e 100644
--- a/web/news.txt
+++ b/web/news.txt
@@ -108,6 +108,8 @@ News
   - The compiler finally considers symbol binding rules in templates and
     generics for overloaded ``[]``, ``[]=``, ``{}``, ``{}=`` operators
     (issue `#2599 <https://github.com/nim-lang/Nim/issues/2599>`_).
+  - The compiler now supports a `bitsize pragma <docs/manual.html#pragmas-bitsize-pragma>`_
+    for constructing bitfields.
 
 
   Language Additions