summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--compiler/ast.nim3
-rw-r--r--compiler/commands.nim178
-rw-r--r--compiler/msgs.nim2
-rw-r--r--compiler/pragmas.nim2
-rw-r--r--compiler/sempass2.nim50
-rw-r--r--compiler/semstmts.nim14
-rw-r--r--compiler/semtempl.nim2
-rw-r--r--compiler/sigmatch.nim3
-rw-r--r--lib/js/dom.nim170
-rw-r--r--lib/packages/docutils/rst.nim912
-rw-r--r--lib/packages/docutils/rstast.nim83
-rw-r--r--lib/posix/posix.nim3
-rw-r--r--lib/pure/collections/sets.nim349
-rw-r--r--lib/pure/json.nim43
-rw-r--r--lib/pure/math.nim7
-rw-r--r--lib/pure/osproc.nim2
-rw-r--r--lib/pure/rawsockets.nim2
-rw-r--r--lib/system.nim2
-rw-r--r--lib/system/alloc.nim4
-rw-r--r--lib/windows/windows.nim10
-rw-r--r--lib/wrappers/iup.nim228
-rw-r--r--tests/parallel/tgc_unsafe2.nim39
-rw-r--r--todo.txt1
23 files changed, 1116 insertions, 993 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim
index 10f2a71da..6e09916fe 100644
--- a/compiler/ast.nim
+++ b/compiler/ast.nim
@@ -728,7 +728,8 @@ type
       typScope*: PScope
     of routineKinds:
       procInstCache*: seq[PInstantiation]
-      scope*: PScope          # the scope where the proc was defined
+      gcUnsafetyReason*: PSym  # for better error messages wrt gcsafe
+      #scope*: PScope          # the scope where the proc was defined
     of skModule:
       # modules keep track of the generic symbols they use from other modules.
       # this is because in incremental compilation, when a module is about to
diff --git a/compiler/commands.nim b/compiler/commands.nim
index a2d02e469..69b1c1f1a 100644
--- a/compiler/commands.nim
+++ b/compiler/commands.nim
@@ -24,8 +24,8 @@ bootSwitch(usedMarkAndSweep, defined(gcmarkandsweep), "--gc:markAndSweep")
 bootSwitch(usedGenerational, defined(gcgenerational), "--gc:generational")
 bootSwitch(usedNoGC, defined(nogc), "--gc:none")
 
-import 
-  os, msgs, options, nversion, condsyms, strutils, extccomp, platform, lists, 
+import
+  os, msgs, options, nversion, condsyms, strutils, extccomp, platform, lists,
   wordrecg, parseutils, nimblecmd, idents, parseopt
 
 # but some have deps to imported modules. Yay.
@@ -39,8 +39,8 @@ bootSwitch(usedFFI, hasFFI, "-d:useFFI")
 
 proc writeCommandLineUsage*()
 
-type 
-  TCmdLinePass* = enum 
+type
+  TCmdLinePass* = enum
     passCmd1,                 # first pass over the command line
     passCmd2,                 # second pass over the command line
     passPP                    # preprocessor called processCommand()
@@ -54,30 +54,30 @@ const
   HelpMessage = "Nim Compiler Version $1 (" & CompileDate & ") [$2: $3]\n" &
       "Copyright (c) 2006-2015 by Andreas Rumpf\n"
 
-const 
+const
   Usage = slurp"doc/basicopt.txt".replace("//", "")
   AdvancedUsage = slurp"doc/advopt.txt".replace("//", "")
 
-proc getCommandLineDesc(): string = 
-  result = (HelpMessage % [VersionAsString, platform.OS[platform.hostOS].name, 
+proc getCommandLineDesc(): string =
+  result = (HelpMessage % [VersionAsString, platform.OS[platform.hostOS].name,
                            CPU[platform.hostCPU].name]) & Usage
 
-proc helpOnError(pass: TCmdLinePass) = 
+proc helpOnError(pass: TCmdLinePass) =
   if pass == passCmd1:
     msgWriteln(getCommandLineDesc())
     msgQuit(0)
 
-proc writeAdvancedUsage(pass: TCmdLinePass) = 
+proc writeAdvancedUsage(pass: TCmdLinePass) =
   if pass == passCmd1:
-    msgWriteln(`%`(HelpMessage, [VersionAsString, 
-                                 platform.OS[platform.hostOS].name, 
+    msgWriteln(`%`(HelpMessage, [VersionAsString,
+                                 platform.OS[platform.hostOS].name,
                                  CPU[platform.hostCPU].name]) & AdvancedUsage)
     msgQuit(0)
 
-proc writeVersionInfo(pass: TCmdLinePass) = 
+proc writeVersionInfo(pass: TCmdLinePass) =
   if pass == passCmd1:
-    msgWriteln(`%`(HelpMessage, [VersionAsString, 
-                                 platform.OS[platform.hostOS].name, 
+    msgWriteln(`%`(HelpMessage, [VersionAsString,
+                                 platform.OS[platform.hostOS].name,
                                  CPU[platform.hostCPU].name]))
 
     discard """const gitHash = gorge("git log -n 1 --format=%H")
@@ -92,8 +92,8 @@ proc writeVersionInfo(pass: TCmdLinePass) =
 var
   helpWritten: bool
 
-proc writeCommandLineUsage() = 
-  if not helpWritten: 
+proc writeCommandLineUsage() =
+  if not helpWritten:
     msgWriteln(getCommandLineDesc())
     helpWritten = true
 
@@ -101,51 +101,51 @@ proc addPrefix(switch: string): string =
   if len(switch) == 1: result = "-" & switch
   else: result = "--" & switch
 
-proc invalidCmdLineOption(pass: TCmdLinePass, switch: string, info: TLineInfo) = 
+proc invalidCmdLineOption(pass: TCmdLinePass, switch: string, info: TLineInfo) =
   if switch == " ": localError(info, errInvalidCmdLineOption, "-")
   else: localError(info, errInvalidCmdLineOption, addPrefix(switch))
 
-proc splitSwitch(switch: string, cmd, arg: var string, pass: TCmdLinePass, 
-                 info: TLineInfo) = 
+proc splitSwitch(switch: string, cmd, arg: var string, pass: TCmdLinePass,
+                 info: TLineInfo) =
   cmd = ""
   var i = 0
   if i < len(switch) and switch[i] == '-': inc(i)
   if i < len(switch) and switch[i] == '-': inc(i)
-  while i < len(switch): 
+  while i < len(switch):
     case switch[i]
     of 'a'..'z', 'A'..'Z', '0'..'9', '_', '.': add(cmd, switch[i])
-    else: break 
+    else: break
     inc(i)
   if i >= len(switch): arg = ""
   elif switch[i] in {':', '=', '['}: arg = substr(switch, i + 1)
   else: invalidCmdLineOption(pass, switch, info)
-  
-proc processOnOffSwitch(op: TOptions, arg: string, pass: TCmdLinePass, 
-                        info: TLineInfo) = 
+
+proc processOnOffSwitch(op: TOptions, arg: string, pass: TCmdLinePass,
+                        info: TLineInfo) =
   case whichKeyword(arg)
   of wOn: gOptions = gOptions + op
   of wOff: gOptions = gOptions - op
   else: localError(info, errOnOrOffExpectedButXFound, arg)
-  
-proc processOnOffSwitchG(op: TGlobalOptions, arg: string, pass: TCmdLinePass, 
-                         info: TLineInfo) = 
+
+proc processOnOffSwitchG(op: TGlobalOptions, arg: string, pass: TCmdLinePass,
+                         info: TLineInfo) =
   case whichKeyword(arg)
   of wOn: gGlobalOptions = gGlobalOptions + op
   of wOff: gGlobalOptions = gGlobalOptions - op
   else: localError(info, errOnOrOffExpectedButXFound, arg)
-  
-proc expectArg(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) = 
+
+proc expectArg(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
   if arg == "": localError(info, errCmdLineArgExpected, addPrefix(switch))
-  
-proc expectNoArg(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) = 
+
+proc expectNoArg(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
   if arg != "": localError(info, errCmdLineNoArgExpected, addPrefix(switch))
-  
-proc processSpecificNote(arg: string, state: TSpecialWord, pass: TCmdLinePass, 
-                         info: TLineInfo; orig: string) = 
+
+proc processSpecificNote(arg: string, state: TSpecialWord, pass: TCmdLinePass,
+                         info: TLineInfo; orig: string) =
   var id = ""  # arg = "X]:on|off"
   var i = 0
   var n = hintMin
-  while i < len(arg) and (arg[i] != ']'): 
+  while i < len(arg) and (arg[i] != ']'):
     add(id, arg[i])
     inc(i)
   if i < len(arg) and (arg[i] == ']'): inc(i)
@@ -165,7 +165,7 @@ proc processSpecificNote(arg: string, state: TSpecialWord, pass: TCmdLinePass,
   of wOff: excl(gNotes, n)
   else: localError(info, errOnOrOffExpectedButXFound, arg)
 
-proc processCompile(filename: string) = 
+proc processCompile(filename: string) =
   var found = findFile(filename)
   if found == "": found = filename
   var trunc = changeFileExt(found, "")
@@ -191,7 +191,7 @@ proc testCompileOptionArg*(switch, arg: string, info: TLineInfo): bool =
     else: localError(info, errNoneSpeedOrSizeExpectedButXFound, arg)
   else: invalidCmdLineOption(passCmd1, switch, info)
 
-proc testCompileOption*(switch: string, info: TLineInfo): bool = 
+proc testCompileOption*(switch: string, info: TLineInfo): bool =
   case switch.normalize
   of "debuginfo": result = contains(gGlobalOptions, optCDebug)
   of "compileonly", "c": result = contains(gGlobalOptions, optCompileOnly)
@@ -228,11 +228,11 @@ proc testCompileOption*(switch: string, info: TLineInfo): bool =
   of "patterns": result = contains(gOptions, optPatterns)
   of "experimental": result = gExperimentalMode
   else: invalidCmdLineOption(passCmd1, switch, info)
-  
+
 proc processPath(path: string, notRelativeToProj = false): string =
   let p = if notRelativeToProj or os.isAbsolute(path) or
-              '$' in path or path[0] == '.': 
-            path 
+              '$' in path or path[0] == '.':
+            path
           else:
             options.gProjectPath / path
   result = unixToNativePath(p % ["nimrod", getPrefixDir(),
@@ -251,14 +251,14 @@ proc trackDirty(arg: string, info: TLineInfo) =
     localError(info, errInvalidNumber, a[1])
   if parseUtils.parseInt(a[3], column) <= 0:
     localError(info, errInvalidNumber, a[2])
-  
+
   let dirtyOriginalIdx = a[1].fileInfoIdx
   if dirtyOriginalIdx >= 0:
     msgs.setDirtyFile(dirtyOriginalIdx, a[0])
 
   gTrackPos = newLineInfo(dirtyOriginalIdx, line, column)
 
-proc track(arg: string, info: TLineInfo) = 
+proc track(arg: string, info: TLineInfo) =
   var a = arg.split(',')
   if a.len != 3: localError(info, errTokenExpected, "FILE,LINE,COLUMN")
   var line, column: int
@@ -273,13 +273,13 @@ proc dynlibOverride(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
     expectArg(switch, arg, pass, info)
     options.inclDynlibOverride(arg)
 
-proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) = 
-  var 
+proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
+  var
     theOS: TSystemOS
     cpu: TSystemCPU
     key, val: string
   case switch.normalize
-  of "path", "p": 
+  of "path", "p":
     expectArg(switch, arg, pass, info)
     addPath(processPath(arg), info)
   of "nimblepath", "babelpath":
@@ -303,7 +303,7 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
   of "nimcache":
     expectArg(switch, arg, pass, info)
     options.nimcacheDir = processPath(arg)
-  of "out", "o": 
+  of "out", "o":
     expectArg(switch, arg, pass, info)
     options.outFile = arg
   of "docseesrcurl":
@@ -311,19 +311,19 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
     options.docSeeSrcUrl = arg
   of "mainmodule", "m":
     discard "allow for backwards compatibility, but don't do anything"
-  of "define", "d": 
+  of "define", "d":
     expectArg(switch, arg, pass, info)
     defineSymbol(arg)
-  of "undef", "u": 
+  of "undef", "u":
     expectArg(switch, arg, pass, info)
     undefSymbol(arg)
   of "symbol":
     expectArg(switch, arg, pass, info)
-    declareSymbol(arg)  
-  of "compile": 
+    declareSymbol(arg)
+  of "compile":
     expectArg(switch, arg, pass, info)
     if pass in {passCmd2, passPP}: processCompile(arg)
-  of "link": 
+  of "link":
     expectArg(switch, arg, pass, info)
     if pass in {passCmd2, passPP}: addFileToLink(arg)
   of "debuginfo":
@@ -332,25 +332,25 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
   of "embedsrc":
     expectNoArg(switch, arg, pass, info)
     incl(gGlobalOptions, optEmbedOrigSrc)
-  of "compileonly", "c": 
+  of "compileonly", "c":
     expectNoArg(switch, arg, pass, info)
     incl(gGlobalOptions, optCompileOnly)
-  of "nolinking": 
+  of "nolinking":
     expectNoArg(switch, arg, pass, info)
     incl(gGlobalOptions, optNoLinking)
-  of "nomain": 
+  of "nomain":
     expectNoArg(switch, arg, pass, info)
     incl(gGlobalOptions, optNoMain)
-  of "forcebuild", "f": 
+  of "forcebuild", "f":
     expectNoArg(switch, arg, pass, info)
     incl(gGlobalOptions, optForceFullMake)
   of "project":
     expectNoArg(switch, arg, pass, info)
     gWholeProject = true
-  of "gc": 
+  of "gc":
     expectArg(switch, arg, pass, info)
     case arg.normalize
-    of "boehm": 
+    of "boehm":
       gSelectedGC = gcBoehm
       defineSymbol("boehmgc")
     of "refc":
@@ -388,7 +388,7 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
       undefSymbol("endb")
     else:
       localError(info, "expected endb|gdb but found " & arg)
-  of "profiler": 
+  of "profiler":
     processOnOffSwitch({optProfiler}, arg, pass, info)
     if optProfiler in gOptions: defineSymbol("profiler")
     else: undefSymbol("profiler")
@@ -407,7 +407,7 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
   of "deadcodeelim": processOnOffSwitchG({optDeadCodeElim}, arg, pass, info)
   of "threads":
     processOnOffSwitchG({optThreads}, arg, pass, info)
-    if optThreads in gGlobalOptions: incl(gNotes, warnGcUnsafe)
+    #if optThreads in gGlobalOptions: incl(gNotes, warnGcUnsafe)
   of "tlsemulation": processOnOffSwitchG({optTlsEmulation}, arg, pass, info)
   of "taintmode": processOnOffSwitchG({optTaintMode}, arg, pass, info)
   of "implicitstatic":
@@ -417,17 +417,17 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
   of "opt":
     expectArg(switch, arg, pass, info)
     case arg.normalize
-    of "speed": 
+    of "speed":
       incl(gOptions, optOptimizeSpeed)
       excl(gOptions, optOptimizeSize)
-    of "size": 
+    of "size":
       excl(gOptions, optOptimizeSpeed)
       incl(gOptions, optOptimizeSize)
     of "none":
       excl(gOptions, optOptimizeSpeed)
       excl(gOptions, optOptimizeSize)
     else: localError(info, errNoneSpeedOrSizeExpectedButXFound, arg)
-  of "app": 
+  of "app":
     expectArg(switch, arg, pass, info)
     case arg.normalize
     of "gui":
@@ -449,10 +449,10 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
       defineSymbol("library")
       defineSymbol("staticlib")
     else: localError(info, errGuiConsoleOrLibExpectedButXFound, arg)
-  of "passc", "t": 
+  of "passc", "t":
     expectArg(switch, arg, pass, info)
     if pass in {passCmd2, passPP}: extccomp.addCompileOption(arg)
-  of "passl", "l": 
+  of "passl", "l":
     expectArg(switch, arg, pass, info)
     if pass in {passCmd2, passPP}: extccomp.addLinkOption(arg)
   of "cincludes":
@@ -475,52 +475,52 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
   of "include":
     expectArg(switch, arg, pass, info)
     if pass in {passCmd2, passPP}: implicitIncludes.add arg
-  of "listcmd": 
+  of "listcmd":
     expectNoArg(switch, arg, pass, info)
     incl(gGlobalOptions, optListCmd)
-  of "genmapping": 
+  of "genmapping":
     expectNoArg(switch, arg, pass, info)
     incl(gGlobalOptions, optGenMapping)
-  of "os": 
+  of "os":
     expectArg(switch, arg, pass, info)
-    if pass in {passCmd1, passPP}: 
+    if pass in {passCmd1, passPP}:
       theOS = platform.nameToOS(arg)
       if theOS == osNone: localError(info, errUnknownOS, arg)
-      elif theOS != platform.hostOS: 
+      elif theOS != platform.hostOS:
         setTarget(theOS, targetCPU)
         condsyms.initDefines()
-  of "cpu": 
+  of "cpu":
     expectArg(switch, arg, pass, info)
-    if pass in {passCmd1, passPP}: 
+    if pass in {passCmd1, passPP}:
       cpu = platform.nameToCPU(arg)
       if cpu == cpuNone: localError(info, errUnknownCPU, arg)
-      elif cpu != platform.hostCPU: 
+      elif cpu != platform.hostCPU:
         setTarget(targetOS, cpu)
         condsyms.initDefines()
-  of "run", "r": 
+  of "run", "r":
     expectNoArg(switch, arg, pass, info)
     incl(gGlobalOptions, optRun)
-  of "verbosity": 
+  of "verbosity":
     expectArg(switch, arg, pass, info)
     gVerbosity = parseInt(arg)
-  of "parallelbuild": 
+  of "parallelbuild":
     expectArg(switch, arg, pass, info)
     gNumberOfProcessors = parseInt(arg)
-  of "version", "v": 
+  of "version", "v":
     expectNoArg(switch, arg, pass, info)
     writeVersionInfo(pass)
-  of "advanced": 
+  of "advanced":
     expectNoArg(switch, arg, pass, info)
     writeAdvancedUsage(pass)
-  of "help", "h": 
+  of "help", "h":
     expectNoArg(switch, arg, pass, info)
     helpOnError(pass)
-  of "symbolfiles": 
+  of "symbolfiles":
     processOnOffSwitchG({optSymbolFiles}, arg, pass, info)
-  of "skipcfg": 
+  of "skipcfg":
     expectNoArg(switch, arg, pass, info)
     incl(gGlobalOptions, optSkipConfigFile)
-  of "skipprojcfg": 
+  of "skipprojcfg":
     expectNoArg(switch, arg, pass, info)
     incl(gGlobalOptions, optSkipProjConfigFile)
   of "skipusercfg":
@@ -529,17 +529,17 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
   of "skipparentcfg":
     expectNoArg(switch, arg, pass, info)
     incl(gGlobalOptions, optSkipParentConfigFiles)
-  of "genscript": 
+  of "genscript":
     expectNoArg(switch, arg, pass, info)
     incl(gGlobalOptions, optGenScript)
   of "lib":
     expectArg(switch, arg, pass, info)
     libpath = processPath(arg, notRelativeToProj=true)
-  of "putenv": 
+  of "putenv":
     expectArg(switch, arg, pass, info)
     splitSwitch(arg, key, val, pass, info)
     os.putEnv(key, val)
-  of "cc": 
+  of "cc":
     expectArg(switch, arg, pass, info)
     setCC(arg)
   of "track":
@@ -548,7 +548,7 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
   of "trackdirty":
     expectArg(switch, arg, pass, info)
     trackDirty(arg, info)
-  of "suggest": 
+  of "suggest":
     expectNoArg(switch, arg, pass, info)
     gIdeCmd = ideSug
   of "def":
@@ -584,7 +584,7 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
   else:
     if strutils.find(switch, '.') >= 0: options.setConfigVar(switch, arg)
     else: invalidCmdLineOption(pass, switch, info)
-  
+
 proc processCommand(switch: string, pass: TCmdLinePass) =
   var cmd, arg: string
   splitSwitch(switch, cmd, arg, pass, gCmdLineInfo)
@@ -600,14 +600,14 @@ proc processSwitch*(pass: TCmdLinePass; p: OptParser) =
   # hint[X]:off is parsed as (p.key = "hint[X]", p.val = "off")
   # we fix this here
   var bracketLe = strutils.find(p.key, '[')
-  if bracketLe >= 0: 
+  if bracketLe >= 0:
     var key = substr(p.key, 0, bracketLe - 1)
     var val = substr(p.key, bracketLe + 1) & ':' & p.val
     processSwitch(key, val, pass, gCmdLineInfo)
-  else: 
+  else:
     processSwitch(p.key, p.val, pass, gCmdLineInfo)
 
-proc processArgument*(pass: TCmdLinePass; p: OptParser; 
+proc processArgument*(pass: TCmdLinePass; p: OptParser;
                       argsCount: var int): bool =
   if argsCount == 0:
     options.command = p.key
diff --git a/compiler/msgs.nim b/compiler/msgs.nim
index c8aaa7b0b..7fe95f673 100644
--- a/compiler/msgs.nim
+++ b/compiler/msgs.nim
@@ -387,7 +387,7 @@ const
     warnProveField: "cannot prove that field '$1' is accessible [ProveField]",
     warnProveIndex: "cannot prove index '$1' is valid [ProveIndex]",
     warnGcUnsafe: "not GC-safe: '$1' [GcUnsafe]",
-    warnGcUnsafe2: "cannot prove '$1' is GC-safe. Does not compile with --threads:on.",
+    warnGcUnsafe2: "$1",
     warnUninit: "'$1' might not have been initialized [Uninit]",
     warnGcMem: "'$1' uses GC'ed memory [GcMem]",
     warnDestructor: "usage of a type with a destructor in a non destructible context. This will become a compile time error in the future. [Destructor]",
diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim
index ab9ba5db1..54162c016 100644
--- a/compiler/pragmas.nim
+++ b/compiler/pragmas.nim
@@ -865,9 +865,11 @@ proc implicitPragmas*(c: PContext, sym: PSym, n: PNode,
     while it != nil:
       let o = it.otherPragmas
       if not o.isNil:
+        pushInfoContext(n.info)
         for i in countup(0, sonsLen(o) - 1):
           if singlePragma(c, sym, o, i, validPragmas):
             internalError(n.info, "implicitPragmas")
+        popInfoContext()
       it = it.next.POptionEntry
 
     if lfExportLib in sym.loc.flags and sfExportc notin sym.flags:
diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim
index 48f54fa6c..6928dbaf4 100644
--- a/compiler/sempass2.nim
+++ b/compiler/sempass2.nim
@@ -194,8 +194,38 @@ proc warnAboutGcUnsafe(n: PNode) =
   #assert false
   message(n.info, warnGcUnsafe, renderTree(n))
 
-template markGcUnsafe(a: PEffects) =
+proc markGcUnsafe(a: PEffects; reason: PSym) =
   a.gcUnsafe = true
+  if a.owner.kind in routineKinds: a.owner.gcUnsafetyReason = reason
+
+proc markGcUnsafe(a: PEffects; reason: PNode) =
+  a.gcUnsafe = true
+  if a.owner.kind in routineKinds:
+    if reason.kind == nkSym:
+      a.owner.gcUnsafetyReason = reason.sym
+    else:
+      a.owner.gcUnsafetyReason = newSym(skUnknown, getIdent("<unknown>"),
+                                        a.owner, reason.info)
+
+proc listGcUnsafety(s: PSym; onlyWarning: bool) =
+  let u = s.gcUnsafetyReason
+  if u != nil:
+    let msgKind = if onlyWarning: warnGcUnsafe2 else: errGenerated
+    if u.kind in {skLet, skVar}:
+      message(s.info, msgKind,
+        ("'$#' is not GC-safe as it accesses '$#'" &
+        " which is a global using GC'ed memory") % [s.name.s, u.name.s])
+    elif u.kind in routineKinds:
+      # recursive call *always* produces only a warning so the full error
+      # message is printed:
+      listGcUnsafety(u, true)
+      message(s.info, msgKind,
+        "'$#' is not GC-safe as it calls '$#'" %
+        [s.name.s, u.name.s])
+    else:
+      internalAssert u.kind == skUnknown
+      message(u.info, msgKind,
+        "'$#' is not GC-safe as it performs an indirect call here" % s.name.s)
 
 proc useVar(a: PEffects, n: PNode) =
   let s = n.sym
@@ -210,8 +240,8 @@ proc useVar(a: PEffects, n: PNode) =
   if {sfGlobal, sfThread} * s.flags == {sfGlobal} and s.kind in {skVar, skLet}:
     if s.guard != nil: guardGlobal(a, n, s.guard)
     if (tfHasGCedMem in s.typ.flags or s.typ.isGCedMem):
-      if warnGcUnsafe in gNotes: warnAboutGcUnsafe(n)
-      markGcUnsafe(a)
+      #if warnGcUnsafe in gNotes: warnAboutGcUnsafe(n)
+      markGcUnsafe(a, s)
 
 type
   TIntersection = seq[tuple[id, count: int]] # a simple count table
@@ -450,7 +480,7 @@ proc propagateEffects(tracked: PEffects, n: PNode, s: PSym) =
 
   if notGcSafe(s.typ) and sfImportc notin s.flags:
     if warnGcUnsafe in gNotes: warnAboutGcUnsafe(n)
-    markGcUnsafe(tracked)
+    markGcUnsafe(tracked, s)
   mergeLockLevels(tracked, n, s.getLockLevel)
 
 proc notNilCheck(tracked: PEffects, n: PNode, paramType: PType) =
@@ -504,13 +534,13 @@ proc trackOperand(tracked: PEffects, n: PNode, paramType: PType) =
       # assume GcUnsafe unless in its type; 'forward' does not matter:
       if notGcSafe(op) and not isOwnedProcVar(a, tracked.owner):
         if warnGcUnsafe in gNotes: warnAboutGcUnsafe(n)
-        markGcUnsafe(tracked)
+        markGcUnsafe(tracked, a)
     else:
       mergeEffects(tracked, effectList.sons[exceptionEffects], n)
       mergeTags(tracked, effectList.sons[tagEffects], n)
       if notGcSafe(op):
         if warnGcUnsafe in gNotes: warnAboutGcUnsafe(n)
-        markGcUnsafe(tracked)
+        markGcUnsafe(tracked, a)
   notNilCheck(tracked, n, paramType)
 
 proc breaksBlock(n: PNode): bool =
@@ -658,7 +688,7 @@ proc track(tracked: PEffects, n: PNode) =
           # and it's not a recursive call:
           if not (a.kind == nkSym and a.sym == tracked.owner):
             warnAboutGcUnsafe(n)
-            markGcUnsafe(tracked)
+            markGcUnsafe(tracked, a)
     for i in 1 .. <len(n): trackOperand(tracked, n.sons[i], paramType(op, i))
     if a.kind == nkSym and a.sym.magic in {mNew, mNewFinalize, mNewSeq}:
       # may not look like an assignment, but it is:
@@ -853,9 +883,11 @@ proc trackProc*(s: PSym, body: PNode) =
 
   if sfThread in s.flags and t.gcUnsafe:
     if optThreads in gGlobalOptions and optThreadAnalysis in gGlobalOptions:
-      localError(s.info, "'$1' is not GC-safe" % s.name.s)
+      #localError(s.info, "'$1' is not GC-safe" % s.name.s)
+      listGcUnsafety(s, onlyWarning=false)
     else:
-      localError(s.info, warnGcUnsafe2, s.name.s)
+      listGcUnsafety(s, onlyWarning=true)
+      #localError(s.info, warnGcUnsafe2, s.name.s)
   if not t.gcUnsafe:
     s.typ.flags.incl tfGcSafe
   if s.typ.lockLevel == UnspecifiedLockLevel:
diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim
index 7263b21b9..fd15eab53 100644
--- a/compiler/semstmts.nim
+++ b/compiler/semstmts.nim
@@ -970,7 +970,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
       s = semIdentDef(c, n.sons[0], kind)
     n.sons[namePos] = newSymNode(s)
     s.ast = n
-    s.scope = c.currentScope
+    #s.scope = c.currentScope
 
     if sfNoForward in c.module.flags and
        sfSystemModule notin c.module.flags:
@@ -982,14 +982,14 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
     s.owner = getCurrOwner()
     typeIsDetermined = s.typ == nil
     s.ast = n
-    s.scope = c.currentScope
+    #s.scope = c.currentScope
 
     # if typeIsDetermined: assert phase == stepCompileBody
     # else: assert phase == stepDetermineType
   # before compiling the proc body, set as current the scope
   # where the proc was declared
   let oldScope = c.currentScope
-  c.currentScope = s.scope
+  #c.currentScope = s.scope
   pushOwner(s)
   openScope(c)
   var gp: PNode
@@ -1014,7 +1014,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
   if s.kind in skIterators:
     s.typ.flags.incl(tfIterator)
 
-  var proto = searchForProc(c, s.scope, s)
+  var proto = searchForProc(c, oldScope, s)
   if proto == nil:
     if s.kind == skClosureIterator: s.typ.callConv = ccClosure
     else: s.typ.callConv = lastOptionEntry(c).defaultCC
@@ -1022,10 +1022,10 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
     if sfGenSym in s.flags: discard
     elif kind in OverloadableSyms:
       if not typeIsDetermined:
-        addInterfaceOverloadableSymAt(c, s.scope, s)
+        addInterfaceOverloadableSymAt(c, oldScope, s)
     else:
       if not typeIsDetermined:
-        addInterfaceDeclAt(c, s.scope, s)
+        addInterfaceDeclAt(c, oldScope, s)
     if n.sons[pragmasPos].kind != nkEmpty:
       pragma(c, s, n.sons[pragmasPos], validPragmas)
     else:
@@ -1093,7 +1093,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
     elif sfBorrow in s.flags: semBorrow(c, n, s)
   sideEffectsCheck(c, s)
   closeScope(c)           # close scope for parameters
-  c.currentScope = oldScope
+  # c.currentScope = oldScope
   popOwner()
   if n.sons[patternPos].kind != nkEmpty:
     c.patterns.add(s)
diff --git a/compiler/semtempl.nim b/compiler/semtempl.nim
index b6efa5119..161d22fc1 100644
--- a/compiler/semtempl.nim
+++ b/compiler/semtempl.nim
@@ -482,7 +482,7 @@ proc semTemplateDef(c: PContext, n: PNode): PNode =
     s = semIdentVis(c, skTemplate, n.sons[0], {})
   styleCheckDef(s)
   # check parameter list:
-  s.scope = c.currentScope
+  #s.scope = c.currentScope
   pushOwner(s)
   openScope(c)
   n.sons[namePos] = newSymNode(s, n.sons[namePos].info)
diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim
index 1fce99e50..10130ddb3 100644
--- a/compiler/sigmatch.nim
+++ b/compiler/sigmatch.nim
@@ -101,7 +101,8 @@ proc initCandidate*(ctx: PContext, c: var TCandidate, callee: PSym,
     if callee.originatingModule == ctx.module:
       let rootSym = if sfFromGeneric notin callee.flags: callee
                     else: callee.owner
-      c.calleeScope = rootSym.scope.depthLevel
+      c.calleeScope = 2 #  rootSym.scope.depthLevel
+      #echo "SCOPE IS ", rootSym.scope.depthLevel
     else:
       c.calleeScope = 1
   else:
diff --git a/lib/js/dom.nim b/lib/js/dom.nim
index 870213db3..18ff94c9a 100644
--- a/lib/js/dom.nim
+++ b/lib/js/dom.nim
@@ -36,6 +36,8 @@ type
     onsubmit*: proc (event: ref TEvent) {.nimcall.}
     onunload*: proc (event: ref TEvent) {.nimcall.}
 
+    addEventListener*: proc(ev: cstring, cb: proc(ev: ref TEvent), useCapture: bool = false) {.nimcall.}
+
   TWindow* {.importc.} = object of TEventHandlers
     document*: ref TDocument
     event*: ref TEvent
@@ -55,7 +57,6 @@ type
     status*: cstring
     toolbar*: ref TToolBar
 
-    addEventListener*: proc(ev: cstring, cb: proc(ev: ref TEvent) ) {.nimcall.}
     alert*: proc (msg: cstring) {.nimcall.}
     back*: proc () {.nimcall.}
     blur*: proc () {.nimcall.}
@@ -91,8 +92,59 @@ type
 
   TFrame* {.importc.} = object of TWindow
 
-  TDocument* {.importc.} = object of TEventHandlers
-    addEventListener*: proc(ev: cstring, cb: proc(ev: ref TEvent) ) {.nimcall.}
+  ClassList* {.importc.} = object of RootObj
+    add*: proc (class: cstring) {.nimcall.}
+    remove*: proc (class: cstring) {.nimcall.}
+    contains*: proc (class: cstring):bool {.nimcall.}
+    toggle*: proc (class: cstring) {.nimcall.}
+
+  TNodeType* = enum
+    ElementNode = 1,
+    AttributeNode,
+    TextNode,
+    CDATANode,
+    EntityRefNode,
+    EntityNode,
+    ProcessingInstructionNode,
+    CommentNode,
+    DocumentNode,
+    DocumentTypeNode,
+    DocumentFragmentNode,
+    NotationNode
+  TNode* {.importc.} = object of TEventHandlers
+    attributes*: seq[ref TNode]
+    childNodes*: seq[ref TNode]
+    children*: seq[ref TNode]
+    data*: cstring
+    firstChild*: ref TNode
+    lastChild*: ref TNode
+    nextSibling*: ref TNode
+    nodeName*: cstring
+    nodeType*: TNodeType
+    nodeValue*: cstring
+    parentNode*: ref TNode
+    previousSibling*: ref TNode
+    appendChild*: proc (child: ref TNode) {.nimcall.}
+    appendData*: proc (data: cstring) {.nimcall.}
+    cloneNode*: proc (copyContent: bool): ref TNode {.nimcall.}
+    deleteData*: proc (start, len: int) {.nimcall.}
+    getAttribute*: proc (attr: cstring): cstring {.nimcall.}
+    getAttributeNode*: proc (attr: cstring): ref TNode {.nimcall.}
+    hasChildNodes*: proc (): bool {.nimcall.}
+    innerHTML*: cstring
+    insertBefore*: proc (newNode, before: ref TNode) {.nimcall.}
+    insertData*: proc (position: int, data: cstring) {.nimcall.}
+    removeAttribute*: proc (attr: cstring) {.nimcall.}
+    removeAttributeNode*: proc (attr: ref TNode) {.nimcall.}
+    removeChild*: proc (child: ref TNode) {.nimcall.}
+    replaceChild*: proc (newNode, oldNode: ref TNode) {.nimcall.}
+    replaceData*: proc (start, len: int, text: cstring) {.nimcall.}
+    scrollIntoView*: proc () {.nimcall.}
+    setAttribute*: proc (name, value: cstring) {.nimcall.}
+    setAttributeNode*: proc (attr: ref TNode) {.nimcall.}
+    style*: ref TStyle
+
+  TDocument* {.importc.} = object of TNode
     alinkColor*: cstring
     bgColor*: cstring
     charset*: cstring
@@ -109,10 +161,10 @@ type
     createAttribute*: proc (identifier: cstring): ref TNode {.nimcall.}
     createElement*: proc (identifier: cstring): ref TNode {.nimcall.}
     createTextNode*: proc (identifier: cstring): ref TNode {.nimcall.}
-    getElementById*: proc (id: cstring): ref TNode {.nimcall.}
-    getElementsByName*: proc (name: cstring): seq[ref TNode] {.nimcall.}
-    getElementsByTagName*: proc (name: cstring): seq[ref TNode] {.nimcall.}
-    getElementsByClassName*: proc (name: cstring): seq[ref TNode] {.nimcall.}
+    getElementById*: proc (id: cstring): ref TElement {.nimcall.}
+    getElementsByName*: proc (name: cstring): seq[ref TElement] {.nimcall.}
+    getElementsByTagName*: proc (name: cstring): seq[ref TElement] {.nimcall.}
+    getElementsByClassName*: proc (name: cstring): seq[ref TElement] {.nimcall.}
     getSelection*: proc (): cstring {.nimcall.}
     handleEvent*: proc (event: ref TEvent) {.nimcall.}
     open*: proc () {.nimcall.}
@@ -127,17 +179,33 @@ type
     embeds*: seq[ref TEmbed]
     links*: seq[ref TLink]
 
-  TLink* {.importc.} = object of RootObj
+  TElement* {.importc.} = object of TNode
+    classList*: ref Classlist
+    checked*: bool
+    defaultChecked*: bool
+    defaultValue*: cstring
+    disabled*: bool
+    form*: ref TForm
     name*: cstring
+    readOnly*: bool
+    blur*: proc () {.nimcall.}
+    click*: proc () {.nimcall.}
+    focus*: proc () {.nimcall.}
+    handleEvent*: proc (event: ref TEvent) {.nimcall.}
+    select*: proc () {.nimcall.}
+    options*: seq[ref TOption]
+    getElementsByTagName*: proc (name: cstring): seq[ref TNode] {.nimcall.}
+    getElementsByClassName*: proc (name: cstring): seq[ref TNode] {.nimcall.}
+
+  TLink* {.importc.} = object of TElement
     target*: cstring
     text*: cstring
     x*: int
     y*: int
 
-  TEmbed* {.importc.} = object of RootObj
+  TEmbed* {.importc.} = object of TElement
     height*: int
     hspace*: int
-    name*: cstring
     src*: cstring
     width*: int
     `type`*: cstring
@@ -152,108 +220,32 @@ type
 
   TApplet* {.importc.} = object of RootObj
 
-  TElement* {.importc.} = object of TEventHandlers
-    checked*: bool
-    defaultChecked*: bool
-    defaultValue*: cstring
-    disabled*: bool
-    form*: ref TForm
-    name*: cstring
-    readOnly*: bool
-    `type`*: cstring
-    value*: cstring
-    blur*: proc () {.nimcall.}
-    click*: proc () {.nimcall.}
-    focus*: proc () {.nimcall.}
-    handleEvent*: proc (event: ref TEvent) {.nimcall.}
-    select*: proc () {.nimcall.}
-    options*: seq[ref TOption]
-
-  TOption* {.importc.} = object of RootObj
+  TOption* {.importc.} = object of TElement
     defaultSelected*: bool
     selected*: bool
     selectedIndex*: int
     text*: cstring
     value*: cstring
 
-  TForm* {.importc.} = object of TEventHandlers
+  TForm* {.importc.} = object of TElement
     action*: cstring
     encoding*: cstring
     `method`*: cstring
-    name*: cstring
     target*: cstring
-    handleEvent*: proc (event: ref TEvent) {.nimcall.}
     reset*: proc () {.nimcall.}
     submit*: proc () {.nimcall.}
     elements*: seq[ref TElement]
 
-  TImage* {.importc.} = object of TEventHandlers
+  TImage* {.importc.} = object of TElement
     border*: int
     complete*: bool
     height*: int
     hspace*: int
     lowsrc*: cstring
-    name*: cstring
     src*: cstring
     vspace*: int
     width*: int
-    handleEvent*: proc (event: ref TEvent) {.nimcall.}
 
-  ClassList* {.importc.} = object of RootObj
-    add*: proc (class: cstring) {.nimcall.}
-    remove*: proc (class: cstring) {.nimcall.}
-    contains*: proc (class: cstring):bool {.nimcall.}
-    toggle*: proc (class: cstring) {.nimcall.}
-
-  TNodeType* = enum
-    ElementNode = 1,
-    AttributeNode,
-    TextNode,
-    CDATANode,
-    EntityRefNode,
-    EntityNode,
-    ProcessingInstructionNode,
-    CommentNode,
-    DocumentNode,
-    DocumentTypeNode,
-    DocumentFragmentNode,
-    NotationNode
-  TNode* {.importc.} = object of RootObj
-    attributes*: seq[ref TNode]
-    childNodes*: seq[ref TNode]
-    children*: seq[ref TNode]
-    classList*: ref Classlist
-    data*: cstring
-    firstChild*: ref TNode
-    lastChild*: ref TNode
-    nextSibling*: ref TNode
-    nodeName*: cstring
-    nodeType*: TNodeType
-    nodeValue*: cstring
-    parentNode*: ref TNode
-    previousSibling*: ref TNode
-    appendChild*: proc (child: ref TNode) {.nimcall.}
-    appendData*: proc (data: cstring) {.nimcall.}
-    cloneNode*: proc (copyContent: bool): ref TNode {.nimcall.}
-    deleteData*: proc (start, len: int) {.nimcall.}
-    getAttribute*: proc (attr: cstring): cstring {.nimcall.}
-    getAttributeNode*: proc (attr: cstring): ref TNode {.nimcall.}
-    getElementsByTagName*: proc (name: cstring): seq[ref TNode] {.nimcall.}
-    getElementsByClassName*: proc (name: cstring): seq[ref TNode] {.nimcall.}
-    hasChildNodes*: proc (): bool {.nimcall.}
-    innerHTML*: cstring
-    insertBefore*: proc (newNode, before: ref TNode) {.nimcall.}
-    insertData*: proc (position: int, data: cstring) {.nimcall.}
-    addEventListener*: proc(ev: cstring, cb: proc(ev: ref TEvent)) {.nimcall.}
-    removeAttribute*: proc (attr: cstring) {.nimcall.}
-    removeAttributeNode*: proc (attr: ref TNode) {.nimcall.}
-    removeChild*: proc (child: ref TNode) {.nimcall.}
-    replaceChild*: proc (newNode, oldNode: ref TNode) {.nimcall.}
-    replaceData*: proc (start, len: int, text: cstring) {.nimcall.}
-    scrollIntoView*: proc () {.nimcall.}
-    setAttribute*: proc (name, value: cstring) {.nimcall.}
-    setAttributeNode*: proc (attr: ref TNode) {.nimcall.}
-    style*: ref TStyle
 
   TStyle* {.importc.} = object of RootObj
     background*: cstring
diff --git a/lib/packages/docutils/rst.nim b/lib/packages/docutils/rst.nim
index 97784898e..a4d095e68 100644
--- a/lib/packages/docutils/rst.nim
+++ b/lib/packages/docutils/rst.nim
@@ -11,25 +11,25 @@
 ## subset is implemented. Some features of the `markdown`:idx: wiki syntax are
 ## also supported.
 
-import 
+import
   os, strutils, rstast
 
 type
-  TRstParseOption* = enum     ## options for the RST parser 
+  TRstParseOption* = enum     ## options for the RST parser
     roSkipPounds,             ## skip ``#`` at line beginning (documentation
                               ## embedded in Nim comments)
     roSupportSmilies,         ## make the RST parser support smilies like ``:)``
     roSupportRawDirective,    ## support the ``raw`` directive (don't support
                               ## it for sandboxing)
     roSupportMarkdown         ## support additional features of markdown
-  
+
   TRstParseOptions* = set[TRstParseOption]
-  
+
   TMsgClass* = enum
-    mcHint = "Hint", 
-    mcWarning = "Warning", 
+    mcHint = "Hint",
+    mcWarning = "Warning",
     mcError = "Error"
-  
+
   TMsgKind* = enum          ## the possible messages
     meCannotOpenFile,
     meExpected,
@@ -41,20 +41,20 @@ type
     mwUnknownSubstitution,
     mwUnsupportedLanguage,
     mwUnsupportedField
-  
+
   TMsgHandler* = proc (filename: string, line, col: int, msgKind: TMsgKind,
                        arg: string) {.nimcall.} ## what to do in case of an error
   TFindFileHandler* = proc (filename: string): string {.nimcall.}
 
 const
   messages: array [TMsgKind, string] = [
-    meCannotOpenFile: "cannot open '$1'", 
+    meCannotOpenFile: "cannot open '$1'",
     meExpected: "'$1' expected",
     meGridTableNotImplemented: "grid table is not implemented",
-    meNewSectionExpected: "new section expected", 
+    meNewSectionExpected: "new section expected",
     meGeneralParseError: "general parse error",
     meInvalidDirective: "invalid directive: '$1'",
-    mwRedefinitionOfLabel: "redefinition of label '$1'", 
+    mwRedefinitionOfLabel: "redefinition of label '$1'",
     mwUnknownSubstitution: "unknown substitution '$1'",
     mwUnsupportedLanguage: "language '$1' not supported",
     mwUnsupportedField: "field '$1' not supported"
@@ -67,7 +67,7 @@ proc getArgument*(n: PRstNode): string
 
 # ----------------------------- scanner part --------------------------------
 
-const 
+const
   SymChars: set[char] = {'a'..'z', 'A'..'Z', '0'..'9', '\x80'..'\xFF'}
   SmileyStartChars: set[char] = {':', ';', '8'}
   Smilies = {
@@ -111,14 +111,14 @@ const
   }
 
 type
-  TTokType = enum 
+  TTokType = enum
     tkEof, tkIndent, tkWhite, tkWord, tkAdornment, tkPunct, tkOther
   TToken = object             # a RST token
     kind*: TTokType           # the type of the token
     ival*: int                # the indentation or parsed integer value
     symbol*: string           # the parsed symbol as string
     line*, col*: int          # line and column of the token
-  
+
   TTokenSeq = seq[TToken]
   TLexer = object of RootObj
     buf*: cstring
@@ -127,61 +127,61 @@ type
     skipPounds*: bool
 
 
-proc getThing(L: var TLexer, tok: var TToken, s: set[char]) = 
+proc getThing(L: var TLexer, tok: var TToken, s: set[char]) =
   tok.kind = tkWord
   tok.line = L.line
   tok.col = L.col
   var pos = L.bufpos
-  while true: 
+  while true:
     add(tok.symbol, L.buf[pos])
     inc(pos)
-    if L.buf[pos] notin s: break 
+    if L.buf[pos] notin s: break
   inc(L.col, pos - L.bufpos)
   L.bufpos = pos
 
-proc getAdornment(L: var TLexer, tok: var TToken) = 
+proc getAdornment(L: var TLexer, tok: var TToken) =
   tok.kind = tkAdornment
   tok.line = L.line
   tok.col = L.col
   var pos = L.bufpos
   var c = L.buf[pos]
-  while true: 
+  while true:
     add(tok.symbol, L.buf[pos])
     inc(pos)
-    if L.buf[pos] != c: break 
+    if L.buf[pos] != c: break
   inc(L.col, pos - L.bufpos)
   L.bufpos = pos
 
-proc getIndentAux(L: var TLexer, start: int): int = 
+proc getIndentAux(L: var TLexer, start: int): int =
   var pos = start
-  var buf = L.buf                 
+  var buf = L.buf
   # skip the newline (but include it in the token!)
-  if buf[pos] == '\x0D': 
+  if buf[pos] == '\x0D':
     if buf[pos + 1] == '\x0A': inc(pos, 2)
     else: inc(pos)
-  elif buf[pos] == '\x0A': 
+  elif buf[pos] == '\x0A':
     inc(pos)
-  if L.skipPounds: 
+  if L.skipPounds:
     if buf[pos] == '#': inc(pos)
     if buf[pos] == '#': inc(pos)
-  while true: 
+  while true:
     case buf[pos]
-    of ' ', '\x0B', '\x0C': 
+    of ' ', '\x0B', '\x0C':
       inc(pos)
       inc(result)
-    of '\x09': 
+    of '\x09':
       inc(pos)
       result = result - (result mod 8) + 8
-    else: 
+    else:
       break                   # EndOfFile also leaves the loop
-  if buf[pos] == '\0': 
+  if buf[pos] == '\0':
     result = 0
-  elif (buf[pos] == '\x0A') or (buf[pos] == '\x0D'): 
+  elif (buf[pos] == '\x0A') or (buf[pos] == '\x0D'):
     # look at the next line for proper indentation:
     result = getIndentAux(L, pos)
   L.bufpos = pos              # no need to set back buf
-  
-proc getIndent(L: var TLexer, tok: var TToken) = 
+
+proc getIndent(L: var TLexer, tok: var TToken) =
   tok.col = 0
   tok.kind = tkIndent         # skip the newline (but include it in the token!)
   tok.ival = getIndentAux(L, L.bufpos)
@@ -191,85 +191,85 @@ proc getIndent(L: var TLexer, tok: var TToken) =
   tok.ival = max(tok.ival - L.baseIndent, 0)
   tok.symbol = "\n" & spaces(tok.ival)
 
-proc rawGetTok(L: var TLexer, tok: var TToken) = 
+proc rawGetTok(L: var TLexer, tok: var TToken) =
   tok.symbol = ""
   tok.ival = 0
   var c = L.buf[L.bufpos]
   case c
-  of 'a'..'z', 'A'..'Z', '\x80'..'\xFF', '0'..'9': 
+  of 'a'..'z', 'A'..'Z', '\x80'..'\xFF', '0'..'9':
     getThing(L, tok, SymChars)
-  of ' ', '\x09', '\x0B', '\x0C': 
+  of ' ', '\x09', '\x0B', '\x0C':
     getThing(L, tok, {' ', '\x09'})
     tok.kind = tkWhite
-    if L.buf[L.bufpos] in {'\x0D', '\x0A'}: 
+    if L.buf[L.bufpos] in {'\x0D', '\x0A'}:
       rawGetTok(L, tok)       # ignore spaces before \n
-  of '\x0D', '\x0A': 
+  of '\x0D', '\x0A':
     getIndent(L, tok)
-  of '!', '\"', '#', '$', '%', '&', '\'', '(', ')', '*', '+', ',', '-', '.', 
+  of '!', '\"', '#', '$', '%', '&', '\'', '(', ')', '*', '+', ',', '-', '.',
      '/', ':', ';', '<', '=', '>', '?', '@', '[', '\\', ']', '^', '_', '`', '{',
-     '|', '}', '~': 
+     '|', '}', '~':
     getAdornment(L, tok)
     if len(tok.symbol) <= 3: tok.kind = tkPunct
-  else: 
+  else:
     tok.line = L.line
     tok.col = L.col
-    if c == '\0': 
+    if c == '\0':
       tok.kind = tkEof
-    else: 
+    else:
       tok.kind = tkOther
       add(tok.symbol, c)
       inc(L.bufpos)
       inc(L.col)
   tok.col = max(tok.col - L.baseIndent, 0)
 
-proc getTokens(buffer: string, skipPounds: bool, tokens: var TTokenSeq): int = 
+proc getTokens(buffer: string, skipPounds: bool, tokens: var TTokenSeq): int =
   var L: TLexer
   var length = len(tokens)
   L.buf = cstring(buffer)
   L.line = 0                  # skip UTF-8 BOM
-  if (L.buf[0] == '\xEF') and (L.buf[1] == '\xBB') and (L.buf[2] == '\xBF'): 
+  if (L.buf[0] == '\xEF') and (L.buf[1] == '\xBB') and (L.buf[2] == '\xBF'):
     inc(L.bufpos, 3)
   L.skipPounds = skipPounds
-  if skipPounds: 
-    if L.buf[L.bufpos] == '#': 
+  if skipPounds:
+    if L.buf[L.bufpos] == '#':
       inc(L.bufpos)
       inc(result)
-    if L.buf[L.bufpos] == '#': 
+    if L.buf[L.bufpos] == '#':
       inc(L.bufpos)
       inc(result)
     L.baseIndent = 0
-    while L.buf[L.bufpos] == ' ': 
+    while L.buf[L.bufpos] == ' ':
       inc(L.bufpos)
       inc(L.baseIndent)
       inc(result)
-  while true: 
+  while true:
     inc(length)
     setLen(tokens, length)
     rawGetTok(L, tokens[length - 1])
-    if tokens[length - 1].kind == tkEof: break 
-  if tokens[0].kind == tkWhite: 
+    if tokens[length - 1].kind == tkEof: break
+  if tokens[0].kind == tkWhite:
     # BUGFIX
     tokens[0].ival = len(tokens[0].symbol)
     tokens[0].kind = tkIndent
 
 type
   TLevelMap = array[char, int]
-  TSubstitution = object 
+  TSubstitution = object
     key*: string
     value*: PRstNode
 
-  TSharedState = object 
+  TSharedState = object
     options: TRstParseOptions   # parsing options
     uLevel, oLevel: int         # counters for the section levels
     subs: seq[TSubstitution]    # substitutions
     refs: seq[TSubstitution]    # references
     underlineToLevel: TLevelMap # Saves for each possible title adornment
                                 # character its level in the
-                                # current document. 
+                                # current document.
                                 # This is for single underline adornments.
-    overlineToLevel: TLevelMap  # Saves for each possible title adornment 
+    overlineToLevel: TLevelMap  # Saves for each possible title adornment
                                 # character its level in the current
-                                # document. 
+                                # document.
                                 # This is for over-underline adornments.
     msgHandler: TMsgHandler     # How to handle errors.
     findFile: TFindFileHandler  # How to find files.
@@ -293,7 +293,7 @@ proc whichMsgClass*(k: TMsgKind): TMsgClass =
   of 'w', 'W': result = mcWarning
   of 'h', 'H': result = mcHint
   else: assert false, "msgkind does not fit naming scheme"
-  
+
 proc defaultMsgHandler*(filename: string, line, col: int, msgkind: TMsgKind,
                         arg: string) {.procvar.} =
   let mc = msgkind.whichMsgClass
@@ -302,31 +302,31 @@ proc defaultMsgHandler*(filename: string, line, col: int, msgkind: TMsgKind,
   if mc == mcError: raise newException(EParseError, message)
   else: writeln(stdout, message)
 
-proc defaultFindFile*(filename: string): string {.procvar.} = 
+proc defaultFindFile*(filename: string): string {.procvar.} =
   if existsFile(filename): result = filename
   else: result = ""
 
 proc newSharedState(options: TRstParseOptions,
                     findFile: TFindFileHandler,
-                    msgHandler: TMsgHandler): PSharedState = 
+                    msgHandler: TMsgHandler): PSharedState =
   new(result)
   result.subs = @[]
   result.refs = @[]
   result.options = options
   result.msgHandler = if not isNil(msgHandler): msgHandler else: defaultMsgHandler
   result.findFile = if not isNil(findFile): findFile else: defaultFindFile
-  
-proc rstMessage(p: TRstParser, msgKind: TMsgKind, arg: string) = 
-  p.s.msgHandler(p.filename, p.line + p.tok[p.idx].line, 
+
+proc rstMessage(p: TRstParser, msgKind: TMsgKind, arg: string) =
+  p.s.msgHandler(p.filename, p.line + p.tok[p.idx].line,
                              p.col + p.tok[p.idx].col, msgKind, arg)
 
-proc rstMessage(p: TRstParser, msgKind: TMsgKind, arg: string, line, col: int) = 
+proc rstMessage(p: TRstParser, msgKind: TMsgKind, arg: string, line, col: int) =
   p.s.msgHandler(p.filename, p.line + line,
                              p.col + col, msgKind, arg)
 
-proc rstMessage(p: TRstParser, msgKind: TMsgKind) = 
-  p.s.msgHandler(p.filename, p.line + p.tok[p.idx].line, 
-                             p.col + p.tok[p.idx].col, msgKind, 
+proc rstMessage(p: TRstParser, msgKind: TMsgKind) =
+  p.s.msgHandler(p.filename, p.line + p.tok[p.idx].line,
+                             p.col + p.tok[p.idx].col, msgKind,
                              p.tok[p.idx].symbol)
 
 when false:
@@ -334,16 +334,16 @@ when false:
     assert p.indentStack[0] == 0
     for i in 1 .. high(p.indentStack): assert p.indentStack[i] < 1_000
 
-proc currInd(p: TRstParser): int = 
+proc currInd(p: TRstParser): int =
   result = p.indentStack[high(p.indentStack)]
 
-proc pushInd(p: var TRstParser, ind: int) = 
+proc pushInd(p: var TRstParser, ind: int) =
   add(p.indentStack, ind)
 
 proc popInd(p: var TRstParser) =
   if len(p.indentStack) > 1: setLen(p.indentStack, len(p.indentStack) - 1)
-  
-proc initParser(p: var TRstParser, sharedState: PSharedState) = 
+
+proc initParser(p: var TRstParser, sharedState: PSharedState) =
   p.indentStack = @[0]
   p.tok = @[]
   p.idx = 0
@@ -353,150 +353,150 @@ proc initParser(p: var TRstParser, sharedState: PSharedState) =
   p.line = 1
   p.s = sharedState
 
-proc addNodesAux(n: PRstNode, result: var string) = 
-  if n.kind == rnLeaf: 
+proc addNodesAux(n: PRstNode, result: var string) =
+  if n.kind == rnLeaf:
     add(result, n.text)
-  else: 
+  else:
     for i in countup(0, len(n) - 1): addNodesAux(n.sons[i], result)
-  
-proc addNodes(n: PRstNode): string = 
+
+proc addNodes(n: PRstNode): string =
   result = ""
   addNodesAux(n, result)
 
-proc rstnodeToRefnameAux(n: PRstNode, r: var string, b: var bool) = 
-  if n.kind == rnLeaf: 
-    for i in countup(0, len(n.text) - 1): 
+proc rstnodeToRefnameAux(n: PRstNode, r: var string, b: var bool) =
+  if n.kind == rnLeaf:
+    for i in countup(0, len(n.text) - 1):
       case n.text[i]
-      of '0'..'9': 
-        if b: 
+      of '0'..'9':
+        if b:
           add(r, '-')
           b = false
         if len(r) == 0: add(r, 'Z')
         add(r, n.text[i])
-      of 'a'..'z': 
-        if b: 
+      of 'a'..'z':
+        if b:
           add(r, '-')
           b = false
         add(r, n.text[i])
-      of 'A'..'Z': 
-        if b: 
+      of 'A'..'Z':
+        if b:
           add(r, '-')
           b = false
         add(r, chr(ord(n.text[i]) - ord('A') + ord('a')))
-      else: 
+      else:
         if (len(r) > 0): b = true
-  else: 
+  else:
     for i in countup(0, len(n) - 1): rstnodeToRefnameAux(n.sons[i], r, b)
-  
-proc rstnodeToRefname(n: PRstNode): string = 
+
+proc rstnodeToRefname(n: PRstNode): string =
   result = ""
   var b = false
   rstnodeToRefnameAux(n, result, b)
 
-proc findSub(p: var TRstParser, n: PRstNode): int = 
-  var key = addNodes(n)           
+proc findSub(p: var TRstParser, n: PRstNode): int =
+  var key = addNodes(n)
   # the spec says: if no exact match, try one without case distinction:
-  for i in countup(0, high(p.s.subs)): 
-    if key == p.s.subs[i].key: 
+  for i in countup(0, high(p.s.subs)):
+    if key == p.s.subs[i].key:
       return i
-  for i in countup(0, high(p.s.subs)): 
-    if cmpIgnoreStyle(key, p.s.subs[i].key) == 0: 
+  for i in countup(0, high(p.s.subs)):
+    if cmpIgnoreStyle(key, p.s.subs[i].key) == 0:
       return i
   result = -1
 
-proc setSub(p: var TRstParser, key: string, value: PRstNode) = 
+proc setSub(p: var TRstParser, key: string, value: PRstNode) =
   var length = len(p.s.subs)
-  for i in countup(0, length - 1): 
-    if key == p.s.subs[i].key: 
+  for i in countup(0, length - 1):
+    if key == p.s.subs[i].key:
       p.s.subs[i].value = value
-      return 
+      return
   setLen(p.s.subs, length + 1)
   p.s.subs[length].key = key
   p.s.subs[length].value = value
 
-proc setRef(p: var TRstParser, key: string, value: PRstNode) = 
+proc setRef(p: var TRstParser, key: string, value: PRstNode) =
   var length = len(p.s.refs)
-  for i in countup(0, length - 1): 
+  for i in countup(0, length - 1):
     if key == p.s.refs[i].key:
       if p.s.refs[i].value.addNodes != value.addNodes:
         rstMessage(p, mwRedefinitionOfLabel, key)
 
       p.s.refs[i].value = value
-      return 
+      return
   setLen(p.s.refs, length + 1)
   p.s.refs[length].key = key
   p.s.refs[length].value = value
 
-proc findRef(p: var TRstParser, key: string): PRstNode = 
-  for i in countup(0, high(p.s.refs)): 
-    if key == p.s.refs[i].key: 
+proc findRef(p: var TRstParser, key: string): PRstNode =
+  for i in countup(0, high(p.s.refs)):
+    if key == p.s.refs[i].key:
       return p.s.refs[i].value
 
-proc newLeaf(p: var TRstParser): PRstNode = 
+proc newLeaf(p: var TRstParser): PRstNode =
   result = newRstNode(rnLeaf, p.tok[p.idx].symbol)
 
-proc getReferenceName(p: var TRstParser, endStr: string): PRstNode = 
+proc getReferenceName(p: var TRstParser, endStr: string): PRstNode =
   var res = newRstNode(rnInner)
-  while true: 
+  while true:
     case p.tok[p.idx].kind
-    of tkWord, tkOther, tkWhite: 
+    of tkWord, tkOther, tkWhite:
       add(res, newLeaf(p))
-    of tkPunct: 
-      if p.tok[p.idx].symbol == endStr: 
+    of tkPunct:
+      if p.tok[p.idx].symbol == endStr:
         inc(p.idx)
-        break 
-      else: 
+        break
+      else:
         add(res, newLeaf(p))
-    else: 
+    else:
       rstMessage(p, meExpected, endStr)
-      break 
+      break
     inc(p.idx)
   result = res
 
-proc untilEol(p: var TRstParser): PRstNode = 
+proc untilEol(p: var TRstParser): PRstNode =
   result = newRstNode(rnInner)
-  while not (p.tok[p.idx].kind in {tkIndent, tkEof}): 
+  while not (p.tok[p.idx].kind in {tkIndent, tkEof}):
     add(result, newLeaf(p))
     inc(p.idx)
 
-proc expect(p: var TRstParser, tok: string) = 
+proc expect(p: var TRstParser, tok: string) =
   if p.tok[p.idx].symbol == tok: inc(p.idx)
   else: rstMessage(p, meExpected, tok)
-  
-proc isInlineMarkupEnd(p: TRstParser, markup: string): bool = 
+
+proc isInlineMarkupEnd(p: TRstParser, markup: string): bool =
   result = p.tok[p.idx].symbol == markup
-  if not result: 
+  if not result:
     return                    # Rule 3:
   result = not (p.tok[p.idx - 1].kind in {tkIndent, tkWhite})
-  if not result: 
+  if not result:
     return                    # Rule 4:
   result = (p.tok[p.idx + 1].kind in {tkIndent, tkWhite, tkEof}) or
       (p.tok[p.idx + 1].symbol[0] in
-      {'\'', '\"', ')', ']', '}', '>', '-', '/', '\\', ':', '.', ',', ';', '!', 
+      {'\'', '\"', ')', ']', '}', '>', '-', '/', '\\', ':', '.', ',', ';', '!',
        '?', '_'})
-  if not result: 
+  if not result:
     return                    # Rule 7:
-  if p.idx > 0: 
-    if (markup != "``") and (p.tok[p.idx - 1].symbol == "\\"): 
+  if p.idx > 0:
+    if (markup != "``") and (p.tok[p.idx - 1].symbol == "\\"):
       result = false
 
-proc isInlineMarkupStart(p: TRstParser, markup: string): bool = 
+proc isInlineMarkupStart(p: TRstParser, markup: string): bool =
   var d: char
   result = p.tok[p.idx].symbol == markup
-  if not result: 
+  if not result:
     return                    # Rule 1:
   result = (p.idx == 0) or (p.tok[p.idx - 1].kind in {tkIndent, tkWhite}) or
       (p.tok[p.idx - 1].symbol[0] in
       {'\'', '\"', '(', '[', '{', '<', '-', '/', ':', '_'})
-  if not result: 
+  if not result:
     return                    # Rule 2:
   result = not (p.tok[p.idx + 1].kind in {tkIndent, tkWhite, tkEof})
-  if not result: 
+  if not result:
     return                    # Rule 5 & 7:
-  if p.idx > 0: 
-    if p.tok[p.idx - 1].symbol == "\\": 
+  if p.idx > 0:
+    if p.tok[p.idx - 1].symbol == "\\":
       result = false
-    else: 
+    else:
       var c = p.tok[p.idx - 1].symbol[0]
       case c
       of '\'', '\"': d = c
@@ -507,7 +507,7 @@ proc isInlineMarkupStart(p: TRstParser, markup: string): bool =
       else: d = '\0'
       if d != '\0': result = p.tok[p.idx + 1].symbol[0] != d
 
-proc match(p: TRstParser, start: int, expr: string): bool = 
+proc match(p: TRstParser, start: int, expr: string): bool =
   # regular expressions are:
   # special char     exact match
   # 'w'              tkWord
@@ -521,7 +521,7 @@ proc match(p: TRstParser, start: int, expr: string): bool =
   var i = 0
   var j = start
   var last = len(expr) - 1
-  while i <= last: 
+  while i <= last:
     case expr[i]
     of 'w': result = p.tok[j].kind == tkWord
     of ' ': result = p.tok[j].kind == tkWhite
@@ -531,75 +531,75 @@ proc match(p: TRstParser, start: int, expr: string): bool =
     of 'o': result = p.tok[j].kind == tkOther
     of 'T': result = true
     of 'E': result = p.tok[j].kind in {tkEof, tkWhite, tkIndent}
-    of 'e': 
+    of 'e':
       result = (p.tok[j].kind == tkWord) or (p.tok[j].symbol == "#")
-      if result: 
+      if result:
         case p.tok[j].symbol[0]
         of 'a'..'z', 'A'..'Z': result = len(p.tok[j].symbol) == 1
         of '0'..'9': result = allCharsInSet(p.tok[j].symbol, {'0'..'9'})
         else: discard
-    else: 
+    else:
       var c = expr[i]
       var length = 0
-      while (i <= last) and (expr[i] == c): 
+      while (i <= last) and (expr[i] == c):
         inc(i)
         inc(length)
       dec(i)
       result = (p.tok[j].kind in {tkPunct, tkAdornment}) and
           (len(p.tok[j].symbol) == length) and (p.tok[j].symbol[0] == c)
-    if not result: return 
+    if not result: return
     inc(j)
     inc(i)
   result = true
-  
-proc fixupEmbeddedRef(n, a, b: PRstNode) = 
+
+proc fixupEmbeddedRef(n, a, b: PRstNode) =
   var sep = - 1
-  for i in countdown(len(n) - 2, 0): 
-    if n.sons[i].text == "<": 
+  for i in countdown(len(n) - 2, 0):
+    if n.sons[i].text == "<":
       sep = i
-      break 
+      break
   var incr = if (sep > 0) and (n.sons[sep - 1].text[0] == ' '): 2 else: 1
   for i in countup(0, sep - incr): add(a, n.sons[i])
   for i in countup(sep + 1, len(n) - 2): add(b, n.sons[i])
-  
-proc parsePostfix(p: var TRstParser, n: PRstNode): PRstNode = 
+
+proc parsePostfix(p: var TRstParser, n: PRstNode): PRstNode =
   result = n
-  if isInlineMarkupEnd(p, "_"): 
+  if isInlineMarkupEnd(p, "_"):
     inc(p.idx)
     if p.tok[p.idx-2].symbol == "`" and p.tok[p.idx-3].symbol == ">":
       var a = newRstNode(rnInner)
       var b = newRstNode(rnInner)
       fixupEmbeddedRef(n, a, b)
-      if len(a) == 0: 
+      if len(a) == 0:
         result = newRstNode(rnStandaloneHyperlink)
         add(result, b)
-      else: 
+      else:
         result = newRstNode(rnHyperlink)
         add(result, a)
         add(result, b)
         setRef(p, rstnodeToRefname(a), b)
-    elif n.kind == rnInterpretedText: 
+    elif n.kind == rnInterpretedText:
       n.kind = rnRef
-    else: 
+    else:
       result = newRstNode(rnRef)
       add(result, n)
-  elif match(p, p.idx, ":w:"): 
+  elif match(p, p.idx, ":w:"):
     # a role:
-    if p.tok[p.idx + 1].symbol == "idx": 
+    if p.tok[p.idx + 1].symbol == "idx":
       n.kind = rnIdx
-    elif p.tok[p.idx + 1].symbol == "literal": 
+    elif p.tok[p.idx + 1].symbol == "literal":
       n.kind = rnInlineLiteral
-    elif p.tok[p.idx + 1].symbol == "strong": 
+    elif p.tok[p.idx + 1].symbol == "strong":
       n.kind = rnStrongEmphasis
-    elif p.tok[p.idx + 1].symbol == "emphasis": 
+    elif p.tok[p.idx + 1].symbol == "emphasis":
       n.kind = rnEmphasis
     elif (p.tok[p.idx + 1].symbol == "sub") or
-        (p.tok[p.idx + 1].symbol == "subscript"): 
+        (p.tok[p.idx + 1].symbol == "subscript"):
       n.kind = rnSub
     elif (p.tok[p.idx + 1].symbol == "sup") or
-        (p.tok[p.idx + 1].symbol == "supscript"): 
+        (p.tok[p.idx + 1].symbol == "supscript"):
       n.kind = rnSup
-    else: 
+    else:
       result = newRstNode(rnGeneralRole)
       n.kind = rnInner
       add(result, n)
@@ -614,7 +614,7 @@ proc matchVerbatim(p: TRstParser, start: int, expr: string): int =
     inc j, p.tok[result].symbol.len
     inc result
   if j < expr.len: result = 0
-  
+
 proc parseSmiley(p: var TRstParser): PRstNode =
   if p.tok[p.idx].symbol[0] notin SmileyStartChars: return
   for key, val in items(Smilies):
@@ -636,17 +636,17 @@ proc isUrl(p: TRstParser, i: int): bool =
     (p.tok[i+3].kind == tkWord) and
     (p.tok[i].symbol in ["http", "https", "ftp", "telnet", "file"])
 
-proc parseUrl(p: var TRstParser, father: PRstNode) = 
+proc parseUrl(p: var TRstParser, father: PRstNode) =
   #if p.tok[p.idx].symbol[strStart] == '<':
   if isUrl(p, p.idx):
     var n = newRstNode(rnStandaloneHyperlink)
-    while true: 
+    while true:
       case p.tok[p.idx].kind
       of tkWord, tkAdornment, tkOther: discard
-      of tkPunct: 
+      of tkPunct:
         if p.tok[p.idx+1].kind notin {tkWord, tkAdornment, tkOther, tkPunct}:
           break
-      else: break 
+      else: break
       add(n, newLeaf(p))
       inc(p.idx)
     add(father, n)
@@ -655,13 +655,13 @@ proc parseUrl(p: var TRstParser, father: PRstNode) =
     inc(p.idx)
     if p.tok[p.idx].symbol == "_": n = parsePostfix(p, n)
     add(father, n)
-  
-proc parseBackslash(p: var TRstParser, father: PRstNode) = 
+
+proc parseBackslash(p: var TRstParser, father: PRstNode) =
   assert(p.tok[p.idx].kind == tkPunct)
-  if p.tok[p.idx].symbol == "\\\\": 
+  if p.tok[p.idx].symbol == "\\\\":
     add(father, newRstNode(rnLeaf, "\\"))
     inc(p.idx)
-  elif p.tok[p.idx].symbol == "\\": 
+  elif p.tok[p.idx].symbol == "\\":
     # XXX: Unicode?
     inc(p.idx)
     if p.tok[p.idx].kind != tkWhite: add(father, newLeaf(p))
@@ -674,13 +674,13 @@ when false:
   proc parseAdhoc(p: var TRstParser, father: PRstNode, verbatim: bool) =
     if not verbatim and isURL(p, p.idx):
       var n = newRstNode(rnStandaloneHyperlink)
-      while true: 
+      while true:
         case p.tok[p.idx].kind
         of tkWord, tkAdornment, tkOther: nil
-        of tkPunct: 
+        of tkPunct:
           if p.tok[p.idx+1].kind notin {tkWord, tkAdornment, tkOther, tkPunct}:
             break
-        else: break 
+        else: break
         add(n, newLeaf(p))
         inc(p.idx)
       add(father, n)
@@ -694,33 +694,33 @@ when false:
       if p.tok[p.idx].symbol == "_": n = parsePostfix(p, n)
       add(father, n)
 
-proc parseUntil(p: var TRstParser, father: PRstNode, postfix: string, 
-                interpretBackslash: bool) = 
+proc parseUntil(p: var TRstParser, father: PRstNode, postfix: string,
+                interpretBackslash: bool) =
   let
     line = p.tok[p.idx].line
     col = p.tok[p.idx].col
   inc p.idx
-  while true: 
+  while true:
     case p.tok[p.idx].kind
-    of tkPunct: 
-      if isInlineMarkupEnd(p, postfix): 
+    of tkPunct:
+      if isInlineMarkupEnd(p, postfix):
         inc(p.idx)
-        break 
-      elif interpretBackslash: 
+        break
+      elif interpretBackslash:
         parseBackslash(p, father)
-      else: 
+      else:
         add(father, newLeaf(p))
         inc(p.idx)
-    of tkAdornment, tkWord, tkOther: 
+    of tkAdornment, tkWord, tkOther:
       add(father, newLeaf(p))
       inc(p.idx)
-    of tkIndent: 
+    of tkIndent:
       add(father, newRstNode(rnLeaf, " "))
       inc(p.idx)
-      if p.tok[p.idx].kind == tkIndent: 
+      if p.tok[p.idx].kind == tkIndent:
         rstMessage(p, meExpected, postfix, line, col)
-        break 
-    of tkWhite: 
+        break
+    of tkWhite:
       add(father, newRstNode(rnLeaf, " "))
       inc(p.idx)
     else: rstMessage(p, meExpected, postfix, line, col)
@@ -753,20 +753,20 @@ proc parseMarkdownCodeblock(p: var TRstParser): PRstNode =
   result = newRstNode(rnCodeBlock)
   add(result, args)
   add(result, nil)
-  add(result, lb)  
-  
-proc parseInline(p: var TRstParser, father: PRstNode) = 
+  add(result, lb)
+
+proc parseInline(p: var TRstParser, father: PRstNode) =
   case p.tok[p.idx].kind
-  of tkPunct: 
+  of tkPunct:
     if isInlineMarkupStart(p, "***"):
       var n = newRstNode(rnTripleEmphasis)
       parseUntil(p, n, "***", true)
       add(father, n)
-    elif isInlineMarkupStart(p, "**"): 
+    elif isInlineMarkupStart(p, "**"):
       var n = newRstNode(rnStrongEmphasis)
       parseUntil(p, n, "**", true)
       add(father, n)
-    elif isInlineMarkupStart(p, "*"): 
+    elif isInlineMarkupStart(p, "*"):
       var n = newRstNode(rnEmphasis)
       parseUntil(p, n, "*", true)
       add(father, n)
@@ -777,12 +777,12 @@ proc parseInline(p: var TRstParser, father: PRstNode) =
       var n = newRstNode(rnInlineLiteral)
       parseUntil(p, n, "``", false)
       add(father, n)
-    elif isInlineMarkupStart(p, "`"): 
+    elif isInlineMarkupStart(p, "`"):
       var n = newRstNode(rnInterpretedText)
       parseUntil(p, n, "`", true)
       n = parsePostfix(p, n)
       add(father, n)
-    elif isInlineMarkupStart(p, "|"): 
+    elif isInlineMarkupStart(p, "|"):
       var n = newRstNode(rnSubstitutionReferences)
       parseUntil(p, n, "|", false)
       add(father, n)
@@ -800,7 +800,7 @@ proc parseInline(p: var TRstParser, father: PRstNode) =
         add(father, n)
         return
     parseUrl(p, father)
-  of tkAdornment, tkOther, tkWhite: 
+  of tkAdornment, tkOther, tkWhite:
     if roSupportSmilies in p.s.options:
       let n = parseSmiley(p)
       if n != nil:
@@ -809,75 +809,75 @@ proc parseInline(p: var TRstParser, father: PRstNode) =
     add(father, newLeaf(p))
     inc(p.idx)
   else: discard
-  
-proc getDirective(p: var TRstParser): string = 
-  if p.tok[p.idx].kind == tkWhite and p.tok[p.idx+1].kind == tkWord: 
+
+proc getDirective(p: var TRstParser): string =
+  if p.tok[p.idx].kind == tkWhite and p.tok[p.idx+1].kind == tkWord:
     var j = p.idx
     inc(p.idx)
     result = p.tok[p.idx].symbol
     inc(p.idx)
-    while p.tok[p.idx].kind in {tkWord, tkPunct, tkAdornment, tkOther}: 
-      if p.tok[p.idx].symbol == "::": break 
+    while p.tok[p.idx].kind in {tkWord, tkPunct, tkAdornment, tkOther}:
+      if p.tok[p.idx].symbol == "::": break
       add(result, p.tok[p.idx].symbol)
       inc(p.idx)
     if p.tok[p.idx].kind == tkWhite: inc(p.idx)
-    if p.tok[p.idx].symbol == "::": 
+    if p.tok[p.idx].symbol == "::":
       inc(p.idx)
       if (p.tok[p.idx].kind == tkWhite): inc(p.idx)
-    else: 
+    else:
       p.idx = j               # set back
       result = ""             # error
-  else: 
+  else:
     result = ""
-  
-proc parseComment(p: var TRstParser): PRstNode = 
+
+proc parseComment(p: var TRstParser): PRstNode =
   case p.tok[p.idx].kind
-  of tkIndent, tkEof: 
-    if p.tok[p.idx].kind != tkEof and p.tok[p.idx + 1].kind == tkIndent: 
+  of tkIndent, tkEof:
+    if p.tok[p.idx].kind != tkEof and p.tok[p.idx + 1].kind == tkIndent:
       inc(p.idx)              # empty comment
-    else: 
+    else:
       var indent = p.tok[p.idx].ival
-      while true: 
+      while true:
         case p.tok[p.idx].kind
-        of tkEof: 
-          break 
-        of tkIndent: 
-          if (p.tok[p.idx].ival < indent): break 
-        else: 
+        of tkEof:
+          break
+        of tkIndent:
+          if (p.tok[p.idx].ival < indent): break
+        else:
           discard
         inc(p.idx)
   else:
     while p.tok[p.idx].kind notin {tkIndent, tkEof}: inc(p.idx)
   result = nil
 
-type 
+type
   TDirKind = enum             # must be ordered alphabetically!
     dkNone, dkAuthor, dkAuthors, dkCode, dkCodeBlock, dkContainer, dkContents,
     dkFigure, dkImage, dkInclude, dkIndex, dkRaw, dkTitle
 
-const 
+const
   DirIds: array[0..12, string] = ["", "author", "authors", "code",
     "code-block", "container", "contents", "figure", "image", "include",
     "index", "raw", "title"]
 
-proc getDirKind(s: string): TDirKind = 
+proc getDirKind(s: string): TDirKind =
   let i = find(DirIds, s)
   if i >= 0: result = TDirKind(i)
   else: result = dkNone
-  
-proc parseLine(p: var TRstParser, father: PRstNode) = 
-  while true: 
+
+proc parseLine(p: var TRstParser, father: PRstNode) =
+  while true:
     case p.tok[p.idx].kind
     of tkWhite, tkWord, tkOther, tkPunct: parseInline(p, father)
-    else: break 
+    else: break
 
-proc parseUntilNewline(p: var TRstParser, father: PRstNode) = 
-  while true: 
+proc parseUntilNewline(p: var TRstParser, father: PRstNode) =
+  while true:
     case p.tok[p.idx].kind
     of tkWhite, tkWord, tkAdornment, tkOther, tkPunct: parseInline(p, father)
     of tkEof, tkIndent: break
-  
-proc parseSection(p: var TRstParser, result: PRstNode)
+
+proc parseSection(p: var TRstParser, result: PRstNode) {.gcsafe.}
 proc parseField(p: var TRstParser): PRstNode =
   ## Returns a parsed rnField node.
   ##
@@ -888,9 +888,9 @@ proc parseField(p: var TRstParser): PRstNode =
   parseUntil(p, fieldname, ":", false)
   var fieldbody = newRstNode(rnFieldBody)
   if p.tok[p.idx].kind != tkIndent: parseLine(p, fieldbody)
-  if p.tok[p.idx].kind == tkIndent: 
+  if p.tok[p.idx].kind == tkIndent:
     var indent = p.tok[p.idx].ival
-    if indent > col: 
+    if indent > col:
       pushInd(p, indent)
       parseSection(p, fieldbody)
       popInd(p)
@@ -909,14 +909,14 @@ proc parseFields(p: var TRstParser): PRstNode =
     var col = if atStart: p.tok[p.idx].col else: p.tok[p.idx].ival
     result = newRstNode(rnFieldList)
     if not atStart: inc(p.idx)
-    while true: 
+    while true:
       add(result, parseField(p))
       if (p.tok[p.idx].kind == tkIndent) and (p.tok[p.idx].ival == col) and
-          (p.tok[p.idx + 1].symbol == ":"): 
+          (p.tok[p.idx + 1].symbol == ":"):
         inc(p.idx)
-      else: 
-        break 
-  
+      else:
+        break
+
 proc getFieldValue*(n: PRstNode): string =
   ## Returns the value of a specific ``rnField`` node.
   ##
@@ -929,122 +929,122 @@ proc getFieldValue*(n: PRstNode): string =
   assert n.sons[1].kind == rnFieldBody
   result = addNodes(n.sons[1]).strip
 
-proc getFieldValue(n: PRstNode, fieldname: string): string = 
+proc getFieldValue(n: PRstNode, fieldname: string): string =
   result = ""
-  if n.sons[1] == nil: return 
-  if (n.sons[1].kind != rnFieldList): 
+  if n.sons[1] == nil: return
+  if (n.sons[1].kind != rnFieldList):
     #InternalError("getFieldValue (2): " & $n.sons[1].kind)
     # We don't like internal errors here anymore as that would break the forum!
     return
-  for i in countup(0, len(n.sons[1]) - 1): 
+  for i in countup(0, len(n.sons[1]) - 1):
     var f = n.sons[1].sons[i]
-    if cmpIgnoreStyle(addNodes(f.sons[0]), fieldname) == 0: 
+    if cmpIgnoreStyle(addNodes(f.sons[0]), fieldname) == 0:
       result = addNodes(f.sons[1])
       if result == "": result = "\x01\x01" # indicates that the field exists
-      return 
+      return
 
-proc getArgument(n: PRstNode): string = 
+proc getArgument(n: PRstNode): string =
   if n.sons[0] == nil: result = ""
   else: result = addNodes(n.sons[0])
-  
-proc parseDotDot(p: var TRstParser): PRstNode
-proc parseLiteralBlock(p: var TRstParser): PRstNode = 
+
+proc parseDotDot(p: var TRstParser): PRstNode {.gcsafe.}
+proc parseLiteralBlock(p: var TRstParser): PRstNode =
   result = newRstNode(rnLiteralBlock)
   var n = newRstNode(rnLeaf, "")
-  if p.tok[p.idx].kind == tkIndent: 
+  if p.tok[p.idx].kind == tkIndent:
     var indent = p.tok[p.idx].ival
     inc(p.idx)
-    while true: 
+    while true:
       case p.tok[p.idx].kind
-      of tkEof: 
-        break 
-      of tkIndent: 
-        if (p.tok[p.idx].ival < indent): 
-          break 
-        else: 
+      of tkEof:
+        break
+      of tkIndent:
+        if (p.tok[p.idx].ival < indent):
+          break
+        else:
           add(n.text, "\n")
           add(n.text, spaces(p.tok[p.idx].ival - indent))
           inc(p.idx)
-      else: 
+      else:
         add(n.text, p.tok[p.idx].symbol)
         inc(p.idx)
-  else: 
-    while not (p.tok[p.idx].kind in {tkIndent, tkEof}): 
+  else:
+    while not (p.tok[p.idx].kind in {tkIndent, tkEof}):
       add(n.text, p.tok[p.idx].symbol)
       inc(p.idx)
   add(result, n)
 
-proc getLevel(map: var TLevelMap, lvl: var int, c: char): int = 
-  if map[c] == 0: 
+proc getLevel(map: var TLevelMap, lvl: var int, c: char): int =
+  if map[c] == 0:
     inc(lvl)
     map[c] = lvl
   result = map[c]
 
-proc tokenAfterNewline(p: TRstParser): int = 
+proc tokenAfterNewline(p: TRstParser): int =
   result = p.idx
-  while true: 
+  while true:
     case p.tok[result].kind
-    of tkEof: 
-      break 
-    of tkIndent: 
+    of tkEof:
+      break
+    of tkIndent:
       inc(result)
-      break 
+      break
     else: inc(result)
-  
-proc isLineBlock(p: TRstParser): bool = 
+
+proc isLineBlock(p: TRstParser): bool =
   var j = tokenAfterNewline(p)
   result = (p.tok[p.idx].col == p.tok[j].col) and (p.tok[j].symbol == "|") or
       (p.tok[j].col > p.tok[p.idx].col)
 
-proc predNL(p: TRstParser): bool = 
+proc predNL(p: TRstParser): bool =
   result = true
   if p.idx > 0:
     result = p.tok[p.idx-1].kind == tkIndent and
         p.tok[p.idx-1].ival == currInd(p)
-  
-proc isDefList(p: TRstParser): bool = 
+
+proc isDefList(p: TRstParser): bool =
   var j = tokenAfterNewline(p)
   result = (p.tok[p.idx].col < p.tok[j].col) and
       (p.tok[j].kind in {tkWord, tkOther, tkPunct}) and
       (p.tok[j - 2].symbol != "::")
 
-proc isOptionList(p: TRstParser): bool = 
+proc isOptionList(p: TRstParser): bool =
   result = match(p, p.idx, "-w") or match(p, p.idx, "--w") or
            match(p, p.idx, "/w") or match(p, p.idx, "//w")
 
-proc whichSection(p: TRstParser): TRstNodeKind = 
+proc whichSection(p: TRstParser): TRstNodeKind =
   case p.tok[p.idx].kind
-  of tkAdornment: 
+  of tkAdornment:
     if match(p, p.idx + 1, "ii"): result = rnTransition
     elif match(p, p.idx + 1, " a"): result = rnTable
     elif match(p, p.idx + 1, "i"): result = rnOverline
     else: result = rnLeaf
-  of tkPunct: 
-    if match(p, tokenAfterNewline(p), "ai"): 
+  of tkPunct:
+    if match(p, tokenAfterNewline(p), "ai"):
       result = rnHeadline
-    elif p.tok[p.idx].symbol == "::": 
+    elif p.tok[p.idx].symbol == "::":
       result = rnLiteralBlock
     elif predNL(p) and
         ((p.tok[p.idx].symbol == "+") or (p.tok[p.idx].symbol == "*") or
-        (p.tok[p.idx].symbol == "-")) and (p.tok[p.idx + 1].kind == tkWhite): 
+        (p.tok[p.idx].symbol == "-")) and (p.tok[p.idx + 1].kind == tkWhite):
       result = rnBulletList
-    elif (p.tok[p.idx].symbol == "|") and isLineBlock(p): 
+    elif (p.tok[p.idx].symbol == "|") and isLineBlock(p):
       result = rnLineBlock
-    elif (p.tok[p.idx].symbol == "..") and predNL(p): 
+    elif (p.tok[p.idx].symbol == "..") and predNL(p):
       result = rnDirective
     elif match(p, p.idx, ":w:") and predNL(p):
       # (p.tok[p.idx].symbol == ":")
       result = rnFieldList
-    elif match(p, p.idx, "(e) "): 
+    elif match(p, p.idx, "(e) "):
       result = rnEnumList
-    elif match(p, p.idx, "+a+"): 
+    elif match(p, p.idx, "+a+"):
       result = rnGridTable
       rstMessage(p, meGridTableNotImplemented)
-    elif isDefList(p): 
+    elif isDefList(p):
       result = rnDefList
-    elif isOptionList(p): 
+    elif isOptionList(p):
       result = rnOptionList
-    else: 
+    else:
       result = rnParagraph
   of tkWord, tkOther, tkWhite:
     if match(p, tokenAfterNewline(p), "ai"): result = rnHeadline
@@ -1052,58 +1052,58 @@ proc whichSection(p: TRstParser): TRstNodeKind =
     elif isDefList(p): result = rnDefList
     else: result = rnParagraph
   else: result = rnLeaf
-  
-proc parseLineBlock(p: var TRstParser): PRstNode = 
+
+proc parseLineBlock(p: var TRstParser): PRstNode =
   result = nil
-  if p.tok[p.idx + 1].kind == tkWhite: 
+  if p.tok[p.idx + 1].kind == tkWhite:
     var col = p.tok[p.idx].col
     result = newRstNode(rnLineBlock)
     pushInd(p, p.tok[p.idx + 2].col)
     inc(p.idx, 2)
-    while true: 
+    while true:
       var item = newRstNode(rnLineBlockItem)
       parseSection(p, item)
       add(result, item)
       if (p.tok[p.idx].kind == tkIndent) and (p.tok[p.idx].ival == col) and
           (p.tok[p.idx + 1].symbol == "|") and
-          (p.tok[p.idx + 2].kind == tkWhite): 
+          (p.tok[p.idx + 2].kind == tkWhite):
         inc(p.idx, 3)
-      else: 
-        break 
+      else:
+        break
     popInd(p)
 
-proc parseParagraph(p: var TRstParser, result: PRstNode) = 
-  while true: 
+proc parseParagraph(p: var TRstParser, result: PRstNode) =
+  while true:
     case p.tok[p.idx].kind
-    of tkIndent: 
-      if p.tok[p.idx + 1].kind == tkIndent: 
+    of tkIndent:
+      if p.tok[p.idx + 1].kind == tkIndent:
         inc(p.idx)
-        break 
-      elif (p.tok[p.idx].ival == currInd(p)): 
+        break
+      elif (p.tok[p.idx].ival == currInd(p)):
         inc(p.idx)
         case whichSection(p)
-        of rnParagraph, rnLeaf, rnHeadline, rnOverline, rnDirective: 
+        of rnParagraph, rnLeaf, rnHeadline, rnOverline, rnDirective:
           add(result, newRstNode(rnLeaf, " "))
-        of rnLineBlock: 
+        of rnLineBlock:
           addIfNotNil(result, parseLineBlock(p))
-        else: break 
-      else: 
-        break 
-    of tkPunct: 
+        else: break
+      else:
+        break
+    of tkPunct:
       if (p.tok[p.idx].symbol == "::") and
           (p.tok[p.idx + 1].kind == tkIndent) and
-          (currInd(p) < p.tok[p.idx + 1].ival): 
+          (currInd(p) < p.tok[p.idx + 1].ival):
         add(result, newRstNode(rnLeaf, ":"))
         inc(p.idx)            # skip '::'
         add(result, parseLiteralBlock(p))
-        break 
-      else: 
+        break
+      else:
         parseInline(p, result)
-    of tkWhite, tkWord, tkAdornment, tkOther: 
+    of tkWhite, tkWord, tkAdornment, tkOther:
       parseInline(p, result)
     else: break
 
-proc parseHeadline(p: var TRstParser): PRstNode = 
+proc parseHeadline(p: var TRstParser): PRstNode =
   result = newRstNode(rnHeadline)
   parseUntilNewline(p, result)
   assert(p.tok[p.idx].kind == tkIndent)
@@ -1112,31 +1112,31 @@ proc parseHeadline(p: var TRstParser): PRstNode =
   inc(p.idx, 2)
   result.level = getLevel(p.s.underlineToLevel, p.s.uLevel, c)
 
-type 
+type
   TIntSeq = seq[int]
 
-proc tokEnd(p: TRstParser): int = 
+proc tokEnd(p: TRstParser): int =
   result = p.tok[p.idx].col + len(p.tok[p.idx].symbol) - 1
 
-proc getColumns(p: var TRstParser, cols: var TIntSeq) = 
+proc getColumns(p: var TRstParser, cols: var TIntSeq) =
   var L = 0
-  while true: 
+  while true:
     inc(L)
     setLen(cols, L)
     cols[L - 1] = tokEnd(p)
     assert(p.tok[p.idx].kind == tkAdornment)
     inc(p.idx)
-    if p.tok[p.idx].kind != tkWhite: break 
+    if p.tok[p.idx].kind != tkWhite: break
     inc(p.idx)
-    if p.tok[p.idx].kind != tkAdornment: break 
-  if p.tok[p.idx].kind == tkIndent: inc(p.idx)                
+    if p.tok[p.idx].kind != tkAdornment: break
+  if p.tok[p.idx].kind == tkIndent: inc(p.idx)
   # last column has no limit:
   cols[L - 1] = 32000
 
-proc parseDoc(p: var TRstParser): PRstNode
+proc parseDoc(p: var TRstParser): PRstNode {.gcsafe.}
 
-proc parseSimpleTable(p: var TRstParser): PRstNode = 
-  var 
+proc parseSimpleTable(p: var TRstParser): PRstNode =
+  var
     cols: TIntSeq
     row: seq[string]
     i, last, line: int
@@ -1148,36 +1148,36 @@ proc parseSimpleTable(p: var TRstParser): PRstNode =
   row = @[]
   a = nil
   c = p.tok[p.idx].symbol[0]
-  while true: 
-    if p.tok[p.idx].kind == tkAdornment: 
+  while true:
+    if p.tok[p.idx].kind == tkAdornment:
       last = tokenAfterNewline(p)
-      if p.tok[last].kind in {tkEof, tkIndent}: 
+      if p.tok[last].kind in {tkEof, tkIndent}:
         # skip last adornment line:
         p.idx = last
-        break 
+        break
       getColumns(p, cols)
       setLen(row, len(cols))
-      if a != nil: 
+      if a != nil:
         for j in 0..len(a)-1: a.sons[j].kind = rnTableHeaderCell
-    if p.tok[p.idx].kind == tkEof: break 
+    if p.tok[p.idx].kind == tkEof: break
     for j in countup(0, high(row)): row[j] = ""
     # the following while loop iterates over the lines a single cell may span:
     line = p.tok[p.idx].line
-    while true: 
+    while true:
       i = 0
-      while not (p.tok[p.idx].kind in {tkIndent, tkEof}): 
-        if (tokEnd(p) <= cols[i]): 
+      while not (p.tok[p.idx].kind in {tkIndent, tkEof}):
+        if (tokEnd(p) <= cols[i]):
           add(row[i], p.tok[p.idx].symbol)
           inc(p.idx)
-        else: 
+        else:
           if p.tok[p.idx].kind == tkWhite: inc(p.idx)
           inc(i)
       if p.tok[p.idx].kind == tkIndent: inc(p.idx)
-      if tokEnd(p) <= cols[0]: break 
-      if p.tok[p.idx].kind in {tkEof, tkAdornment}: break 
+      if tokEnd(p) <= cols[0]: break
+      if p.tok[p.idx].kind in {tkEof, tkAdornment}: break
       for j in countup(1, high(row)): add(row[j], '\x0A')
     a = newRstNode(rnTableRow)
-    for j in countup(0, high(row)): 
+    for j in countup(0, high(row)):
       initParser(q, p.s)
       q.col = cols[j]
       q.line = line - 1
@@ -1188,95 +1188,95 @@ proc parseSimpleTable(p: var TRstParser): PRstNode =
       add(a, b)
     add(result, a)
 
-proc parseTransition(p: var TRstParser): PRstNode = 
+proc parseTransition(p: var TRstParser): PRstNode =
   result = newRstNode(rnTransition)
   inc(p.idx)
   if p.tok[p.idx].kind == tkIndent: inc(p.idx)
   if p.tok[p.idx].kind == tkIndent: inc(p.idx)
-  
-proc parseOverline(p: var TRstParser): PRstNode = 
+
+proc parseOverline(p: var TRstParser): PRstNode =
   var c = p.tok[p.idx].symbol[0]
   inc(p.idx, 2)
   result = newRstNode(rnOverline)
-  while true: 
+  while true:
     parseUntilNewline(p, result)
-    if p.tok[p.idx].kind == tkIndent: 
+    if p.tok[p.idx].kind == tkIndent:
       inc(p.idx)
-      if p.tok[p.idx - 1].ival > currInd(p): 
+      if p.tok[p.idx - 1].ival > currInd(p):
         add(result, newRstNode(rnLeaf, " "))
-      else: 
-        break 
-    else: 
-      break 
+      else:
+        break
+    else:
+      break
   result.level = getLevel(p.s.overlineToLevel, p.s.oLevel, c)
-  if p.tok[p.idx].kind == tkAdornment: 
+  if p.tok[p.idx].kind == tkAdornment:
     inc(p.idx)                # XXX: check?
     if p.tok[p.idx].kind == tkIndent: inc(p.idx)
-  
-proc parseBulletList(p: var TRstParser): PRstNode = 
+
+proc parseBulletList(p: var TRstParser): PRstNode =
   result = nil
-  if p.tok[p.idx + 1].kind == tkWhite: 
+  if p.tok[p.idx + 1].kind == tkWhite:
     var bullet = p.tok[p.idx].symbol
     var col = p.tok[p.idx].col
     result = newRstNode(rnBulletList)
     pushInd(p, p.tok[p.idx + 2].col)
     inc(p.idx, 2)
-    while true: 
+    while true:
       var item = newRstNode(rnBulletItem)
       parseSection(p, item)
       add(result, item)
       if (p.tok[p.idx].kind == tkIndent) and (p.tok[p.idx].ival == col) and
           (p.tok[p.idx + 1].symbol == bullet) and
-          (p.tok[p.idx + 2].kind == tkWhite): 
+          (p.tok[p.idx + 2].kind == tkWhite):
         inc(p.idx, 3)
-      else: 
-        break 
+      else:
+        break
     popInd(p)
 
-proc parseOptionList(p: var TRstParser): PRstNode = 
+proc parseOptionList(p: var TRstParser): PRstNode =
   result = newRstNode(rnOptionList)
-  while true: 
+  while true:
     if isOptionList(p):
       var a = newRstNode(rnOptionGroup)
       var b = newRstNode(rnDescription)
       var c = newRstNode(rnOptionListItem)
       if match(p, p.idx, "//w"): inc(p.idx)
-      while not (p.tok[p.idx].kind in {tkIndent, tkEof}): 
-        if (p.tok[p.idx].kind == tkWhite) and (len(p.tok[p.idx].symbol) > 1): 
+      while not (p.tok[p.idx].kind in {tkIndent, tkEof}):
+        if (p.tok[p.idx].kind == tkWhite) and (len(p.tok[p.idx].symbol) > 1):
           inc(p.idx)
-          break 
+          break
         add(a, newLeaf(p))
         inc(p.idx)
       var j = tokenAfterNewline(p)
       if (j > 0) and (p.tok[j - 1].kind == tkIndent) and
-          (p.tok[j - 1].ival > currInd(p)): 
+          (p.tok[j - 1].ival > currInd(p)):
         pushInd(p, p.tok[j - 1].ival)
         parseSection(p, b)
         popInd(p)
-      else: 
+      else:
         parseLine(p, b)
       if (p.tok[p.idx].kind == tkIndent): inc(p.idx)
       add(c, a)
       add(c, b)
       add(result, c)
-    else: 
-      break 
-  
-proc parseDefinitionList(p: var TRstParser): PRstNode = 
+    else:
+      break
+
+proc parseDefinitionList(p: var TRstParser): PRstNode =
   result = nil
   var j = tokenAfterNewline(p) - 1
   if (j >= 1) and (p.tok[j].kind == tkIndent) and
-      (p.tok[j].ival > currInd(p)) and (p.tok[j - 1].symbol != "::"): 
+      (p.tok[j].ival > currInd(p)) and (p.tok[j - 1].symbol != "::"):
     var col = p.tok[p.idx].col
     result = newRstNode(rnDefList)
-    while true: 
+    while true:
       j = p.idx
       var a = newRstNode(rnDefName)
       parseLine(p, a)
       if (p.tok[p.idx].kind == tkIndent) and
           (p.tok[p.idx].ival > currInd(p)) and
           (p.tok[p.idx + 1].symbol != "::") and
-          not (p.tok[p.idx + 1].kind in {tkIndent, tkEof}): 
+          not (p.tok[p.idx + 1].kind in {tkIndent, tkEof}):
         pushInd(p, p.tok[p.idx].ival)
         var b = newRstNode(rnDefBody)
         parseSection(p, b)
@@ -1285,74 +1285,74 @@ proc parseDefinitionList(p: var TRstParser): PRstNode =
         add(c, b)
         add(result, c)
         popInd(p)
-      else: 
+      else:
         p.idx = j
-        break 
-      if (p.tok[p.idx].kind == tkIndent) and (p.tok[p.idx].ival == col): 
+        break
+      if (p.tok[p.idx].kind == tkIndent) and (p.tok[p.idx].ival == col):
         inc(p.idx)
         j = tokenAfterNewline(p) - 1
         if j >= 1 and p.tok[j].kind == tkIndent and p.tok[j].ival > col and
-            p.tok[j-1].symbol != "::" and p.tok[j+1].kind != tkIndent: 
+            p.tok[j-1].symbol != "::" and p.tok[j+1].kind != tkIndent:
           discard
-        else: 
-          break 
+        else:
+          break
     if len(result) == 0: result = nil
-  
-proc parseEnumList(p: var TRstParser): PRstNode = 
-  const 
+
+proc parseEnumList(p: var TRstParser): PRstNode =
+  const
     wildcards: array[0..2, string] = ["(e) ", "e) ", "e. "]
     wildpos: array[0..2, int] = [1, 0, 0]
   result = nil
   var w = 0
-  while w <= 2: 
-    if match(p, p.idx, wildcards[w]): break 
+  while w <= 2:
+    if match(p, p.idx, wildcards[w]): break
     inc(w)
-  if w <= 2: 
+  if w <= 2:
     var col = p.tok[p.idx].col
     result = newRstNode(rnEnumList)
     inc(p.idx, wildpos[w] + 3)
     var j = tokenAfterNewline(p)
-    if (p.tok[j].col == p.tok[p.idx].col) or match(p, j, wildcards[w]): 
+    if (p.tok[j].col == p.tok[p.idx].col) or match(p, j, wildcards[w]):
       pushInd(p, p.tok[p.idx].col)
-      while true: 
+      while true:
         var item = newRstNode(rnEnumItem)
         parseSection(p, item)
         add(result, item)
         if (p.tok[p.idx].kind == tkIndent) and (p.tok[p.idx].ival == col) and
-            match(p, p.idx + 1, wildcards[w]): 
+            match(p, p.idx + 1, wildcards[w]):
           inc(p.idx, wildpos[w] + 4)
-        else: 
-          break 
+        else:
+          break
       popInd(p)
-    else: 
+    else:
       dec(p.idx, wildpos[w] + 3)
       result = nil
 
-proc sonKind(father: PRstNode, i: int): TRstNodeKind = 
+proc sonKind(father: PRstNode, i: int): TRstNodeKind =
   result = rnLeaf
   if i < len(father): result = father.sons[i].kind
-  
-proc parseSection(p: var TRstParser, result: PRstNode) = 
-  while true: 
+
+proc parseSection(p: var TRstParser, result: PRstNode) =
+  while true:
     var leave = false
     assert(p.idx >= 0)
-    while p.tok[p.idx].kind == tkIndent: 
-      if currInd(p) == p.tok[p.idx].ival: 
+    while p.tok[p.idx].kind == tkIndent:
+      if currInd(p) == p.tok[p.idx].ival:
         inc(p.idx)
-      elif p.tok[p.idx].ival > currInd(p): 
+      elif p.tok[p.idx].ival > currInd(p):
         pushInd(p, p.tok[p.idx].ival)
         var a = newRstNode(rnBlockQuote)
         parseSection(p, a)
         add(result, a)
         popInd(p)
-      else: 
+      else:
         leave = true
         break
     if leave or p.tok[p.idx].kind == tkEof: break
     var a: PRstNode = nil
     var k = whichSection(p)
     case k
-    of rnLiteralBlock: 
+    of rnLiteralBlock:
       inc(p.idx)              # skip '::'
       a = parseLiteralBlock(p)
     of rnBulletList: a = parseBulletList(p)
@@ -1362,7 +1362,7 @@ proc parseSection(p: var TRstParser, result: PRstNode) =
     of rnLeaf: rstMessage(p, meNewSectionExpected)
     of rnParagraph: discard
     of rnDefList: a = parseDefinitionList(p)
-    of rnFieldList: 
+    of rnFieldList:
       if p.idx > 0: dec(p.idx)
       a = parseFields(p)
     of rnTransition: a = parseTransition(p)
@@ -1373,35 +1373,35 @@ proc parseSection(p: var TRstParser, result: PRstNode) =
     else:
       #InternalError("rst.parseSection()")
       discard
-    if a == nil and k != rnDirective: 
+    if a == nil and k != rnDirective:
       a = newRstNode(rnParagraph)
       parseParagraph(p, a)
     addIfNotNil(result, a)
-  if sonKind(result, 0) == rnParagraph and sonKind(result, 1) != rnParagraph: 
+  if sonKind(result, 0) == rnParagraph and sonKind(result, 1) != rnParagraph:
     result.sons[0].kind = rnInner
-  
-proc parseSectionWrapper(p: var TRstParser): PRstNode = 
+
+proc parseSectionWrapper(p: var TRstParser): PRstNode =
   result = newRstNode(rnInner)
   parseSection(p, result)
-  while (result.kind == rnInner) and (len(result) == 1): 
+  while (result.kind == rnInner) and (len(result) == 1):
     result = result.sons[0]
-  
+
 proc `$`(t: TToken): string =
   result = $t.kind & ' ' & (if isNil(t.symbol): "NIL" else: t.symbol)
 
-proc parseDoc(p: var TRstParser): PRstNode = 
+proc parseDoc(p: var TRstParser): PRstNode =
   result = parseSectionWrapper(p)
-  if p.tok[p.idx].kind != tkEof: 
+  if p.tok[p.idx].kind != tkEof:
     when false:
       assert isAllocatedPtr(cast[pointer](p.tok))
       for i in 0 .. high(p.tok):
-        assert isNil(p.tok[i].symbol) or 
+        assert isNil(p.tok[i].symbol) or
                isAllocatedPtr(cast[pointer](p.tok[i].symbol))
       echo "index: ", p.idx, " length: ", high(p.tok), "##",
           p.tok[p.idx-1], p.tok[p.idx], p.tok[p.idx+1]
     #assert isAllocatedPtr(cast[pointer](p.indentStack))
     rstMessage(p, meGeneralParseError)
-  
+
 type
   TDirFlag = enum
     hasArg, hasOptions, argIsFile, argIsWord
@@ -1421,55 +1421,55 @@ proc parseDirective(p: var TRstParser, flags: TDirFlags): PRstNode =
   result = newRstNode(rnDirective)
   var args: PRstNode = nil
   var options: PRstNode = nil
-  if hasArg in flags: 
+  if hasArg in flags:
     args = newRstNode(rnDirArg)
-    if argIsFile in flags: 
-      while true: 
+    if argIsFile in flags:
+      while true:
         case p.tok[p.idx].kind
-        of tkWord, tkOther, tkPunct, tkAdornment: 
+        of tkWord, tkOther, tkPunct, tkAdornment:
           add(args, newLeaf(p))
           inc(p.idx)
-        else: break 
+        else: break
     elif argIsWord in flags:
       while p.tok[p.idx].kind == tkWhite: inc(p.idx)
-      if p.tok[p.idx].kind == tkWord: 
+      if p.tok[p.idx].kind == tkWord:
         add(args, newLeaf(p))
         inc(p.idx)
       else:
         args = nil
-    else: 
+    else:
       parseLine(p, args)
   add(result, args)
-  if hasOptions in flags: 
+  if hasOptions in flags:
     if (p.tok[p.idx].kind == tkIndent) and (p.tok[p.idx].ival >= 3) and
-        (p.tok[p.idx + 1].symbol == ":"): 
+        (p.tok[p.idx + 1].symbol == ":"):
       options = parseFields(p)
   add(result, options)
-  
-proc indFollows(p: TRstParser): bool = 
+
+proc indFollows(p: TRstParser): bool =
   result = p.tok[p.idx].kind == tkIndent and p.tok[p.idx].ival > currInd(p)
-  
-proc parseDirective(p: var TRstParser, flags: TDirFlags, 
-                    contentParser: TSectionParser): PRstNode = 
+
+proc parseDirective(p: var TRstParser, flags: TDirFlags,
+                    contentParser: TSectionParser): PRstNode =
   ## Returns a generic rnDirective tree.
   ##
   ## The children are rnDirArg, rnFieldList and rnLineBlock. Any might be nil.
   result = parseDirective(p, flags)
-  if not isNil(contentParser) and indFollows(p): 
+  if not isNil(contentParser) and indFollows(p):
     pushInd(p, p.tok[p.idx].ival)
     var content = contentParser(p)
     popInd(p)
     add(result, content)
-  else: 
+  else:
     add(result, nil)
 
-proc parseDirBody(p: var TRstParser, contentParser: TSectionParser): PRstNode = 
-  if indFollows(p): 
+proc parseDirBody(p: var TRstParser, contentParser: TSectionParser): PRstNode =
+  if indFollows(p):
     pushInd(p, p.tok[p.idx].ival)
     result = contentParser(p)
     popInd(p)
-  
-proc dirInclude(p: var TRstParser): PRstNode = 
+
+proc dirInclude(p: var TRstParser): PRstNode =
   #
   #The following options are recognized:
   #
@@ -1490,18 +1490,18 @@ proc dirInclude(p: var TRstParser): PRstNode =
   var n = parseDirective(p, {hasArg, argIsFile, hasOptions}, nil)
   var filename = strip(addNodes(n.sons[0]))
   var path = p.s.findFile(filename)
-  if path == "": 
+  if path == "":
     rstMessage(p, meCannotOpenFile, filename)
-  else: 
+  else:
     # XXX: error handling; recursive file inclusion!
-    if getFieldValue(n, "literal") != "": 
+    if getFieldValue(n, "literal") != "":
       result = newRstNode(rnLiteralBlock)
       add(result, newRstNode(rnLeaf, readFile(path)))
     else:
       var q: TRstParser
       initParser(q, p.s)
       q.filename = filename
-      q.col += getTokens(readFile(path), false, q.tok) 
+      q.col += getTokens(readFile(path), false, q.tok)
       # workaround a GCC bug; more like the interior pointer bug?
       #if find(q.tok[high(q.tok)].symbol, "\0\x01\x02") > 0:
       #  InternalError("Too many binary zeros in include file")
@@ -1526,7 +1526,7 @@ proc dirCodeBlock(p: var TRstParser, nimrodExtension = false): PRstNode =
   ## file.
   result = parseDirective(p, {hasArg, hasOptions}, parseLiteralBlock)
   var filename = strip(getFieldValue(result, "file"))
-  if filename != "": 
+  if filename != "":
     var path = p.s.findFile(filename)
     if path == "": rstMessage(p, meCannotOpenFile, filename)
     var n = newRstNode(rnLiteralBlock)
@@ -1548,49 +1548,49 @@ proc dirCodeBlock(p: var TRstParser, nimrodExtension = false): PRstNode =
 
   result.kind = rnCodeBlock
 
-proc dirContainer(p: var TRstParser): PRstNode = 
+proc dirContainer(p: var TRstParser): PRstNode =
   result = parseDirective(p, {hasArg}, parseSectionWrapper)
   assert(result.kind == rnDirective)
   assert(len(result) == 3)
   result.kind = rnContainer
 
-proc dirImage(p: var TRstParser): PRstNode = 
+proc dirImage(p: var TRstParser): PRstNode =
   result = parseDirective(p, {hasOptions, hasArg, argIsFile}, nil)
   result.kind = rnImage
 
-proc dirFigure(p: var TRstParser): PRstNode = 
-  result = parseDirective(p, {hasOptions, hasArg, argIsFile}, 
+proc dirFigure(p: var TRstParser): PRstNode =
+  result = parseDirective(p, {hasOptions, hasArg, argIsFile},
                           parseSectionWrapper)
   result.kind = rnFigure
 
-proc dirTitle(p: var TRstParser): PRstNode = 
+proc dirTitle(p: var TRstParser): PRstNode =
   result = parseDirective(p, {hasArg}, nil)
   result.kind = rnTitle
 
-proc dirContents(p: var TRstParser): PRstNode = 
+proc dirContents(p: var TRstParser): PRstNode =
   result = parseDirective(p, {hasArg}, nil)
   result.kind = rnContents
 
-proc dirIndex(p: var TRstParser): PRstNode = 
+proc dirIndex(p: var TRstParser): PRstNode =
   result = parseDirective(p, {}, parseSectionWrapper)
   result.kind = rnIndex
 
 proc dirRawAux(p: var TRstParser, result: var PRstNode, kind: TRstNodeKind,
-               contentParser: TSectionParser) = 
+               contentParser: TSectionParser) =
   var filename = getFieldValue(result, "file")
-  if filename.len > 0: 
+  if filename.len > 0:
     var path = p.s.findFile(filename)
-    if path.len == 0: 
+    if path.len == 0:
       rstMessage(p, meCannotOpenFile, filename)
-    else: 
+    else:
       var f = readFile(path)
       result = newRstNode(kind)
       add(result, newRstNode(rnLeaf, f))
-  else:      
+  else:
     result.kind = kind
     add(result, parseDirBody(p, contentParser))
 
-proc dirRaw(p: var TRstParser): PRstNode = 
+proc dirRaw(p: var TRstParser): PRstNode =
   #
   #The following options are recognized:
   #
@@ -1603,19 +1603,19 @@ proc dirRaw(p: var TRstParser): PRstNode =
   if result.sons[0] != nil:
     if cmpIgnoreCase(result.sons[0].sons[0].text, "html") == 0:
       dirRawAux(p, result, rnRawHtml, parseLiteralBlock)
-    elif cmpIgnoreCase(result.sons[0].sons[0].text, "latex") == 0: 
+    elif cmpIgnoreCase(result.sons[0].sons[0].text, "latex") == 0:
       dirRawAux(p, result, rnRawLatex, parseLiteralBlock)
     else:
       rstMessage(p, meInvalidDirective, result.sons[0].sons[0].text)
   else:
     dirRawAux(p, result, rnRaw, parseSectionWrapper)
 
-proc parseDotDot(p: var TRstParser): PRstNode = 
+proc parseDotDot(p: var TRstParser): PRstNode =
   result = nil
   var col = p.tok[p.idx].col
   inc(p.idx)
   var d = getDirective(p)
-  if d != "": 
+  if d != "":
     pushInd(p, col)
     case getDirKind(d)
     of dkInclude: result = dirInclude(p)
@@ -1634,66 +1634,66 @@ proc parseDotDot(p: var TRstParser): PRstNode =
     of dkIndex: result = dirIndex(p)
     else: rstMessage(p, meInvalidDirective, d)
     popInd(p)
-  elif match(p, p.idx, " _"): 
+  elif match(p, p.idx, " _"):
     # hyperlink target:
     inc(p.idx, 2)
     var a = getReferenceName(p, ":")
     if p.tok[p.idx].kind == tkWhite: inc(p.idx)
     var b = untilEol(p)
     setRef(p, rstnodeToRefname(a), b)
-  elif match(p, p.idx, " |"): 
+  elif match(p, p.idx, " |"):
     # substitution definitions:
     inc(p.idx, 2)
     var a = getReferenceName(p, "|")
     var b: PRstNode
     if p.tok[p.idx].kind == tkWhite: inc(p.idx)
-    if cmpIgnoreStyle(p.tok[p.idx].symbol, "replace") == 0: 
+    if cmpIgnoreStyle(p.tok[p.idx].symbol, "replace") == 0:
       inc(p.idx)
       expect(p, "::")
       b = untilEol(p)
-    elif cmpIgnoreStyle(p.tok[p.idx].symbol, "image") == 0: 
+    elif cmpIgnoreStyle(p.tok[p.idx].symbol, "image") == 0:
       inc(p.idx)
       b = dirImage(p)
-    else: 
+    else:
       rstMessage(p, meInvalidDirective, p.tok[p.idx].symbol)
     setSub(p, addNodes(a), b)
-  elif match(p, p.idx, " ["): 
+  elif match(p, p.idx, " ["):
     # footnotes, citations
     inc(p.idx, 2)
     var a = getReferenceName(p, "]")
     if p.tok[p.idx].kind == tkWhite: inc(p.idx)
     var b = untilEol(p)
     setRef(p, rstnodeToRefname(a), b)
-  else: 
+  else:
     result = parseComment(p)
-  
-proc resolveSubs(p: var TRstParser, n: PRstNode): PRstNode = 
+
+proc resolveSubs(p: var TRstParser, n: PRstNode): PRstNode =
   result = n
-  if n == nil: return 
+  if n == nil: return
   case n.kind
-  of rnSubstitutionReferences: 
+  of rnSubstitutionReferences:
     var x = findSub(p, n)
-    if x >= 0: 
+    if x >= 0:
       result = p.s.subs[x].value
-    else: 
+    else:
       var key = addNodes(n)
       var e = getEnv(key)
       if e != "": result = newRstNode(rnLeaf, e)
       else: rstMessage(p, mwUnknownSubstitution, key)
-  of rnRef: 
+  of rnRef:
     var y = findRef(p, rstnodeToRefname(n))
-    if y != nil: 
+    if y != nil:
       result = newRstNode(rnHyperlink)
       n.kind = rnInner
       add(result, n)
       add(result, y)
-  of rnLeaf: 
+  of rnLeaf:
     discard
-  of rnContents: 
+  of rnContents:
     p.hasToc = true
-  else: 
+  else:
     for i in countup(0, len(n) - 1): n.sons[i] = resolveSubs(p, n.sons[i])
-  
+
 proc rstParse*(text, filename: string,
                line, column: int, hasToc: var bool,
                options: TRstParseOptions,
diff --git a/lib/packages/docutils/rstast.nim b/lib/packages/docutils/rstast.nim
index 614001d76..c3956ab8b 100644
--- a/lib/packages/docutils/rstast.nim
+++ b/lib/packages/docutils/rstast.nim
@@ -30,7 +30,7 @@ type
     rnField,                  # a field item
     rnFieldName,              # consisting of a field name ...
     rnFieldBody,              # ... and a field body
-    rnOptionList, rnOptionListItem, rnOptionGroup, rnOption, rnOptionString, 
+    rnOptionList, rnOptionListItem, rnOptionGroup, rnOption, rnOptionString,
     rnOptionArgument, rnDescription, rnLiteralBlock, rnQuotedLiteralBlock,
     rnLineBlock,              # the | thingie
     rnLineBlockItem,          # sons of the | thing
@@ -50,7 +50,7 @@ type
                               #     * `file#id <file#id>'_
     rnSubstitutionDef,        # a definition of a substitution
     rnGeneralRole,            # Inline markup:
-    rnSub, rnSup, rnIdx, 
+    rnSub, rnSup, rnIdx,
     rnEmphasis,               # "*"
     rnStrongEmphasis,         # "**"
     rnTripleEmphasis,         # "***"
@@ -71,25 +71,25 @@ type
     level*: int               ## valid for some node kinds
     sons*: TRstNodeSeq        ## the node's sons
 
-proc len*(n: PRstNode): int = 
+proc len*(n: PRstNode): int =
   result = len(n.sons)
 
-proc newRstNode*(kind: TRstNodeKind): PRstNode = 
+proc newRstNode*(kind: TRstNodeKind): PRstNode =
   new(result)
   result.sons = @[]
   result.kind = kind
 
-proc newRstNode*(kind: TRstNodeKind, s: string): PRstNode = 
+proc newRstNode*(kind: TRstNodeKind, s: string): PRstNode =
   result = newRstNode(kind)
   result.text = s
 
-proc lastSon*(n: PRstNode): PRstNode = 
+proc lastSon*(n: PRstNode): PRstNode =
   result = n.sons[len(n.sons)-1]
 
 proc add*(father, son: PRstNode) =
   add(father.sons, son)
 
-proc addIfNotNil*(father, son: PRstNode) = 
+proc addIfNotNil*(father, son: PRstNode) =
   if son != nil: add(father, son)
 
 
@@ -98,26 +98,27 @@ type
     indent: int
     verbatim: int
 
-proc renderRstToRst(d: var TRenderContext, n: PRstNode, result: var string)
+proc renderRstToRst(d: var TRenderContext, n: PRstNode,
+                    result: var string) {.gcsafe.}
 
-proc renderRstSons(d: var TRenderContext, n: PRstNode, result: var string) = 
-  for i in countup(0, len(n) - 1): 
+proc renderRstSons(d: var TRenderContext, n: PRstNode, result: var string) =
+  for i in countup(0, len(n) - 1):
     renderRstToRst(d, n.sons[i], result)
-  
+
 proc renderRstToRst(d: var TRenderContext, n: PRstNode, result: var string) =
   # this is needed for the index generation; it may also be useful for
   # debugging, but most code is already debugged...
-  const 
+  const
     lvlToChar: array[0..8, char] = ['!', '=', '-', '~', '`', '<', '*', '|', '+']
   if n == nil: return
   var ind = spaces(d.indent)
   case n.kind
-  of rnInner: 
+  of rnInner:
     renderRstSons(d, n, result)
   of rnHeadline:
     result.add("\n")
     result.add(ind)
-    
+
     let oldLen = result.len
     renderRstSons(d, n, result)
     let headlineLen = result.len - oldLen
@@ -131,16 +132,16 @@ proc renderRstToRst(d: var TRenderContext, n: PRstNode, result: var string) =
 
     var headline = ""
     renderRstSons(d, n, headline)
-    
+
     let lvl = repeat(lvlToChar[n.level], headline.len - d.indent)
     result.add(lvl)
     result.add("\n")
     result.add(headline)
-    
+
     result.add("\n")
     result.add(ind)
     result.add(lvl)
-  of rnTransition: 
+  of rnTransition:
     result.add("\n\n")
     result.add(ind)
     result.add repeat('-', 78-d.indent)
@@ -149,11 +150,11 @@ proc renderRstToRst(d: var TRenderContext, n: PRstNode, result: var string) =
     result.add("\n\n")
     result.add(ind)
     renderRstSons(d, n, result)
-  of rnBulletItem: 
+  of rnBulletItem:
     inc(d.indent, 2)
     var tmp = ""
     renderRstSons(d, n, tmp)
-    if tmp.len > 0: 
+    if tmp.len > 0:
       result.add("\n")
       result.add(ind)
       result.add("* ")
@@ -163,22 +164,22 @@ proc renderRstToRst(d: var TRenderContext, n: PRstNode, result: var string) =
     inc(d.indent, 4)
     var tmp = ""
     renderRstSons(d, n, tmp)
-    if tmp.len > 0: 
+    if tmp.len > 0:
       result.add("\n")
       result.add(ind)
       result.add("(#) ")
       result.add(tmp)
     dec(d.indent, 4)
-  of rnOptionList, rnFieldList, rnDefList, rnDefItem, rnLineBlock, rnFieldName, 
-     rnFieldBody, rnStandaloneHyperlink, rnBulletList, rnEnumList: 
+  of rnOptionList, rnFieldList, rnDefList, rnDefItem, rnLineBlock, rnFieldName,
+     rnFieldBody, rnStandaloneHyperlink, rnBulletList, rnEnumList:
     renderRstSons(d, n, result)
-  of rnDefName: 
+  of rnDefName:
     result.add("\n\n")
     result.add(ind)
     renderRstSons(d, n, result)
   of rnDefBody:
     inc(d.indent, 2)
-    if n.sons[0].kind != rnBulletList: 
+    if n.sons[0].kind != rnBulletList:
       result.add("\n")
       result.add(ind)
       result.add("  ")
@@ -187,10 +188,10 @@ proc renderRstToRst(d: var TRenderContext, n: PRstNode, result: var string) =
   of rnField:
     var tmp = ""
     renderRstToRst(d, n.sons[0], tmp)
-    
+
     var L = max(tmp.len + 3, 30)
     inc(d.indent, L)
-    
+
     result.add "\n"
     result.add ind
     result.add ':'
@@ -198,9 +199,9 @@ proc renderRstToRst(d: var TRenderContext, n: PRstNode, result: var string) =
     result.add ':'
     result.add spaces(L - tmp.len - 2)
     renderRstToRst(d, n.sons[1], result)
-    
+
     dec(d.indent, L)
-  of rnLineBlockItem: 
+  of rnLineBlockItem:
     result.add("\n")
     result.add(ind)
     result.add("| ")
@@ -209,11 +210,11 @@ proc renderRstToRst(d: var TRenderContext, n: PRstNode, result: var string) =
     inc(d.indent, 2)
     renderRstSons(d, n, result)
     dec(d.indent, 2)
-  of rnRef: 
+  of rnRef:
     result.add("`")
     renderRstSons(d, n, result)
     result.add("`_")
-  of rnHyperlink: 
+  of rnHyperlink:
     result.add('`')
     renderRstToRst(d, n.sons[0], result)
     result.add(" <")
@@ -225,23 +226,23 @@ proc renderRstToRst(d: var TRenderContext, n: PRstNode, result: var string) =
     result.add("`:")
     renderRstToRst(d, n.sons[1],result)
     result.add(':')
-  of rnSub: 
+  of rnSub:
     result.add('`')
     renderRstSons(d, n, result)
     result.add("`:sub:")
-  of rnSup: 
+  of rnSup:
     result.add('`')
     renderRstSons(d, n, result)
     result.add("`:sup:")
-  of rnIdx: 
+  of rnIdx:
     result.add('`')
     renderRstSons(d, n, result)
     result.add("`:idx:")
-  of rnEmphasis: 
+  of rnEmphasis:
     result.add("*")
     renderRstSons(d, n, result)
     result.add("*")
-  of rnStrongEmphasis: 
+  of rnStrongEmphasis:
     result.add("**")
     renderRstSons(d, n, result)
     result.add("**")
@@ -249,11 +250,11 @@ proc renderRstToRst(d: var TRenderContext, n: PRstNode, result: var string) =
     result.add("***")
     renderRstSons(d, n, result)
     result.add("***")
-  of rnInterpretedText: 
+  of rnInterpretedText:
     result.add('`')
     renderRstSons(d, n, result)
     result.add('`')
-  of rnInlineLiteral: 
+  of rnInlineLiteral:
     inc(d.verbatim)
     result.add("``")
     renderRstSons(d, n, result)
@@ -266,11 +267,11 @@ proc renderRstToRst(d: var TRenderContext, n: PRstNode, result: var string) =
       result.add("\\\\") # XXX: escape more special characters!
     else:
       result.add(n.text)
-  of rnIndex: 
+  of rnIndex:
     result.add("\n\n")
     result.add(ind)
     result.add(".. index::\n")
-    
+
     inc(d.indent, 3)
     if n.sons[2] != nil: renderRstSons(d, n.sons[2], result)
     dec(d.indent, 3)
@@ -280,7 +281,7 @@ proc renderRstToRst(d: var TRenderContext, n: PRstNode, result: var string) =
     result.add(".. contents::")
   else:
     result.add("Error: cannot render: " & $n.kind)
-  
+
 proc renderRstToRst*(n: PRstNode, result: var string) =
   ## renders `n` into its string representation and appends to `result`.
   var d: TRenderContext
@@ -302,7 +303,7 @@ proc renderRstToJsonNode(node: PRstNode): JsonNode =
 
 proc renderRstToJson*(node: PRstNode): string =
   ## Writes the given RST node as JSON that is in the form
-  ## :: 
+  ## ::
   ##   {
   ##     "kind":string node.kind,
   ##     "text":optional string node.text,
diff --git a/lib/posix/posix.nim b/lib/posix/posix.nim
index 00b655a10..5c3190bf7 100644
--- a/lib/posix/posix.nim
+++ b/lib/posix/posix.nim
@@ -95,10 +95,11 @@ type
              header: "<dirent.h>", final, pure.} = object ## dirent_t struct
     d_ino*: Tino  ## File serial number.
     when defined(linux) or defined(macosx) or defined(bsd):
-      d_off*: TOff  ## Not an offset. Value that ``telldir()`` would return.
       d_reclen*: cshort ## Length of this record. (not POSIX)
       d_type*: int8 ## Type of file; not supported by all filesystem types.
                     ## (not POSIX)
+      when defined(linux) or defined(bsd):
+        d_off*: TOff  ## Not an offset. Value that ``telldir()`` would return.
     d_name*: array [0..255, char] ## Name of entry.
 
   Tflock* {.importc: "struct flock", final, pure,
diff --git a/lib/pure/collections/sets.nim b/lib/pure/collections/sets.nim
index 4a20d00a4..35fe21c10 100644
--- a/lib/pure/collections/sets.nim
+++ b/lib/pure/collections/sets.nim
@@ -798,177 +798,178 @@ proc `==`*[A](s, t: OrderedSet[A]): bool =
     g = nxg
   result = compared == s.counter
 
-proc testModule() =
-  ## Internal micro test to validate docstrings and such.
-  block isValidTest:
-    var options: HashSet[string]
-    proc savePreferences(options: HashSet[string]) =
-      assert options.isValid, "Pass an initialized set!"
-    options = initSet[string]()
-    options.savePreferences
-
-  block lenTest:
-    var values: HashSet[int]
-    assert(not values.isValid)
-    assert values.len == 0
-    assert values.card == 0
-
-  block setIterator:
-    type pair = tuple[a, b: int]
-    var a, b = initSet[pair]()
-    a.incl((2, 3))
-    a.incl((3, 2))
-    a.incl((2, 3))
-    for x, y in a.items:
-      b.incl((x - 2, y + 1))
-    assert a.len == b.card
-    assert a.len == 2
-    #echo b
-
-  block setContains:
-    var values = initSet[int]()
-    assert(not values.contains(2))
-    values.incl(2)
-    assert values.contains(2)
-    values.excl(2)
-    assert(not values.contains(2))
-
-    values.incl(4)
-    var others = toSet([6, 7])
-    values.incl(others)
-    assert values.len == 3
-
-    values.init
-    assert values.containsOrIncl(2) == false
-    assert values.containsOrIncl(2) == true
-    var
-      a = toSet([1, 2])
-      b = toSet([1])
-    b.incl(2)
-    assert a == b
-
-  block exclusions:
-    var s = toSet([2, 3, 6, 7])
-    s.excl(2)
-    s.excl(2)
-    assert s.len == 3
-
-    var
-      numbers = toSet([1, 2, 3, 4, 5])
-      even = toSet([2, 4, 6, 8])
-    numbers.excl(even)
-    #echo numbers
-    # --> {1, 3, 5}
-
-  block toSeqAndString:
-    var a = toSet([2, 4, 5])
-    var b = initSet[int]()
-    for x in [2, 4, 5]: b.incl(x)
-    assert($a == $b)
-    #echo a
-    #echo toSet(["no", "esc'aping", "is \" provided"])
-
-  #block orderedToSeqAndString:
-  #  echo toOrderedSet([2, 4, 5])
-  #  echo toOrderedSet(["no", "esc'aping", "is \" provided"])
-
-  block setOperations:
-    var
-      a = toSet(["a", "b"])
-      b = toSet(["b", "c"])
-      c = union(a, b)
-    assert c == toSet(["a", "b", "c"])
-    var d = intersection(a, b)
-    assert d == toSet(["b"])
-    var e = difference(a, b)
-    assert e == toSet(["a"])
-    var f = symmetricDifference(a, b)
-    assert f == toSet(["a", "c"])
-    assert d < a and d < b
-    assert((a < a) == false)
-    assert d <= a and d <= b
-    assert((a <= a))
-    # Alias test.
-    assert a + b == toSet(["a", "b", "c"])
-    assert a * b == toSet(["b"])
-    assert a - b == toSet(["a"])
-    assert a -+- b == toSet(["a", "c"])
-    assert disjoint(a, b) == false
-    assert disjoint(a, b - a) == true
-
-  block mapSet:
-    var a = toSet([1, 2, 3])
-    var b = a.map(proc (x: int): string = $x)
-    assert b == toSet(["1", "2", "3"])
-
-  block isValidTest:
-    var cards: OrderedSet[string]
-    proc saveTarotCards(cards: OrderedSet[string]) =
-      assert cards.isValid, "Pass an initialized set!"
-    cards = initOrderedSet[string]()
-    cards.saveTarotCards
-
-  block lenTest:
-    var values: OrderedSet[int]
-    assert(not values.isValid)
-    assert values.len == 0
-    assert values.card == 0
-
-  block setIterator:
-    type pair = tuple[a, b: int]
-    var a, b = initOrderedSet[pair]()
-    a.incl((2, 3))
-    a.incl((3, 2))
-    a.incl((2, 3))
-    for x, y in a.items:
-      b.incl((x - 2, y + 1))
-    assert a.len == b.card
-    assert a.len == 2
-
-  #block orderedSetIterator:
-  #  var a = initOrderedSet[int]()
-  #  for value in [9, 2, 1, 5, 1, 8, 4, 2]:
-  #    a.incl(value)
-  #  for value in a.items:
-  #    echo "Got ", value
-
-  block setContains:
-    var values = initOrderedSet[int]()
-    assert(not values.contains(2))
-    values.incl(2)
-    assert values.contains(2)
-
-  block toSeqAndString:
-    var a = toOrderedSet([2, 4, 5])
-    var b = initOrderedSet[int]()
-    for x in [2, 4, 5]: b.incl(x)
-    assert($a == $b)
-    assert(a == b) # https://github.com/Araq/Nimrod/issues/1413
-
-  block initBlocks:
-    var a: OrderedSet[int]
-    a.init(4)
-    a.incl(2)
-    a.init
-    assert a.len == 0 and a.isValid
-    a = initOrderedSet[int](4)
-    a.incl(2)
-    assert a.len == 1
-
-    var b: HashSet[int]
-    b.init(4)
-    b.incl(2)
-    b.init
-    assert b.len == 0 and b.isValid
-    b = initSet[int](4)
-    b.incl(2)
-    assert b.len == 1
-
-  for i in 0 .. 32:
-    var s = rightSize(i)
-    if s <= i or mustRehash(s, i):
-      echo "performance issue: rightSize() will not elide enlarge() at ", i
-
-  echo "Micro tests run successfully."
-
-when isMainModule and not defined(release): testModule()
+when isMainModule and not defined(release):
+  proc testModule() =
+    ## Internal micro test to validate docstrings and such.
+    block isValidTest:
+      var options: HashSet[string]
+      proc savePreferences(options: HashSet[string]) =
+        assert options.isValid, "Pass an initialized set!"
+      options = initSet[string]()
+      options.savePreferences
+
+    block lenTest:
+      var values: HashSet[int]
+      assert(not values.isValid)
+      assert values.len == 0
+      assert values.card == 0
+
+    block setIterator:
+      type pair = tuple[a, b: int]
+      var a, b = initSet[pair]()
+      a.incl((2, 3))
+      a.incl((3, 2))
+      a.incl((2, 3))
+      for x, y in a.items:
+        b.incl((x - 2, y + 1))
+      assert a.len == b.card
+      assert a.len == 2
+      #echo b
+
+    block setContains:
+      var values = initSet[int]()
+      assert(not values.contains(2))
+      values.incl(2)
+      assert values.contains(2)
+      values.excl(2)
+      assert(not values.contains(2))
+
+      values.incl(4)
+      var others = toSet([6, 7])
+      values.incl(others)
+      assert values.len == 3
+
+      values.init
+      assert values.containsOrIncl(2) == false
+      assert values.containsOrIncl(2) == true
+      var
+        a = toSet([1, 2])
+        b = toSet([1])
+      b.incl(2)
+      assert a == b
+
+    block exclusions:
+      var s = toSet([2, 3, 6, 7])
+      s.excl(2)
+      s.excl(2)
+      assert s.len == 3
+
+      var
+        numbers = toSet([1, 2, 3, 4, 5])
+        even = toSet([2, 4, 6, 8])
+      numbers.excl(even)
+      #echo numbers
+      # --> {1, 3, 5}
+
+    block toSeqAndString:
+      var a = toSet([2, 4, 5])
+      var b = initSet[int]()
+      for x in [2, 4, 5]: b.incl(x)
+      assert($a == $b)
+      #echo a
+      #echo toSet(["no", "esc'aping", "is \" provided"])
+
+    #block orderedToSeqAndString:
+    #  echo toOrderedSet([2, 4, 5])
+    #  echo toOrderedSet(["no", "esc'aping", "is \" provided"])
+
+    block setOperations:
+      var
+        a = toSet(["a", "b"])
+        b = toSet(["b", "c"])
+        c = union(a, b)
+      assert c == toSet(["a", "b", "c"])
+      var d = intersection(a, b)
+      assert d == toSet(["b"])
+      var e = difference(a, b)
+      assert e == toSet(["a"])
+      var f = symmetricDifference(a, b)
+      assert f == toSet(["a", "c"])
+      assert d < a and d < b
+      assert((a < a) == false)
+      assert d <= a and d <= b
+      assert((a <= a))
+      # Alias test.
+      assert a + b == toSet(["a", "b", "c"])
+      assert a * b == toSet(["b"])
+      assert a - b == toSet(["a"])
+      assert a -+- b == toSet(["a", "c"])
+      assert disjoint(a, b) == false
+      assert disjoint(a, b - a) == true
+
+    block mapSet:
+      var a = toSet([1, 2, 3])
+      var b = a.map(proc (x: int): string = $x)
+      assert b == toSet(["1", "2", "3"])
+
+    block isValidTest:
+      var cards: OrderedSet[string]
+      proc saveTarotCards(cards: OrderedSet[string]) =
+        assert cards.isValid, "Pass an initialized set!"
+      cards = initOrderedSet[string]()
+      cards.saveTarotCards
+
+    block lenTest:
+      var values: OrderedSet[int]
+      assert(not values.isValid)
+      assert values.len == 0
+      assert values.card == 0
+
+    block setIterator:
+      type pair = tuple[a, b: int]
+      var a, b = initOrderedSet[pair]()
+      a.incl((2, 3))
+      a.incl((3, 2))
+      a.incl((2, 3))
+      for x, y in a.items:
+        b.incl((x - 2, y + 1))
+      assert a.len == b.card
+      assert a.len == 2
+
+    #block orderedSetIterator:
+    #  var a = initOrderedSet[int]()
+    #  for value in [9, 2, 1, 5, 1, 8, 4, 2]:
+    #    a.incl(value)
+    #  for value in a.items:
+    #    echo "Got ", value
+
+    block setContains:
+      var values = initOrderedSet[int]()
+      assert(not values.contains(2))
+      values.incl(2)
+      assert values.contains(2)
+
+    block toSeqAndString:
+      var a = toOrderedSet([2, 4, 5])
+      var b = initOrderedSet[int]()
+      for x in [2, 4, 5]: b.incl(x)
+      assert($a == $b)
+      assert(a == b) # https://github.com/Araq/Nimrod/issues/1413
+
+    block initBlocks:
+      var a: OrderedSet[int]
+      a.init(4)
+      a.incl(2)
+      a.init
+      assert a.len == 0 and a.isValid
+      a = initOrderedSet[int](4)
+      a.incl(2)
+      assert a.len == 1
+
+      var b: HashSet[int]
+      b.init(4)
+      b.incl(2)
+      b.init
+      assert b.len == 0 and b.isValid
+      b = initSet[int](4)
+      b.incl(2)
+      assert b.len == 1
+
+    for i in 0 .. 32:
+      var s = rightSize(i)
+      if s <= i or mustRehash(s, i):
+        echo "performance issue: rightSize() will not elide enlarge() at ", i
+
+    echo "Micro tests run successfully."
+
+  testModule()
diff --git a/lib/pure/json.nim b/lib/pure/json.nim
index c3db5bdf8..1617402c9 100644
--- a/lib/pure/json.nim
+++ b/lib/pure/json.nim
@@ -605,6 +605,49 @@ proc newJArray*(): JsonNode =
   result.kind = JArray
   result.elems = @[]
 
+proc getStr*(n: JsonNode, default: string = ""): string =
+  ## Retrieves the string value of a `JString JsonNode`.
+  ##
+  ## Returns ``default`` if ``n`` is not a ``JString``.
+  if n.kind != JString: return default
+  else: return n.str
+
+proc getNum*(n: JsonNode, default: BiggestInt = 0): BiggestInt =
+  ## Retrieves the int value of a `JInt JsonNode`.
+  ##
+  ## Returns ``default`` if ``n`` is not a ``JInt``.
+  if n.kind != JInt: return default
+  else: return n.num
+
+proc getFNum*(n: JsonNode, default: float = 0.0): float =
+  ## Retrieves the float value of a `JFloat JsonNode`.
+  ##
+  ## Returns ``default`` if ``n`` is not a ``JFloat``.
+  if n.kind != JFloat: return default
+  else: return n.fnum
+
+proc getBVal*(n: JsonNode, default: bool = false): bool =
+  ## Retrieves the bool value of a `JBool JsonNode`.
+  ##
+  ## Returns ``default`` if ``n`` is not a ``JBool``.
+  if n.kind != JBool: return default
+  else: return n.bval
+
+proc getFields*(n: JsonNode,
+    default: seq[tuple[key: string, val: JsonNode]] = @[]):
+        seq[tuple[key: string, val: JsonNode]] =
+  ## Retrieves the key, value pairs of a `JObject JsonNode`.
+  ##
+  ## Returns ``default`` if ``n`` is not a ``JObject``.
+  if n.kind != JObject: return default
+  else: return n.fields
+
+proc getElems*(n: JsonNode, default: seq[JsonNode] = @[]): seq[JsonNode] =
+  ## Retrieves the int value of a `JArray JsonNode`.
+  ##
+  ## Returns ``default`` if ``n`` is not a ``JArray``.
+  if n.kind != JArray: return default
+  else: return n.elems
 
 proc `%`*(s: string): JsonNode =
   ## Generic constructor for JSON data. Creates a new `JString JsonNode`.
diff --git a/lib/pure/math.nim b/lib/pure/math.nim
index c902af381..aa64933fb 100644
--- a/lib/pure/math.nim
+++ b/lib/pure/math.nim
@@ -152,6 +152,7 @@ proc randomize*(seed: int) {.benign.}
   ## Note: Does nothing for the JavaScript target,
   ## as JavaScript does not support this.
 
+{.push noSideEffect.}
 when not defined(JS):
   proc sqrt*(x: float): float {.importc: "sqrt", header: "<math.h>".}
     ## computes the square root of `x`.
@@ -273,6 +274,8 @@ else:
     var y = exp(2.0*x)
     return (y-1.0)/(y+1.0)
 
+{.pop.}
+
 proc `mod`*(x, y: float): float =
   result = if y == 0.0: x else: x - y * (x/y).floor
 
@@ -370,3 +373,7 @@ when isMainModule and not defined(JS):
   for i in 0..SIZE-1:
     assert buf[i] == random(high(int)), "non deterministic random seeding"
   echo "random values equal after reseeding"
+
+  # Check for no side effect annotation
+  proc mySqrt(num: float): float {.noSideEffect.} =
+    return sqrt(num)
diff --git a/lib/pure/osproc.nim b/lib/pure/osproc.nim
index cd3700019..eb7ad64bb 100644
--- a/lib/pure/osproc.nim
+++ b/lib/pure/osproc.nim
@@ -137,7 +137,7 @@ proc startProcess*(command: string,
   ## `env` is the environment that will be passed to the process.
   ## If ``env == nil`` the environment is inherited of
   ## the parent process. `options` are additional flags that may be passed
-  ## to `startProcess`. See the documentation of ``TProcessOption`` for the
+  ## to `startProcess`. See the documentation of ``ProcessOption`` for the
   ## meaning of these flags. You need to `close` the process when done.
   ##
   ## Note that you can't pass any `args` if you use the option
diff --git a/lib/pure/rawsockets.nim b/lib/pure/rawsockets.nim
index ac348eb1b..de7ff0917 100644
--- a/lib/pure/rawsockets.nim
+++ b/lib/pure/rawsockets.nim
@@ -429,7 +429,7 @@ proc selectWrite*(writefds: var seq[SocketHandle],
   pruneSocketSet(writefds, (wr))
 
 # We ignore signal SIGPIPE on Darwin
-when defined(macosx):
+when defined(macosx) and not defined(nimdoc):
   signal(SIGPIPE, SIG_IGN)
 
 when defined(Windows):
diff --git a/lib/system.nim b/lib/system.nim
index ba0690ace..d1f910715 100644
--- a/lib/system.nim
+++ b/lib/system.nim
@@ -704,6 +704,7 @@ proc `div` *(x, y: int32): int32 {.magic: "DivI", noSideEffect.}
 proc `div` *(x, y: int64): int64 {.magic: "DivI64", noSideEffect.}
   ## computes the integer division. This is roughly the same as
   ## ``floor(x/y)``.
+  ##
   ## .. code-block:: Nim
   ##   1 div 2 == 0
   ##   2 div 2 == 1
@@ -723,6 +724,7 @@ proc `shr` *(x, y: int16): int16 {.magic: "ShrI", noSideEffect.}
 proc `shr` *(x, y: int32): int32 {.magic: "ShrI", noSideEffect.}
 proc `shr` *(x, y: int64): int64 {.magic: "ShrI64", noSideEffect.}
   ## computes the `shift right` operation of `x` and `y`.
+  ##
   ## .. code-block:: Nim
   ##   0b0001_0000'i8 shr 2 == 0b0100_0000'i8
   ##   0b1000_0000'i8 shr 2 == 0b0000_0000'i8
diff --git a/lib/system/alloc.nim b/lib/system/alloc.nim
index fd3ced832..bc34b23a6 100644
--- a/lib/system/alloc.nim
+++ b/lib/system/alloc.nim
@@ -539,8 +539,8 @@ proc allocInv(a: TMemRegion): bool =
 
 proc rawAlloc(a: var TMemRegion, requestedSize: int): pointer =
   sysAssert(allocInv(a), "rawAlloc: begin")
-  sysAssert(roundup(65, 8) == 72, "rawAlloc 1")
-  sysAssert requestedSize >= sizeof(TFreeCell), "rawAlloc 2"
+  sysAssert(roundup(65, 8) == 72, "rawAlloc: roundup broken")
+  sysAssert(requestedSize >= sizeof(TFreeCell), "rawAlloc: requested size too small")
   var size = roundup(requestedSize, MemAlign)
   sysAssert(size >= requestedSize, "insufficient allocated size!")
   #c_fprintf(c_stdout, "alloc; size: %ld; %ld\n", requestedSize, size)
diff --git a/lib/windows/windows.nim b/lib/windows/windows.nim
index 43c595a64..b76dea6c5 100644
--- a/lib/windows/windows.nim
+++ b/lib/windows/windows.nim
@@ -11,7 +11,7 @@
 ## Unicode version.

 

 {.deadCodeElim: on.}

-

+{.push gcsafe.}

 type

   WideChar* = uint16

   PWideChar* = ptr uint16

@@ -23481,7 +23481,7 @@ proc ListView_EnsureVisible(hwndLV: HWND, i, fPartialOK: int32): LRESULT =
                        MAKELPARAM(fPartialOK, 0))

 

 proc ListView_FindItem(wnd: HWND, iStart: int32, lvfi: var LV_FINDINFO): int32 =

-  result = SendMessage(wnd, LVM_FINDITEM, WPARAM(iStart), 

+  result = SendMessage(wnd, LVM_FINDITEM, WPARAM(iStart),

                        cast[LPARAM](addr(lvfi))).int32

 

 proc ListView_GetBkColor(wnd: HWND): LRESULT =

@@ -23615,9 +23615,9 @@ proc ListView_SetTextBkColor(wnd: HWND, clrTextBk: COLORREF): LRESULT =
 proc ListView_SetTextColor(wnd: HWND, clrText: COLORREF): LRESULT =

   result = SendMessage(wnd, LVM_SETTEXTCOLOR, 0, LPARAM(clrText))

 

-proc ListView_SortItems(hwndLV: HWND, pfnCompare: PFNLVCOMPARE, 

+proc ListView_SortItems(hwndLV: HWND, pfnCompare: PFNLVCOMPARE,

                         lPrm: LPARAM): LRESULT =

-  result = SendMessage(hwndLV, LVM_SORTITEMS, WPARAM(lPrm), 

+  result = SendMessage(hwndLV, LVM_SORTITEMS, WPARAM(lPrm),

                        cast[LPARAM](pfnCompare))

 

 proc ListView_Update(hwndLV: HWND, i: int32): LRESULT =

@@ -23924,3 +23924,5 @@ proc LOCALE_NEUTRAL(): DWORD =
 

 proc LOCALE_INVARIANT(): DWORD =

   result = MAKELCID(MAKELANGID(toU16(LANG_INVARIANT), SUBLANG_NEUTRAL), SORT_DEFAULT)

+

+{.pop.}

diff --git a/lib/wrappers/iup.nim b/lib/wrappers/iup.nim
index 27ab7d870..93e14cccd 100644
--- a/lib/wrappers/iup.nim
+++ b/lib/wrappers/iup.nim
@@ -1,13 +1,13 @@
 #
 #    Binding for the IUP GUI toolkit
-#       (c) 2012 Andreas Rumpf 
+#       (c) 2012 Andreas Rumpf
 #    C header files translated by hand
 #    Licence of IUP follows:
 
 
 # ****************************************************************************
 # Copyright (C) 1994-2009 Tecgraf, PUC-Rio.
-# 
+#
 # Permission is hereby granted, free of charge, to any person obtaining
 # a copy of this software and associated documentation files (the
 # "Software"), to deal in the Software without restriction, including
@@ -30,12 +30,12 @@
 
 {.deadCodeElim: on.}
 
-when defined(windows): 
-  const dllname = "iup(30|27|26|25|24).dll"
+when defined(windows):
+  const dllname = "iup(|30|27|26|25|24).dll"
 elif defined(macosx):
-  const dllname = "libiup(3.0|2.7|2.6|2.5|2.4).dylib"
-else: 
-  const dllname = "libiup(3.0|2.7|2.6|2.5|2.4).so.1"
+  const dllname = "libiup(|3.0|2.7|2.6|2.5|2.4).dylib"
+else:
+  const dllname = "libiup(|3.0|2.7|2.6|2.5|2.4).so(|.1)"
 
 const
   IUP_NAME* = "IUP - Portable User Interface"
@@ -67,8 +67,8 @@ proc alarm*(title, msg, b1, b2, b3: cstring): cint {.
   importc: "IupAlarm", dynlib: dllname, cdecl.}
 proc scanf*(format: cstring): cint {.
   importc: "IupScanf", dynlib: dllname, cdecl, varargs.}
-proc listDialog*(theType: cint, title: cstring, size: cint, 
-                 list: cstringArray, op, maxCol, maxLin: cint, 
+proc listDialog*(theType: cint, title: cstring, size: cint,
+                 list: cstringArray, op, maxCol, maxLin: cint,
                  marks: ptr cint): cint {.
                  importc: "IupListDialog", dynlib: dllname, cdecl.}
 proc getText*(title, text: cstring): cint {.
@@ -77,14 +77,14 @@ proc getColor*(x, y: cint, r, g, b: var byte): cint {.
   importc: "IupGetColor", dynlib: dllname, cdecl.}
 
 type
-  Iparamcb* = proc (dialog: PIhandle, paramIndex: cint, 
+  Iparamcb* = proc (dialog: PIhandle, paramIndex: cint,
                     userData: pointer): cint {.cdecl.}
 
-proc getParam*(title: cstring, action: Iparamcb, userData: pointer, 
+proc getParam*(title: cstring, action: Iparamcb, userData: pointer,
                format: cstring): cint {.
                importc: "IupGetParam", cdecl, varargs, dynlib: dllname.}
-proc getParamv*(title: cstring, action: Iparamcb, userData: pointer, 
-                format: cstring, paramCount, paramExtra: cint, 
+proc getParamv*(title: cstring, action: Iparamcb, userData: pointer,
+                format: cstring, paramCount, paramExtra: cint,
                 paramData: pointer): cint {.
                 importc: "IupGetParamv", cdecl, dynlib: dllname.}
 
@@ -96,11 +96,11 @@ proc open*(argc: ptr cint, argv: ptr cstringArray): cint {.
 proc close*() {.importc: "IupClose", cdecl, dynlib: dllname.}
 proc imageLibOpen*() {.importc: "IupImageLibOpen", cdecl, dynlib: dllname.}
 
-proc mainLoop*(): cint {.importc: "IupMainLoop", cdecl, dynlib: dllname, 
+proc mainLoop*(): cint {.importc: "IupMainLoop", cdecl, dynlib: dllname,
                          discardable.}
 proc loopStep*(): cint {.importc: "IupLoopStep", cdecl, dynlib: dllname,
                          discardable.}
-proc mainLoopLevel*(): cint {.importc: "IupMainLoopLevel", cdecl, 
+proc mainLoopLevel*(): cint {.importc: "IupMainLoopLevel", cdecl,
                               dynlib: dllname, discardable.}
 proc flush*() {.importc: "IupFlush", cdecl, dynlib: dllname.}
 proc exitLoop*() {.importc: "IupExitLoop", cdecl, dynlib: dllname.}
@@ -204,7 +204,7 @@ proc getCallback*(ih: PIhandle, name: cstring): Icallback {.
   importc: "IupGetCallback", cdecl, dynlib: dllname.}
 proc setCallback*(ih: PIhandle, name: cstring, fn: Icallback): Icallback {.
   importc: "IupSetCallback", cdecl, dynlib: dllname, discardable.}
-  
+
 proc setCallbacks*(ih: PIhandle, name: cstring, fn: Icallback): PIhandle {.
   importc: "IupSetCallbacks", cdecl, dynlib: dllname, varargs, discardable.}
 
@@ -235,7 +235,7 @@ proc getClassName*(ih: PIhandle): cstring {.
   importc: "IupGetClassName", cdecl, dynlib: dllname.}
 proc getClassType*(ih: PIhandle): cstring {.
   importc: "IupGetClassType", cdecl, dynlib: dllname.}
-proc getClassAttributes*(classname: cstring, names: cstringArray, 
+proc getClassAttributes*(classname: cstring, names: cstringArray,
                          n: cint): cint {.
   importc: "IupGetClassAttributes", cdecl, dynlib: dllname.}
 proc saveClassAttributes*(ih: PIhandle) {.
@@ -378,12 +378,12 @@ const
   IUP_CONTINUE* = cint(-4)
 
   # IupPopup and IupShowXY Parameter Values
-  IUP_CENTER* = cint(0xFFFF) 
-  IUP_LEFT* = cint(0xFFFE) 
-  IUP_RIGHT* = cint(0xFFFD) 
-  IUP_MOUSEPOS* = cint(0xFFFC) 
-  IUP_CURRENT* = cint(0xFFFB) 
-  IUP_CENTERPARENT* = cint(0xFFFA) 
+  IUP_CENTER* = cint(0xFFFF)
+  IUP_LEFT* = cint(0xFFFE)
+  IUP_RIGHT* = cint(0xFFFD)
+  IUP_MOUSEPOS* = cint(0xFFFC)
+  IUP_CURRENT* = cint(0xFFFB)
+  IUP_CENTERPARENT* = cint(0xFFFA)
   IUP_TOP* = IUP_LEFT
   IUP_BOTTOM* = IUP_RIGHT
 
@@ -397,10 +397,10 @@ const
   # SCROLL_CB Callback Values
   IUP_SBUP* = cint(0)
   IUP_SBDN* = cint(1)
-  IUP_SBPGUP* = cint(2)   
+  IUP_SBPGUP* = cint(2)
   IUP_SBPGDN* = cint(3)
   IUP_SBPOSV* = cint(4)
-  IUP_SBDRAGV* = cint(5) 
+  IUP_SBDRAGV* = cint(5)
   IUP_SBLEFT* = cint(6)
   IUP_SBRIGHT* = cint(7)
   IUP_SBPGLEFT* = cint(8)
@@ -433,12 +433,12 @@ const
   IUP_MASK_EFLOAT* = "[+/-]?(/d+/.?/d*|/./d+)([eE][+/-]?/d+)?"
   IUP_MASK_INT* = "[+/-]?/d+"
   IUP_MASK_UINT* = "/d+"
-  
+
 # from 32 to 126, all character sets are equal,
 # the key code i the same as the character code.
 const
   K_SP* = cint(ord(' '))
-  K_exclam* = cint(ord('!'))   
+  K_exclam* = cint(ord('!'))
   K_quotedbl* = cint(ord('\"'))
   K_numbersign* = cint(ord('#'))
   K_dollar* = cint(ord('$'))
@@ -467,51 +467,51 @@ const
   K_semicolon* = cint(ord(';'))
   K_less* = cint(ord('<'))
   K_equal* = cint(ord('='))
-  K_greater* = cint(ord('>'))   
-  K_question* = cint(ord('?'))   
-  K_at* = cint(ord('@'))   
-  K_upperA* = cint(ord('A'))   
-  K_upperB* = cint(ord('B'))   
-  K_upperC* = cint(ord('C'))   
-  K_upperD* = cint(ord('D'))   
-  K_upperE* = cint(ord('E'))   
-  K_upperF* = cint(ord('F'))   
-  K_upperG* = cint(ord('G'))   
-  K_upperH* = cint(ord('H'))   
-  K_upperI* = cint(ord('I'))   
-  K_upperJ* = cint(ord('J'))   
-  K_upperK* = cint(ord('K'))   
-  K_upperL* = cint(ord('L'))   
-  K_upperM* = cint(ord('M'))   
-  K_upperN* = cint(ord('N'))   
-  K_upperO* = cint(ord('O'))   
-  K_upperP* = cint(ord('P'))   
-  K_upperQ* = cint(ord('Q'))  
-  K_upperR* = cint(ord('R'))  
-  K_upperS* = cint(ord('S'))  
-  K_upperT* = cint(ord('T'))  
-  K_upperU* = cint(ord('U'))  
-  K_upperV* = cint(ord('V')) 
-  K_upperW* = cint(ord('W')) 
-  K_upperX* = cint(ord('X'))  
-  K_upperY* = cint(ord('Y'))  
-  K_upperZ* = cint(ord('Z'))  
-  K_bracketleft* = cint(ord('[')) 
-  K_backslash* = cint(ord('\\'))  
-  K_bracketright* = cint(ord(']'))  
-  K_circum* = cint(ord('^'))   
-  K_underscore* = cint(ord('_'))   
-  K_grave* = cint(ord('`'))   
-  K_lowera* = cint(ord('a'))  
-  K_lowerb* = cint(ord('b'))   
-  K_lowerc* = cint(ord('c')) 
-  K_lowerd* = cint(ord('d'))   
-  K_lowere* = cint(ord('e'))   
-  K_lowerf* = cint(ord('f'))  
+  K_greater* = cint(ord('>'))
+  K_question* = cint(ord('?'))
+  K_at* = cint(ord('@'))
+  K_upperA* = cint(ord('A'))
+  K_upperB* = cint(ord('B'))
+  K_upperC* = cint(ord('C'))
+  K_upperD* = cint(ord('D'))
+  K_upperE* = cint(ord('E'))
+  K_upperF* = cint(ord('F'))
+  K_upperG* = cint(ord('G'))
+  K_upperH* = cint(ord('H'))
+  K_upperI* = cint(ord('I'))
+  K_upperJ* = cint(ord('J'))
+  K_upperK* = cint(ord('K'))
+  K_upperL* = cint(ord('L'))
+  K_upperM* = cint(ord('M'))
+  K_upperN* = cint(ord('N'))
+  K_upperO* = cint(ord('O'))
+  K_upperP* = cint(ord('P'))
+  K_upperQ* = cint(ord('Q'))
+  K_upperR* = cint(ord('R'))
+  K_upperS* = cint(ord('S'))
+  K_upperT* = cint(ord('T'))
+  K_upperU* = cint(ord('U'))
+  K_upperV* = cint(ord('V'))
+  K_upperW* = cint(ord('W'))
+  K_upperX* = cint(ord('X'))
+  K_upperY* = cint(ord('Y'))
+  K_upperZ* = cint(ord('Z'))
+  K_bracketleft* = cint(ord('['))
+  K_backslash* = cint(ord('\\'))
+  K_bracketright* = cint(ord(']'))
+  K_circum* = cint(ord('^'))
+  K_underscore* = cint(ord('_'))
+  K_grave* = cint(ord('`'))
+  K_lowera* = cint(ord('a'))
+  K_lowerb* = cint(ord('b'))
+  K_lowerc* = cint(ord('c'))
+  K_lowerd* = cint(ord('d'))
+  K_lowere* = cint(ord('e'))
+  K_lowerf* = cint(ord('f'))
   K_lowerg* = cint(ord('g'))
-  K_lowerh* = cint(ord('h')) 
-  K_loweri* = cint(ord('i')) 
-  K_lowerj* = cint(ord('j')) 
+  K_lowerh* = cint(ord('h'))
+  K_loweri* = cint(ord('i'))
+  K_lowerj* = cint(ord('j'))
   K_lowerk* = cint(ord('k'))
   K_lowerl* = cint(ord('l'))
   K_lowerm* = cint(ord('m'))
@@ -553,19 +553,19 @@ proc isAltXkey*(c: cint): bool = return c > 768 and c < 1024
 proc isSysXkey*(c: cint): bool = return c > 1024 and c < 1280
 
 proc iUPxCODE*(c: cint): cint = return c + cint(128) # Normal (must be above 128)
-proc iUPsxCODE*(c: cint): cint = 
+proc iUPsxCODE*(c: cint): cint =
   return c + cint(256)
-  # Shift (must have range to include the standard keys and the normal 
+  # Shift (must have range to include the standard keys and the normal
   # extended keys, so must be above 256
 
 proc iUPcxCODE*(c: cint): cint = return c + cint(512) # Ctrl
 proc iUPmxCODE*(c: cint): cint = return c + cint(768) # Alt
-proc iUPyxCODE*(c: cint): cint = return c + cint(1024) # Sys (Win or Apple) 
+proc iUPyxCODE*(c: cint): cint = return c + cint(1024) # Sys (Win or Apple)
 
 const
   IUP_NUMMAXCODES* = 1280 ## 5*256=1280  Normal+Shift+Ctrl+Alt+Sys
 
-  K_HOME* = iUPxCODE(1)                
+  K_HOME* = iUPxCODE(1)
   K_UP* = iUPxCODE(2)
   K_PGUP* = iUPxCODE(3)
   K_LEFT* = iUPxCODE(4)
@@ -574,8 +574,8 @@ const
   K_END* = iUPxCODE(7)
   K_DOWN* = iUPxCODE(8)
   K_PGDN* = iUPxCODE(9)
-  K_INS* = iUPxCODE(10)    
-  K_DEL* = iUPxCODE(11)    
+  K_INS* = iUPxCODE(10)
+  K_DEL* = iUPxCODE(11)
   K_PAUSE* = iUPxCODE(12)
   K_ESC* = iUPxCODE(13)
   K_ccedilla* = iUPxCODE(14)
@@ -728,13 +728,13 @@ const
   K_yPrint* = iUPyxCODE(K_Print)
   K_yMenu* = iUPyxCODE(K_Menu)
 
-  K_sPlus* = iUPsxCODE(K_plus)   
-  K_sComma* = iUPsxCODE(K_comma)   
-  K_sMinus* = iUPsxCODE(K_minus)   
-  K_sPeriod* = iUPsxCODE(K_period)   
-  K_sSlash* = iUPsxCODE(K_slash)   
+  K_sPlus* = iUPsxCODE(K_plus)
+  K_sComma* = iUPsxCODE(K_comma)
+  K_sMinus* = iUPsxCODE(K_minus)
+  K_sPeriod* = iUPsxCODE(K_period)
+  K_sSlash* = iUPsxCODE(K_slash)
   K_sAsterisk* = iUPsxCODE(K_asterisk)
-                        
+
   K_cupperA* = iUPcxCODE(K_upperA)
   K_cupperB* = iUPcxCODE(K_upperB)
   K_cupperC* = iUPcxCODE(K_upperC)
@@ -767,16 +767,16 @@ const
   K_c4* = iUPcxCODE(K_4)
   K_c5* = iUPcxCODE(K_5)
   K_c6* = iUPcxCODE(K_6)
-  K_c7* = iUPcxCODE(K_7)        
-  K_c8* = iUPcxCODE(K_8)         
+  K_c7* = iUPcxCODE(K_7)
+  K_c8* = iUPcxCODE(K_8)
   K_c9* = iUPcxCODE(K_9)
   K_c0* = iUPcxCODE(K_0)
-  K_cPlus* = iUPcxCODE(K_plus)   
-  K_cComma* = iUPcxCODE(K_comma)   
-  K_cMinus* = iUPcxCODE(K_minus)   
-  K_cPeriod* = iUPcxCODE(K_period)   
-  K_cSlash* = iUPcxCODE(K_slash)   
-  K_cSemicolon* = iUPcxCODE(K_semicolon) 
+  K_cPlus* = iUPcxCODE(K_plus)
+  K_cComma* = iUPcxCODE(K_comma)
+  K_cMinus* = iUPcxCODE(K_minus)
+  K_cPeriod* = iUPcxCODE(K_period)
+  K_cSlash* = iUPcxCODE(K_slash)
+  K_cSemicolon* = iUPcxCODE(K_semicolon)
   K_cEqual* = iUPcxCODE(K_equal)
   K_cBracketleft* = iUPcxCODE(K_bracketleft)
   K_cBracketright* = iUPcxCODE(K_bracketright)
@@ -815,16 +815,16 @@ const
   K_m4* = iUPmxCODE(K_4)
   K_m5* = iUPmxCODE(K_5)
   K_m6* = iUPmxCODE(K_6)
-  K_m7* = iUPmxCODE(K_7)        
-  K_m8* = iUPmxCODE(K_8)         
+  K_m7* = iUPmxCODE(K_7)
+  K_m8* = iUPmxCODE(K_8)
   K_m9* = iUPmxCODE(K_9)
   K_m0* = iUPmxCODE(K_0)
-  K_mPlus* = iUPmxCODE(K_plus)   
-  K_mComma* = iUPmxCODE(K_comma)   
-  K_mMinus* = iUPmxCODE(K_minus)   
-  K_mPeriod* = iUPmxCODE(K_period)   
-  K_mSlash* = iUPmxCODE(K_slash)   
-  K_mSemicolon* = iUPmxCODE(K_semicolon) 
+  K_mPlus* = iUPmxCODE(K_plus)
+  K_mComma* = iUPmxCODE(K_comma)
+  K_mMinus* = iUPmxCODE(K_minus)
+  K_mPeriod* = iUPmxCODE(K_period)
+  K_mSlash* = iUPmxCODE(K_slash)
+  K_mSemicolon* = iUPmxCODE(K_semicolon)
   K_mEqual* = iUPmxCODE(K_equal)
   K_mBracketleft* = iUPmxCODE(K_bracketleft)
   K_mBracketright* = iUPmxCODE(K_bracketright)
@@ -863,16 +863,16 @@ const
   K_y4* = iUPyxCODE(K_4)
   K_y5* = iUPyxCODE(K_5)
   K_y6* = iUPyxCODE(K_6)
-  K_y7* = iUPyxCODE(K_7)        
-  K_y8* = iUPyxCODE(K_8)         
+  K_y7* = iUPyxCODE(K_7)
+  K_y8* = iUPyxCODE(K_8)
   K_y9* = iUPyxCODE(K_9)
   K_y0* = iUPyxCODE(K_0)
   K_yPlus* = iUPyxCODE(K_plus)
   K_yComma* = iUPyxCODE(K_comma)
-  K_yMinus* = iUPyxCODE(K_minus)   
-  K_yPeriod* = iUPyxCODE(K_period)   
-  K_ySlash* = iUPyxCODE(K_slash)   
-  K_ySemicolon* = iUPyxCODE(K_semicolon) 
+  K_yMinus* = iUPyxCODE(K_minus)
+  K_yPeriod* = iUPyxCODE(K_period)
+  K_ySlash* = iUPyxCODE(K_slash)
+  K_ySemicolon* = iUPyxCODE(K_semicolon)
   K_yEqual* = iUPyxCODE(K_equal)
   K_yBracketleft* = iUPyxCODE(K_bracketleft)
   K_yBracketright* = iUPyxCODE(K_bracketright)
@@ -893,11 +893,11 @@ proc dial*(theType: cstring): PIhandle {.cdecl, importc: "IupDial", dynlib: dlln
 proc matrix*(action: cstring): PIhandle {.cdecl, importc: "IupMatrix", dynlib: dllname.}
 
 # IupMatrix utilities
-proc matSetAttribute*(ih: PIhandle, name: cstring, lin, col: cint, 
+proc matSetAttribute*(ih: PIhandle, name: cstring, lin, col: cint,
                       value: cstring) {.
                       cdecl, importc: "IupMatSetAttribute", dynlib: dllname.}
-proc matStoreAttribute*(ih: PIhandle, name: cstring, lin, col: cint, 
-                        value: cstring) {.cdecl, 
+proc matStoreAttribute*(ih: PIhandle, name: cstring, lin, col: cint,
+                        value: cstring) {.cdecl,
                         importc: "IupMatStoreAttribute", dynlib: dllname.}
 proc matGetAttribute*(ih: PIhandle, name: cstring, lin, col: cint): cstring {.
   cdecl, importc: "IupMatGetAttribute", dynlib: dllname.}
@@ -905,9 +905,9 @@ proc matGetInt*(ih: PIhandle, name: cstring, lin, col: cint): cint {.
   cdecl, importc: "IupMatGetInt", dynlib: dllname.}
 proc matGetFloat*(ih: PIhandle, name: cstring, lin, col: cint): cfloat {.
   cdecl, importc: "IupMatGetFloat", dynlib: dllname.}
-proc matSetfAttribute*(ih: PIhandle, name: cstring, lin, col: cint, 
-                       format: cstring) {.cdecl, 
-                       importc: "IupMatSetfAttribute", 
+proc matSetfAttribute*(ih: PIhandle, name: cstring, lin, col: cint,
+                       format: cstring) {.cdecl,
+                       importc: "IupMatSetfAttribute",
                        dynlib: dllname, varargs.}
 
 # Used by IupColorbar
@@ -931,10 +931,10 @@ proc pPlotAddStr*(ih: PIhandle, x: cstring, y: cfloat) {.
 proc pPlotEnd*(ih: PIhandle): cint {.
   cdecl, importc: "IupPPlotEnd", dynlib: dllname.}
 
-proc pPlotInsertStr*(ih: PIhandle, index, sampleIndex: cint, x: cstring, 
-                     y: cfloat) {.cdecl, importc: "IupPPlotInsertStr", 
+proc pPlotInsertStr*(ih: PIhandle, index, sampleIndex: cint, x: cstring,
+                     y: cfloat) {.cdecl, importc: "IupPPlotInsertStr",
                      dynlib: dllname.}
-proc pPlotInsert*(ih: PIhandle, index, sampleIndex: cint, 
+proc pPlotInsert*(ih: PIhandle, index, sampleIndex: cint,
                   x, y: cfloat) {.
                   cdecl, importc: "IupPPlotInsert", dynlib: dllname.}
 
diff --git a/tests/parallel/tgc_unsafe2.nim b/tests/parallel/tgc_unsafe2.nim
new file mode 100644
index 000000000..ec4605fe9
--- /dev/null
+++ b/tests/parallel/tgc_unsafe2.nim
@@ -0,0 +1,39 @@
+discard """
+  line: 28
+  nimout: '''tgc_unsafe2.nim(22, 5) Warning: 'trick' is not GC-safe as it accesses 'global' which is a global using GC'ed memory
+tgc_unsafe2.nim(26, 5) Warning: 'track' is not GC-safe as it calls 'trick'
+tgc_unsafe2.nim(28, 5) Error: 'consumer' is not GC-safe as it calls 'track'
+'''
+  errormsg: "'consumer' is not GC-safe as it calls 'track'"
+"""
+
+import threadpool
+
+type StringChannel = TChannel[string]
+var channels: array[1..3, StringChannel]
+
+type
+  MyObject[T] = object
+    x: T
+
+var global: MyObject[string]
+var globalB: MyObject[float]
+
+proc trick(ix: int) =
+  echo global.x
+  echo channels[ix].recv()
+
+proc track(ix: int) = trick(ix)
+
+proc consumer(ix: int) {.thread.} =
+  track(ix)
+
+proc main =
+  for ix in 1..3: channels[ix].open()
+  for ix in 1..3: spawn consumer(ix)
+  for ix in 1..3: channels[ix].send("test")
+  sync()
+  for ix in 1..3: channels[ix].close()
+
+when isMainModule:
+  main()
diff --git a/todo.txt b/todo.txt
index fc62385a8..c10406979 100644
--- a/todo.txt
+++ b/todo.txt
@@ -1,7 +1,6 @@
 version 0.10.4
 ==============
 
-- improve GC-unsafety warnings
 - make 'nil' work for 'add' and 'len'
 - overloading of '='