summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--compiler/msgs.nim7
-rw-r--r--compiler/pragmas.nim4
-rw-r--r--compiler/sempass2.nim7
-rw-r--r--lib/core/macros.nim77
-rw-r--r--lib/pure/asyncdispatch.nim20
-rw-r--r--lib/pure/asyncio.nim28
-rw-r--r--lib/pure/cgi.nim2
-rw-r--r--lib/pure/ftpclient.nim11
-rw-r--r--lib/pure/httpserver.nim2
-rw-r--r--lib/pure/irc.nim6
-rw-r--r--lib/pure/math.nim14
-rw-r--r--lib/pure/os.nim2
-rw-r--r--lib/pure/parsecfg.nim2
-rw-r--r--lib/pure/scgi.nim9
-rw-r--r--lib/pure/sockets.nim4
-rw-r--r--lib/pure/streams.nim16
-rw-r--r--lib/pure/times.nim25
-rw-r--r--lib/system.nim3
-rw-r--r--lib/system/channels.nim2
-rw-r--r--lib/system/inclrtl.nim8
-rw-r--r--lib/system/threads.nim4
21 files changed, 139 insertions, 114 deletions
diff --git a/compiler/msgs.nim b/compiler/msgs.nim
index 4d471bdac..8374c92a7 100644
--- a/compiler/msgs.nim
+++ b/compiler/msgs.nim
@@ -118,7 +118,7 @@ type
     warnNilStatement, warnAnalysisLoophole,
     warnDifferentHeaps, warnWriteToForeignHeap, warnImplicitClosure,
     warnEachIdentIsTuple, warnShadowIdent, 
-    warnProveInit, warnProveField, warnProveIndex, warnGcUnsafe,
+    warnProveInit, warnProveField, warnProveIndex, warnGcUnsafe, warnGcUnsafe2,
     warnUninit, warnGcMem, warnUser,
     hintSuccess, hintSuccessX,
     hintLineTooLong, hintXDeclaredButNotUsed, hintConvToBaseNotNeeded,
@@ -387,6 +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. This will become a compile time error in the future.",
     warnUninit: "'$1' might not have been initialized [Uninit]",
     warnGcMem: "'$1' uses GC'ed memory [GcMem]",
     warnUser: "$1 [User]", 
@@ -408,7 +409,7 @@ const
     hintUser: "$1 [User]"]
 
 const
-  WarningsToStr*: array[0..25, string] = ["CannotOpenFile", "OctalEscape", 
+  WarningsToStr*: array[0..26, string] = ["CannotOpenFile", "OctalEscape", 
     "XIsNeverRead", "XmightNotBeenInit",
     "Deprecated", "ConfigDeprecated",
     "SmallLshouldNotBeUsed", "UnknownMagic", 
@@ -416,7 +417,7 @@ const
     "CommentXIgnored", "NilStmt",
     "AnalysisLoophole", "DifferentHeaps", "WriteToForeignHeap",
     "ImplicitClosure", "EachIdentIsTuple", "ShadowIdent", 
-    "ProveInit", "ProveField", "ProveIndex", "GcUnsafe", "Uninit",
+    "ProveInit", "ProveField", "ProveIndex", "GcUnsafe", "GcUnsafe2", "Uninit",
     "GcMem", "User"]
 
   HintsToStr*: array[0..15, string] = ["Success", "SuccessX", "LineTooLong", 
diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim
index 88fa516bf..4cc9c4197 100644
--- a/compiler/pragmas.nim
+++ b/compiler/pragmas.nim
@@ -53,7 +53,7 @@ const
     wPure, wHeader, wCompilerproc, wFinal, wSize, wExtern, wShallow,
     wImportCpp, wImportObjC, wError, wIncompleteStruct, wByCopy, wByRef,
     wInheritable, wGensym, wInject, wRequiresInit, wUnchecked, wUnion, wPacked,
-    wBorrow}
+    wBorrow, wGcSafe}
   fieldPragmas* = {wImportc, wExportc, wDeprecated, wExtern, 
     wImportCpp, wImportObjC, wError}
   varPragmas* = {wImportc, wExportc, wVolatile, wRegister, wThreadVar, wNodecl, 
@@ -690,7 +690,7 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
           if sym.typ != nil: incl(sym.typ.flags, tfThread)
         of wGcSafe:
           noVal(it)
-          incl(sym.flags, sfThread)
+          if sym.kind != skType: incl(sym.flags, sfThread)
           if sym.typ != nil: incl(sym.typ.flags, tfGcSafe)
           else: invalidPragma(it)
         of wPacked:
diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim
index 295321f4b..f8685a5c8 100644
--- a/compiler/sempass2.nim
+++ b/compiler/sempass2.nim
@@ -113,7 +113,8 @@ proc useVar(a: PEffects, n: PNode) =
   if {sfGlobal, sfThread} * s.flags == {sfGlobal} and s.kind == skVar:
     when trackGlobals:
       a.addUse(copyNode(n))
-    if tfHasGCedMem in s.typ.flags or s.typ.isGCedMem:
+    if (tfHasGCedMem in s.typ.flags or s.typ.isGCedMem) and 
+        tfGcSafe notin s.typ.flags:
       message(n.info, warnGcUnsafe, renderTree(n))
       a.gcUnsafe = true
 
@@ -517,6 +518,7 @@ proc track(tracked: PEffects, n: PNode) =
           addEffect(tracked, createRaise(n))
           addTag(tracked, createTag(n))
           when trackGlobals: addUse(tracked, createAnyGlobal(n))
+          # XXX handle 'gcsafe' properly for callbacks!
       else:
         mergeEffects(tracked, effectList.sons[exceptionEffects], n)
         mergeTags(tracked, effectList.sons[tagEffects], n)
@@ -704,7 +706,8 @@ proc trackProc*(s: PSym, body: PNode) =
         "uses an unlisted global variable: ", hints=on, symbolPredicate)
       effects.sons[usesEffects] = usesSpec
   if sfThread in s.flags and t.gcUnsafe:
-    localError(s.info, "'$1' is not GC-safe" % s.name.s)
+    localError(s.info, warnGcUnsafe2, s.name.s)
+    #localError(s.info, "'$1' is not GC-safe" % s.name.s)
   if not t.gcUnsafe: s.typ.flags.incl tfGcSafe
   
 proc trackTopLevelStmt*(module: PSym; n: PNode) =
diff --git a/lib/core/macros.nim b/lib/core/macros.nim
index 79bf34b7c..09dc341df 100644
--- a/lib/core/macros.nim
+++ b/lib/core/macros.nim
@@ -7,6 +7,7 @@
 #    distribution, for details about the copyright.
 #
 
+include "system/inclrtl"
 
 ## This module contains the interface to the compiler's abstract syntax
 ## tree (`AST`:idx:). Macros operate on this tree.
@@ -109,19 +110,20 @@ const
   nnkCallKinds* = {nnkCall, nnkInfix, nnkPrefix, nnkPostfix, nnkCommand,
                    nnkCallStrLit}
 
-proc `[]`*(n: PNimrodNode, i: int): PNimrodNode {.magic: "NChild".}
+proc `[]`*(n: PNimrodNode, i: int): PNimrodNode {.magic: "NChild", noSideEffect.}
   ## get `n`'s `i`'th child.
 
-proc `[]=`*(n: PNimrodNode, i: int, child: PNimrodNode) {.magic: "NSetChild".}
+proc `[]=`*(n: PNimrodNode, i: int, child: PNimrodNode) {.magic: "NSetChild",
+  noSideEffect.}
   ## set `n`'s `i`'th child to `child`.
 
-proc `!`*(s: string): TNimrodIdent {.magic: "StrToIdent".}
+proc `!`*(s: string): TNimrodIdent {.magic: "StrToIdent", noSideEffect.}
   ## constructs an identifier from the string `s`
 
-proc `$`*(i: TNimrodIdent): string {.magic: "IdentToStr".}
+proc `$`*(i: TNimrodIdent): string {.magic: "IdentToStr", noSideEffect.}
   ## converts a Nimrod identifier to a string
 
-proc `$`*(s: PNimrodSymbol): string {.magic: "IdentToStr".}
+proc `$`*(s: PNimrodSymbol): string {.magic: "IdentToStr", noSideEffect.}
   ## converts a Nimrod symbol to a string
 
 proc `==`*(a, b: TNimrodIdent): bool {.magic: "EqIdent", noSideEffect.}
@@ -130,35 +132,36 @@ proc `==`*(a, b: TNimrodIdent): bool {.magic: "EqIdent", noSideEffect.}
 proc `==`*(a, b: PNimrodNode): bool {.magic: "EqNimrodNode", noSideEffect.}
   ## compares two Nimrod nodes
 
-proc len*(n: PNimrodNode): int {.magic: "NLen".}
+proc len*(n: PNimrodNode): int {.magic: "NLen", noSideEffect.}
   ## returns the number of children of `n`.
 
-proc add*(father, child: PNimrodNode): PNimrodNode {.magic: "NAdd", discardable.}
+proc add*(father, child: PNimrodNode): PNimrodNode {.magic: "NAdd", discardable,
+  noSideEffect.}
   ## Adds the `child` to the `father` node. Returns the
   ## father node so that calls can be nested.
 
 proc add*(father: PNimrodNode, children: varargs[PNimrodNode]): PNimrodNode {.
-  magic: "NAddMultiple", discardable.}
+  magic: "NAddMultiple", discardable, noSideEffect.}
   ## Adds each child of `children` to the `father` node.
   ## Returns the `father` node so that calls can be nested.
 
-proc del*(father: PNimrodNode, idx = 0, n = 1) {.magic: "NDel".}
+proc del*(father: PNimrodNode, idx = 0, n = 1) {.magic: "NDel", noSideEffect.}
   ## deletes `n` children of `father` starting at index `idx`.
 
-proc kind*(n: PNimrodNode): TNimrodNodeKind {.magic: "NKind".}
+proc kind*(n: PNimrodNode): TNimrodNodeKind {.magic: "NKind", noSideEffect.}
   ## returns the `kind` of the node `n`.
 
-proc intVal*(n: PNimrodNode): BiggestInt {.magic: "NIntVal".}
-proc floatVal*(n: PNimrodNode): BiggestFloat {.magic: "NFloatVal".}
-proc symbol*(n: PNimrodNode): PNimrodSymbol {.magic: "NSymbol".}
-proc ident*(n: PNimrodNode): TNimrodIdent {.magic: "NIdent".}
-proc typ*(n: PNimrodNode): typedesc {.magic: "NGetType".}
-proc strVal*(n: PNimrodNode): string  {.magic: "NStrVal".}
-
-proc `intVal=`*(n: PNimrodNode, val: BiggestInt) {.magic: "NSetIntVal".}
-proc `floatVal=`*(n: PNimrodNode, val: BiggestFloat) {.magic: "NSetFloatVal".}
-proc `symbol=`*(n: PNimrodNode, val: PNimrodSymbol) {.magic: "NSetSymbol".}
-proc `ident=`*(n: PNimrodNode, val: TNimrodIdent) {.magic: "NSetIdent".}
+proc intVal*(n: PNimrodNode): BiggestInt {.magic: "NIntVal", noSideEffect.}
+proc floatVal*(n: PNimrodNode): BiggestFloat {.magic: "NFloatVal", noSideEffect.}
+proc symbol*(n: PNimrodNode): PNimrodSymbol {.magic: "NSymbol", noSideEffect.}
+proc ident*(n: PNimrodNode): TNimrodIdent {.magic: "NIdent", noSideEffect.}
+proc typ*(n: PNimrodNode): typedesc {.magic: "NGetType", noSideEffect.}
+proc strVal*(n: PNimrodNode): string  {.magic: "NStrVal", noSideEffect.}
+
+proc `intVal=`*(n: PNimrodNode, val: BiggestInt) {.magic: "NSetIntVal", noSideEffect.}
+proc `floatVal=`*(n: PNimrodNode, val: BiggestFloat) {.magic: "NSetFloatVal", noSideEffect.}
+proc `symbol=`*(n: PNimrodNode, val: PNimrodSymbol) {.magic: "NSetSymbol", noSideEffect.}
+proc `ident=`*(n: PNimrodNode, val: TNimrodIdent) {.magic: "NSetIdent", noSideEffect.}
 #proc `typ=`*(n: PNimrodNode, typ: typedesc) {.magic: "NSetType".}
 # this is not sound! Unfortunately forbidding 'typ=' is not enough, as you
 # can easily do:
@@ -166,24 +169,24 @@ proc `ident=`*(n: PNimrodNode, val: TNimrodIdent) {.magic: "NSetIdent".}
 #   let fake = semCheck(2.0)
 #   bracket[0] = fake  # constructs a mixed array with ints and floats!
 
-proc `strVal=`*(n: PNimrodNode, val: string) {.magic: "NSetStrVal".}
+proc `strVal=`*(n: PNimrodNode, val: string) {.magic: "NSetStrVal", noSideEffect.}
 
 proc newNimNode*(kind: TNimrodNodeKind,
-                 n: PNimrodNode=nil): PNimrodNode {.magic: "NNewNimNode".}
+                 n: PNimrodNode=nil): PNimrodNode {.magic: "NNewNimNode", noSideEffect.}
 
-proc copyNimNode*(n: PNimrodNode): PNimrodNode {.magic: "NCopyNimNode".}
-proc copyNimTree*(n: PNimrodNode): PNimrodNode {.magic: "NCopyNimTree".}
+proc copyNimNode*(n: PNimrodNode): PNimrodNode {.magic: "NCopyNimNode", noSideEffect.}
+proc copyNimTree*(n: PNimrodNode): PNimrodNode {.magic: "NCopyNimTree", noSideEffect.}
 
-proc error*(msg: string) {.magic: "NError".}
+proc error*(msg: string) {.magic: "NError", gcsafe.}
   ## writes an error message at compile time
 
-proc warning*(msg: string) {.magic: "NWarning".}
+proc warning*(msg: string) {.magic: "NWarning", gcsafe.}
   ## writes a warning message at compile time
 
-proc hint*(msg: string) {.magic: "NHint".}
+proc hint*(msg: string) {.magic: "NHint", gcsafe.}
   ## writes a hint message at compile time
 
-proc newStrLitNode*(s: string): PNimrodNode {.compileTime.} =
+proc newStrLitNode*(s: string): PNimrodNode {.compileTime, noSideEffect.} =
   ## creates a string literal node from `s`
   result = newNimNode(nnkStrLit)
   result.strVal = s
@@ -219,7 +222,7 @@ type
                          ## any other means in the language currently)
 
 proc bindSym*(ident: string, rule: TBindSymRule = brClosed): PNimrodNode {.
-              magic: "NBindSym".}
+              magic: "NBindSym", noSideEffect.}
   ## creates a node that binds `ident` to a symbol node. The bound symbol
   ## may be an overloaded symbol.
   ## If ``rule == brClosed`` either an ``nkClosedSymChoice`` tree is
@@ -230,11 +233,11 @@ proc bindSym*(ident: string, rule: TBindSymRule = brClosed): PNimrodNode {.
   ## returned even if the symbol is not ambiguous.
 
 proc genSym*(kind: TNimrodSymKind = nskLet; ident = ""): PNimrodNode {.
-  magic: "NGenSym".}
+  magic: "NGenSym", noSideEffect.}
   ## generates a fresh symbol that is guaranteed to be unique. The symbol
   ## needs to occur in a declaration context.
 
-proc callsite*(): PNimrodNode {.magic: "NCallSite".}
+proc callsite*(): PNimrodNode {.magic: "NCallSite", gcsafe.}
   ## returns the AST if the invokation expression that invoked this macro.
 
 proc toStrLit*(n: PNimrodNode): PNimrodNode {.compileTime.} =
@@ -242,19 +245,19 @@ proc toStrLit*(n: PNimrodNode): PNimrodNode {.compileTime.} =
   ## in a string literal node
   return newStrLitNode(repr(n))
 
-proc lineinfo*(n: PNimrodNode): string {.magic: "NLineInfo".}
+proc lineinfo*(n: PNimrodNode): string {.magic: "NLineInfo", noSideEffect.}
   ## returns the position the node appears in the original source file
   ## in the form filename(line, col)
 
-proc parseExpr*(s: string): PNimrodNode {.magic: "ParseExprToAst".}
+proc parseExpr*(s: string): PNimrodNode {.magic: "ParseExprToAst", noSideEffect.}
   ## Compiles the passed string to its AST representation.
   ## Expects a single expression.
 
-proc parseStmt*(s: string): PNimrodNode {.magic: "ParseStmtToAst".}
+proc parseStmt*(s: string): PNimrodNode {.magic: "ParseStmtToAst", noSideEffect.}
   ## Compiles the passed string to its AST representation.
   ## Expects one or more statements.
 
-proc getAst*(macroOrTemplate: expr): PNimrodNode {.magic: "ExpandToAst".}
+proc getAst*(macroOrTemplate: expr): PNimrodNode {.magic: "ExpandToAst", noSideEffect.}
   ## Obtains the AST nodes returned from a macro or template invocation.
   ## Example:
   ##
@@ -263,7 +266,7 @@ proc getAst*(macroOrTemplate: expr): PNimrodNode {.magic: "ExpandToAst".}
   ##   macro FooMacro() =
   ##     var ast = getAst(BarTemplate())
 
-proc quote*(bl: stmt, op = "``"): PNimrodNode {.magic: "QuoteAst".}
+proc quote*(bl: stmt, op = "``"): PNimrodNode {.magic: "QuoteAst", noSideEffect.}
   ## Quasi-quoting operator.
   ## Accepts an expression or a block and returns the AST that represents it.
   ## Within the quoted AST, you are able to interpolate PNimrodNode expressions
diff --git a/lib/pure/asyncdispatch.nim b/lib/pure/asyncdispatch.nim
index 5e638dc74..f50383038 100644
--- a/lib/pure/asyncdispatch.nim
+++ b/lib/pure/asyncdispatch.nim
@@ -7,6 +7,8 @@
 #    distribution, for details about the copyright.
 #
 
+include "system/inclrtl"
+
 import os, oids, tables, strutils, macros
 
 import rawsockets
@@ -31,7 +33,7 @@ export TPort
 
 type
   PFutureBase* = ref object of PObject
-    cb: proc () {.closure.}
+    cb: proc () {.closure,gcsafe.}
     finished: bool
 
   PFuture*[T] = ref object of PFutureBase
@@ -68,7 +70,7 @@ proc fail*[T](future: PFuture[T], error: ref EBase) =
   if future.cb != nil:
     future.cb()
 
-proc `callback=`*(future: PFutureBase, cb: proc () {.closure.}) =
+proc `callback=`*(future: PFutureBase, cb: proc () {.closure,gcsafe.}) =
   ## Sets the callback proc to be called when the future completes.
   ##
   ## If future has already completed then ``cb`` will be called immediately.
@@ -80,7 +82,7 @@ proc `callback=`*(future: PFutureBase, cb: proc () {.closure.}) =
     future.cb()
 
 proc `callback=`*[T](future: PFuture[T],
-    cb: proc (future: PFuture[T]) {.closure.}) =
+    cb: proc (future: PFuture[T]) {.closure,gcsafe.}) =
   ## Sets the callback proc to be called when the future completes.
   ##
   ## If future has already completed then ``cb`` will be called immediately.
@@ -122,7 +124,7 @@ when defined(windows) or defined(nimdoc):
     TCompletionData* = object
       sock: TAsyncFD
       cb: proc (sock: TAsyncFD, bytesTransferred: DWORD,
-                errcode: TOSErrorCode) {.closure.}
+                errcode: TOSErrorCode) {.closure,gcsafe.}
 
     PDispatcher* = ref object
       ioPort: THandle
@@ -237,7 +239,7 @@ when defined(windows) or defined(nimdoc):
     let func =
       cast[proc (s: TSocketHandle, name: ptr TSockAddr, namelen: cint, 
          lpSendBuffer: pointer, dwSendDataLength: dword,
-         lpdwBytesSent: PDWORD, lpOverlapped: POverlapped): bool {.stdcall.}](connectExPtr)
+         lpdwBytesSent: PDWORD, lpOverlapped: POverlapped): bool {.stdcall,gcsafe.}](connectExPtr)
 
     result = func(s, name, namelen, lpSendBuffer, dwSendDataLength, lpdwBytesSent,
          lpOverlapped)
@@ -251,7 +253,7 @@ when defined(windows) or defined(nimdoc):
       cast[proc (listenSock, acceptSock: TSocketHandle, lpOutputBuffer: pointer,
                  dwReceiveDataLength, dwLocalAddressLength,
                  dwRemoteAddressLength: DWORD, lpdwBytesReceived: PDWORD,
-                 lpOverlapped: POverlapped): bool {.stdcall.}](acceptExPtr)
+                 lpOverlapped: POverlapped): bool {.stdcall,gcsafe.}](acceptExPtr)
     result = func(listenSock, acceptSock, lpOutputBuffer, dwReceiveDataLength,
         dwLocalAddressLength, dwRemoteAddressLength, lpdwBytesReceived,
         lpOverlapped)
@@ -268,7 +270,7 @@ when defined(windows) or defined(nimdoc):
                  dwReceiveDataLength, dwLocalAddressLength,
                  dwRemoteAddressLength: DWORD, LocalSockaddr: ptr ptr TSockAddr,
                  LocalSockaddrLength: lpint, RemoteSockaddr: ptr ptr TSockAddr,
-                RemoteSockaddrLength: lpint) {.stdcall.}](getAcceptExSockAddrsPtr)
+                RemoteSockaddrLength: lpint) {.stdcall,gcsafe.}](getAcceptExSockAddrsPtr)
     
     func(lpOutputBuffer, dwReceiveDataLength, dwLocalAddressLength,
                   dwRemoteAddressLength, LocalSockaddr, LocalSockaddrLength,
@@ -537,7 +539,7 @@ else:
   from posix import EINTR, EAGAIN, EINPROGRESS, EWOULDBLOCK, MSG_PEEK
   type
     TAsyncFD* = distinct cint
-    TCallback = proc (sock: TAsyncFD): bool {.closure.}
+    TCallback = proc (sock: TAsyncFD): bool {.closure,gcsafe.}
 
     PData* = ref object of PObject
       sock: TAsyncFD
@@ -757,7 +759,7 @@ proc accept*(socket: TAsyncFD): PFuture[TAsyncFD] =
 
 template createCb*(retFutureSym, iteratorNameSym: expr): stmt {.immediate.} =
   var nameIterVar = iteratorNameSym
-  proc cb {.closure.} =
+  proc cb {.closure,gcsafe.} =
     if not nameIterVar.finished:
       var next = nameIterVar()
       if next == nil:
diff --git a/lib/pure/asyncio.nim b/lib/pure/asyncio.nim
index ab09dc860..c68ca4350 100644
--- a/lib/pure/asyncio.nim
+++ b/lib/pure/asyncio.nim
@@ -6,6 +6,8 @@
 #    distribution, for details about the copyright.
 #
 
+include "system/inclrtl"
+
 import sockets, os
 
 ## This module implements an asynchronous event loop together with asynchronous sockets
@@ -98,13 +100,13 @@ type
     fd*: TSocketHandle
     deleVal*: PObject
 
-    handleRead*: proc (h: PObject) {.nimcall.}
-    handleWrite*: proc (h: PObject) {.nimcall.}
-    handleError*: proc (h: PObject) {.nimcall.}
-    hasDataBuffered*: proc (h: PObject): bool {.nimcall.}
+    handleRead*: proc (h: PObject) {.nimcall, gcsafe.}
+    handleWrite*: proc (h: PObject) {.nimcall, gcsafe.}
+    handleError*: proc (h: PObject) {.nimcall, gcsafe.}
+    hasDataBuffered*: proc (h: PObject): bool {.nimcall, gcsafe.}
     
     open*: bool
-    task*: proc (h: PObject) {.nimcall.}
+    task*: proc (h: PObject) {.nimcall, gcsafe.}
     mode*: TFileMode
     
   PDelegate* = ref TDelegate
@@ -118,13 +120,13 @@ type
     socket: TSocket
     info: TInfo
 
-    handleRead*: proc (s: PAsyncSocket) {.closure.}
-    handleWrite: proc (s: PAsyncSocket) {.closure.}
-    handleConnect*: proc (s:  PAsyncSocket) {.closure.}
+    handleRead*: proc (s: PAsyncSocket) {.closure, gcsafe.}
+    handleWrite: proc (s: PAsyncSocket) {.closure, gcsafe.}
+    handleConnect*: proc (s:  PAsyncSocket) {.closure, gcsafe.}
 
-    handleAccept*: proc (s:  PAsyncSocket) {.closure.}
+    handleAccept*: proc (s:  PAsyncSocket) {.closure, gcsafe.}
 
-    handleTask*: proc (s: PAsyncSocket) {.closure.}
+    handleTask*: proc (s: PAsyncSocket) {.closure, gcsafe.}
 
     lineBuffer: TaintedString ## Temporary storage for ``readLine``
     sendBuffer: string ## Temporary storage for ``send``
@@ -213,7 +215,7 @@ proc asyncSockHandleRead(h: PObject) =
   else:
     PAsyncSocket(h).handleAccept(PAsyncSocket(h))
 
-proc close*(sock: PAsyncSocket)
+proc close*(sock: PAsyncSocket) {.gcsafe.}
 proc asyncSockHandleWrite(h: PObject) =
   when defined(ssl):
     if PAsyncSocket(h).socket.isSSL and not
@@ -254,7 +256,7 @@ proc asyncSockHandleWrite(h: PObject) =
         PAsyncSocket(h).deleg.mode = fmRead
 
 when defined(ssl):
-  proc asyncSockDoHandshake(h: PObject) =
+  proc asyncSockDoHandshake(h: PObject) {.gcsafe.} =
     if PAsyncSocket(h).socket.isSSL and not
          PAsyncSocket(h).socket.gotHandshake:
       if PAsyncSocket(h).sslNeedAccept:
@@ -437,7 +439,7 @@ proc isSendDataBuffered*(s: PAsyncSocket): bool =
   return s.sendBuffer.len != 0
 
 proc setHandleWrite*(s: PAsyncSocket,
-    handleWrite: proc (s: PAsyncSocket) {.closure.}) =
+    handleWrite: proc (s: PAsyncSocket) {.closure, gcsafe.}) =
   ## Setter for the ``handleWrite`` event.
   ##
   ## To remove this event you should use the ``delHandleWrite`` function.
diff --git a/lib/pure/cgi.nim b/lib/pure/cgi.nim
index 4e2b6f5f8..31fb24eef 100644
--- a/lib/pure/cgi.nim
+++ b/lib/pure/cgi.nim
@@ -377,7 +377,7 @@ proc setCookie*(name, value: string) =
   write(stdout, "Set-Cookie: ", name, "=", value, "\n")
 
 var
-  gcookies: PStringTable = nil
+  gcookies {.threadvar.}: PStringTable
 
 proc getCookie*(name: string): TaintedString =
   ## Gets a cookie. If no cookie of `name` exists, "" is returned.
diff --git a/lib/pure/ftpclient.nim b/lib/pure/ftpclient.nim
index 3bb55239b..53f6688b9 100644
--- a/lib/pure/ftpclient.nim
+++ b/lib/pure/ftpclient.nim
@@ -6,6 +6,8 @@
 #    distribution, for details about the copyright.
 #
 
+include "system/inclrtl"
+
 import sockets, strutils, parseutils, times, os, asyncio
 
 ## This module **partially** implements an FTP client as specified
@@ -41,7 +43,7 @@ type
       dummyA, dummyB: pointer # workaround a Nimrod API issue
       asyncCSock: PAsyncSocket
       asyncDSock: PAsyncSocket
-      handleEvent*: proc (ftp: PAsyncFTPClient, ev: TFTPEvent) {.closure.}
+      handleEvent*: proc (ftp: PAsyncFTPClient, ev: TFTPEvent){.closure,gcsafe.}
       disp: PDispatcher
       asyncDSockID: PDelegate
     user, pass: string
@@ -59,7 +61,7 @@ type
     JRetrText, JRetr, JStore
 
   TFTPJob = object
-    prc: proc (ftp: PFTPClient, async: bool): bool {.nimcall.}
+    prc: proc (ftp: PFTPClient, async: bool): bool {.nimcall, gcsafe.}
     case typ*: FTPJobType
     of JRetrText:
       lines: string
@@ -148,7 +150,8 @@ proc assertReply(received: TaintedString, expected: varargs[string]) =
                      [expected.join("' or '"), received.string])
 
 proc createJob(ftp: PFTPClient,
-               prc: proc (ftp: PFTPClient, async: bool): bool {.nimcall.},
+               prc: proc (ftp: PFTPClient, async: bool): bool {.
+                          nimcall,gcsafe.},
                cmd: FTPJobType) =
   if ftp.jobInProgress:
     raise newException(EFTP, "Unable to do two jobs at once.")
@@ -558,7 +561,7 @@ proc csockHandleRead(s: PAsyncSocket, ftp: PAsyncFTPClient) =
 
 proc asyncFTPClient*(address: string, port = TPort(21),
                      user, pass = "",
-    handleEvent: proc (ftp: PAsyncFTPClient, ev: TFTPEvent) {.closure.} = 
+    handleEvent: proc (ftp: PAsyncFTPClient, ev: TFTPEvent) {.closure,gcsafe.} = 
       (proc (ftp: PAsyncFTPClient, ev: TFTPEvent) = discard)): PAsyncFTPClient =
   ## Create a ``PAsyncFTPClient`` object.
   ##
diff --git a/lib/pure/httpserver.nim b/lib/pure/httpserver.nim
index 901fdc779..8de708c5d 100644
--- a/lib/pure/httpserver.nim
+++ b/lib/pure/httpserver.nim
@@ -477,7 +477,7 @@ proc nextAsync(s: PAsyncHTTPServer) =
     s.path = data.substr(i, last-1)
 
 proc asyncHTTPServer*(handleRequest: proc (server: PAsyncHTTPServer, client: TSocket, 
-                        path, query: string): bool {.closure.},
+                        path, query: string): bool {.closure, gcsafe.},
                      port = TPort(80), address = "",
                      reuseAddr = false): PAsyncHTTPServer =
   ## Creates an Asynchronous HTTP server at ``port``.
diff --git a/lib/pure/irc.nim b/lib/pure/irc.nim
index 31a673210..49d9a9a34 100644
--- a/lib/pure/irc.nim
+++ b/lib/pure/irc.nim
@@ -32,6 +32,8 @@
 ## **Warning:** The API of this module is unstable, and therefore is subject
 ## to change.
 
+include "system/inclrtl"
+
 import sockets, strutils, parseutils, times, asyncio, os
 
 type
@@ -41,7 +43,7 @@ type
     nick, user, realname, serverPass: string
     case isAsync: bool
     of true:
-      handleEvent: proc (irc: PAsyncIRC, ev: TIRCEvent) {.closure.}
+      handleEvent: proc (irc: PAsyncIRC, ev: TIRCEvent) {.closure, gcsafe.}
       asyncSock: PAsyncSocket
       myDispatcher: PDispatcher
     of false:
@@ -445,7 +447,7 @@ proc asyncIRC*(address: string, port: TPort = 6667.TPort,
               realname = "NimrodBot", serverPass = "",
               joinChans: seq[string] = @[],
               msgLimit: bool = true,
-              ircEvent: proc (irc: PAsyncIRC, ev: TIRCEvent) {.closure.}
+              ircEvent: proc (irc: PAsyncIRC, ev: TIRCEvent) {.closure,gcsafe.}
               ): PAsyncIRC =
   ## Use this function if you want to use asyncio's dispatcher.
   ## 
diff --git a/lib/pure/math.nim b/lib/pure/math.nim
index 3997b059f..e4aecd272 100644
--- a/lib/pure/math.nim
+++ b/lib/pure/math.nim
@@ -12,6 +12,8 @@
 ## Basic math routines for Nimrod.
 ## This module is available for the JavaScript target.
 
+include "system/inclrtl"
+
 {.push debugger:off .} # the user does not want to trace a part
                        # of the standard library!
 
@@ -127,25 +129,25 @@ proc variance*(x: openArray[float]): float {.noSideEffect.} =
     result = result + diff*diff
   result = result / toFloat(len(x))
 
-proc random*(max: int): int
+proc random*(max: int): int {.gcsafe.}
   ## returns a random number in the range 0..max-1. The sequence of
   ## random number is always the same, unless `randomize` is called
   ## which initializes the random number generator with a "random"
   ## number, i.e. a tickcount.
 
 when not defined(windows):
-  proc random*(max: float): float
+  proc random*(max: float): float {.gcsafe.}
     ## returns a random number in the range 0..<max. The sequence of
     ## random number is always the same, unless `randomize` is called
     ## which initializes the random number generator with a "random"
     ## number, i.e. a tickcount. This is currently not supported for windows.
 
-proc randomize*()
+proc randomize*() {.gcsafe.}
   ## initializes the random number generator with a "random"
   ## number, i.e. a tickcount. Note: Does nothing for the JavaScript target,
   ## as JavaScript does not support this.
   
-proc randomize*(seed: int)
+proc randomize*(seed: int) {.gcsafe.}
   ## initializes the random number generator with a specific seed.
   ## Note: Does nothing for the JavaScript target,
   ## as JavaScript does not support this.
@@ -227,8 +229,8 @@ else:
     result = int(floor(mathrandom() * float(max)))
   proc random(max: float): float =
     result = float(mathrandom() * float(max))
-  proc randomize() = nil
-  proc randomize(seed: int) = nil
+  proc randomize() = discard
+  proc randomize(seed: int) = discard
   
   proc sqrt*(x: float): float {.importc: "Math.sqrt", nodecl.}
   proc ln*(x: float): float {.importc: "Math.log", nodecl.}
diff --git a/lib/pure/os.nim b/lib/pure/os.nim
index faca17e98..62261753f 100644
--- a/lib/pure/os.nim
+++ b/lib/pure/os.nim
@@ -1564,7 +1564,7 @@ when defined(windows):
   # ourselves. This has the additional benefit that the program's behaviour
   # is always the same -- independent of the used C compiler.
   var
-    ownArgv: seq[string]
+    ownArgv {.threadvar.}: seq[string]
 
   proc paramCount*(): int {.rtl, extern: "nos$1", tags: [FReadIO].} =
     ## Returns the number of `command line arguments`:idx: given to the
diff --git a/lib/pure/parsecfg.nim b/lib/pure/parsecfg.nim
index f3249b107..727a8efd8 100644
--- a/lib/pure/parsecfg.nim
+++ b/lib/pure/parsecfg.nim
@@ -70,7 +70,7 @@ const
   SymChars: TCharSet = {'a'..'z', 'A'..'Z', '0'..'9', '_', '\x80'..'\xFF', '.',
                         '/', '\\'} 
   
-proc rawGetTok(c: var TCfgParser, tok: var TToken)
+proc rawGetTok(c: var TCfgParser, tok: var TToken) {.gcsafe.}
 
 proc open*(c: var TCfgParser, input: PStream, filename: string, 
            lineOffset = 0) {.
diff --git a/lib/pure/scgi.nim b/lib/pure/scgi.nim
index a6a0faabc..45f837833 100644
--- a/lib/pure/scgi.nim
+++ b/lib/pure/scgi.nim
@@ -26,6 +26,8 @@
 ## **Warning:** The API of this module is unstable, and therefore is subject
 ## to change.
 
+include "system/inclrtl"
+
 import sockets, strutils, os, strtabs, asyncio
 
 type
@@ -82,7 +84,7 @@ type
   
   TAsyncScgiState = object
     handleRequest: proc (client: PAsyncSocket, 
-                         input: string, headers: PStringTable) {.closure.}
+                         input: string, headers: PStringTable) {.closure,gcsafe.}
     asyncServer: PAsyncSocket
     disp: PDispatcher
   PAsyncScgiState* = ref TAsyncScgiState
@@ -150,7 +152,7 @@ proc writeStatusOkTextContent*(c: TSocket, contentType = "text/html") =
          "Content-Type: $1\r\L\r\L" % contentType)
 
 proc run*(handleRequest: proc (client: TSocket, input: string, 
-                               headers: PStringTable): bool {.nimcall.},
+                               headers: PStringTable): bool {.nimcall,gcsafe.},
           port = TPort(4000)) = 
   ## encapsulates the SCGI object and main loop.
   var s: TScgiState
@@ -246,7 +248,8 @@ proc handleAccept(sock: PAsyncSocket, s: PAsyncScgiState) =
   s.disp.register(client)
 
 proc open*(handleRequest: proc (client: PAsyncSocket, 
-                                input: string, headers: PStringTable) {.closure.},
+                                input: string, headers: PStringTable) {.
+                                closure, gcsafe.},
            port = TPort(4000), address = "127.0.0.1",
            reuseAddr = false): PAsyncScgiState =
   ## Creates an ``PAsyncScgiState`` object which serves as a SCGI server.
diff --git a/lib/pure/sockets.nim b/lib/pure/sockets.nim
index b6acc329f..8d96cbaaf 100644
--- a/lib/pure/sockets.nim
+++ b/lib/pure/sockets.nim
@@ -24,6 +24,8 @@
 ## Asynchronous sockets are supported, however a better alternative is to use
 ## the `asyncio <asyncio.html>`_ module.
 
+include "system/inclrtl"
+
 {.deadCodeElim: on.}
 
 when hostOS == "solaris":
@@ -544,7 +546,7 @@ proc acceptAddr*(server: TSocket, client: var TSocket, address: var string) {.
             else:
               SSLError("Unknown error")
 
-proc setBlocking*(s: TSocket, blocking: bool) {.tags: [].}
+proc setBlocking*(s: TSocket, blocking: bool) {.tags: [], gcsafe.}
   ## Sets blocking mode on socket
 
 when defined(ssl):
diff --git a/lib/pure/streams.nim b/lib/pure/streams.nim
index 3b6dc87a5..63622a26c 100644
--- a/lib/pure/streams.nim
+++ b/lib/pure/streams.nim
@@ -12,6 +12,8 @@
 ## interface for Nimrod file objects (`TFile`) and strings. Other modules
 ## may provide other implementations for this standard stream interface.
 
+include "system/inclrtl"
+
 proc newEIO(msg: string): ref EIO =
   new(result)
   result.msg = msg
@@ -23,15 +25,15 @@ type
                                ## here shouldn't be used directly. They are
                                ## accessible so that a stream implementation
                                ## can override them.
-    closeImpl*: proc (s: PStream) {.nimcall, tags: [].}
-    atEndImpl*: proc (s: PStream): bool {.nimcall, tags: [].}
-    setPositionImpl*: proc (s: PStream, pos: int) {.nimcall, tags: [].}
-    getPositionImpl*: proc (s: PStream): int {.nimcall, tags: [].}
+    closeImpl*: proc (s: PStream) {.nimcall, tags: [], gcsafe.}
+    atEndImpl*: proc (s: PStream): bool {.nimcall, tags: [], gcsafe.}
+    setPositionImpl*: proc (s: PStream, pos: int) {.nimcall, tags: [], gcsafe.}
+    getPositionImpl*: proc (s: PStream): int {.nimcall, tags: [], gcsafe.}
     readDataImpl*: proc (s: PStream, buffer: pointer,
-                         bufLen: int): int {.nimcall, tags: [FReadIO].}
+                         bufLen: int): int {.nimcall, tags: [FReadIO], gcsafe.}
     writeDataImpl*: proc (s: PStream, buffer: pointer, bufLen: int) {.nimcall,
-      tags: [FWriteIO].}
-    flushImpl*: proc (s: PStream) {.nimcall, tags: [FWriteIO].}
+      tags: [FWriteIO], gcsafe.}
+    flushImpl*: proc (s: PStream) {.nimcall, tags: [FWriteIO], gcsafe.}
 
 proc flush*(s: PStream) =
   ## flushes the buffers that the stream `s` might use.
diff --git a/lib/pure/times.nim b/lib/pure/times.nim
index 2fce235e2..fdff06b2a 100644
--- a/lib/pure/times.nim
+++ b/lib/pure/times.nim
@@ -135,38 +135,38 @@ type
     months*: int      ## The number of months
     years*: int       ## The number of years
 
-proc getTime*(): TTime {.tags: [FTime].}
+proc getTime*(): TTime {.tags: [FTime], gcsafe.}
   ## gets the current calendar time as a UNIX epoch value (number of seconds
   ## elapsed since 1970) with integer precission. Use epochTime for higher
   ## resolution.
-proc getLocalTime*(t: TTime): TTimeInfo {.tags: [FTime], raises: [].}
+proc getLocalTime*(t: TTime): TTimeInfo {.tags: [FTime], raises: [], gcsafe.}
   ## converts the calendar time `t` to broken-time representation,
   ## expressed relative to the user's specified time zone.
-proc getGMTime*(t: TTime): TTimeInfo {.tags: [FTime], raises: [].}
+proc getGMTime*(t: TTime): TTimeInfo {.tags: [FTime], raises: [], gcsafe.}
   ## converts the calendar time `t` to broken-down time representation,
   ## expressed in Coordinated Universal Time (UTC).
 
-proc timeInfoToTime*(timeInfo: TTimeInfo): TTime {.tags: [].}
+proc timeInfoToTime*(timeInfo: TTimeInfo): TTime {.tags: [], gcsafe.}
   ## converts a broken-down time structure to
   ## calendar time representation. The function ignores the specified
   ## contents of the structure members `weekday` and `yearday` and recomputes
   ## them from the other information in the broken-down time structure.
 
-proc fromSeconds*(since1970: float): TTime {.tags: [], raises: [].}
+proc fromSeconds*(since1970: float): TTime {.tags: [], raises: [], gcsafe.}
   ## Takes a float which contains the number of seconds since the unix epoch and
   ## returns a time object.
 
-proc fromSeconds*(since1970: int64): TTime {.tags: [], raises: [].} = 
+proc fromSeconds*(since1970: int64): TTime {.tags: [], raises: [], gcsafe.} = 
   ## Takes an int which contains the number of seconds since the unix epoch and
   ## returns a time object.
   fromSeconds(float(since1970))
 
-proc toSeconds*(time: TTime): float {.tags: [], raises: [].}
+proc toSeconds*(time: TTime): float {.tags: [], raises: [], gcsafe.}
   ## Returns the time in seconds since the unix epoch.
 
-proc `$` *(timeInfo: TTimeInfo): string {.tags: [], raises: [].}
+proc `$` *(timeInfo: TTimeInfo): string {.tags: [], raises: [], gcsafe.}
   ## converts a `TTimeInfo` object to a string representation.
-proc `$` *(time: TTime): string {.tags: [], raises: [].}
+proc `$` *(time: TTime): string {.tags: [], raises: [], gcsafe.}
   ## converts a calendar time to a string representation.
 
 proc `-`*(a, b: TTime): int64 {.
@@ -189,14 +189,15 @@ proc `==`*(a, b: TTime): bool {.
   result = a - b == 0
 
 when not defined(JS):
-  proc getTzname*(): tuple[nonDST, DST: string] {.tags: [FTime], raises: [].}
+  proc getTzname*(): tuple[nonDST, DST: string] {.tags: [FTime], raises: [],
+    gcsafe.}
     ## returns the local timezone; ``nonDST`` is the name of the local non-DST
     ## timezone, ``DST`` is the name of the local DST timezone.
 
-proc getTimezone*(): int {.tags: [FTime], raises: [].}
+proc getTimezone*(): int {.tags: [FTime], raises: [], gcsafe.}
   ## returns the offset of the local (non-DST) timezone in seconds west of UTC.
 
-proc getStartMilsecs*(): int {.deprecated, tags: [FTime].}
+proc getStartMilsecs*(): int {.deprecated, tags: [FTime], gcsafe.}
   ## get the miliseconds from the start of the program. **Deprecated since
   ## version 0.8.10.** Use ``epochTime`` or ``cpuTime`` instead.
 
diff --git a/lib/system.nim b/lib/system.nim
index 60d9c5453..a78ceb3fe 100644
--- a/lib/system.nim
+++ b/lib/system.nim
@@ -192,9 +192,6 @@ when defined(nimNewShared):
   type
     `shared`* {.magic: "Shared".}
     guarded* {.magic: "Guarded".}
-else:
-  {.pragma: gcsafe.}
-#{.pragma: gcsafe.}
 
 const NoFakeVars* = defined(NimrodVM) ## true if the backend doesn't support \
   ## "fake variables" like 'var EBADF {.importc.}: cint'.
diff --git a/lib/system/channels.nim b/lib/system/channels.nim
index 2e66680ef..e5535dbdc 100644
--- a/lib/system/channels.nim
+++ b/lib/system/channels.nim
@@ -29,7 +29,7 @@ type
     region: TMemRegion

   PRawChannel = ptr TRawChannel

   TLoadStoreMode = enum mStore, mLoad

-  TChannel*[TMsg] = TRawChannel ## a channel for thread communication

+  TChannel* {.gcsafe.}[TMsg] = TRawChannel ## a channel for thread communication

 

 const ChannelDeadMask = -2

 

diff --git a/lib/system/inclrtl.nim b/lib/system/inclrtl.nim
index 9831130e2..475a09686 100644
--- a/lib/system/inclrtl.nim
+++ b/lib/system/inclrtl.nim
@@ -16,6 +16,8 @@
 #    -> defined(useNimRtl) or appType == "lib" and not defined(createNimRtl)
 # 3) Exported into nimrtl.
 #    -> appType == "lib" and defined(createNimRtl)
+when not defined(nimNewShared):
+  {.pragma: gcsafe.}
 
 when defined(createNimRtl):
   when defined(useNimRtl): 
@@ -24,7 +26,7 @@ when defined(createNimRtl):
     {.error: "nimrtl must be built as a library!".}
 
 when defined(createNimRtl): 
-  {.pragma: rtl, exportc: "nimrtl_$1", dynlib.}
+  {.pragma: rtl, exportc: "nimrtl_$1", dynlib, gcsafe.}
   {.pragma: inl.}
   {.pragma: compilerRtl, compilerproc, exportc: "nimrtl_$1", dynlib.}
 elif defined(useNimRtl):
@@ -34,11 +36,11 @@ elif defined(useNimRtl):
     const nimrtl* = "nimrtl.dylib"
   else: 
     const nimrtl* = "libnimrtl.so"
-  {.pragma: rtl, importc: "nimrtl_$1", dynlib: nimrtl.}
+  {.pragma: rtl, importc: "nimrtl_$1", dynlib: nimrtl, gcsafe.}
   {.pragma: inl.}
   {.pragma: compilerRtl, compilerproc, importc: "nimrtl_$1", dynlib: nimrtl.}
 else:
-  {.pragma: rtl.}
+  {.pragma: rtl, gcsafe.}
   {.pragma: inl, inline.}
   {.pragma: compilerRtl, compilerproc.}
 
diff --git a/lib/system/threads.nim b/lib/system/threads.nim
index ff9ab6cc0..0d52e4d09 100644
--- a/lib/system/threads.nim
+++ b/lib/system/threads.nim
@@ -256,9 +256,9 @@ type
                           ## that **must not** be part of a message! Use
                           ## a ``TThreadId`` for that.
     when TArg is void:
-      dataFn: proc () {.nimcall.}
+      dataFn: proc () {.nimcall, gcsafe.}
     else:
-      dataFn: proc (m: TArg) {.nimcall.}
+      dataFn: proc (m: TArg) {.nimcall, gcsafe.}
       data: TArg
   TThreadId*[TArg] = ptr TThread[TArg] ## the current implementation uses
                                        ## a pointer as a thread ID.