diff options
-rw-r--r-- | compiler/msgs.nim | 7 | ||||
-rw-r--r-- | compiler/pragmas.nim | 4 | ||||
-rw-r--r-- | compiler/sempass2.nim | 7 | ||||
-rw-r--r-- | lib/core/macros.nim | 77 | ||||
-rw-r--r-- | lib/pure/asyncdispatch.nim | 20 | ||||
-rw-r--r-- | lib/pure/asyncio.nim | 28 | ||||
-rw-r--r-- | lib/pure/cgi.nim | 2 | ||||
-rw-r--r-- | lib/pure/ftpclient.nim | 11 | ||||
-rw-r--r-- | lib/pure/httpserver.nim | 2 | ||||
-rw-r--r-- | lib/pure/irc.nim | 6 | ||||
-rw-r--r-- | lib/pure/math.nim | 14 | ||||
-rw-r--r-- | lib/pure/os.nim | 2 | ||||
-rw-r--r-- | lib/pure/parsecfg.nim | 2 | ||||
-rw-r--r-- | lib/pure/scgi.nim | 9 | ||||
-rw-r--r-- | lib/pure/sockets.nim | 4 | ||||
-rw-r--r-- | lib/pure/streams.nim | 16 | ||||
-rw-r--r-- | lib/pure/times.nim | 25 | ||||
-rw-r--r-- | lib/system.nim | 3 | ||||
-rw-r--r-- | lib/system/channels.nim | 2 | ||||
-rw-r--r-- | lib/system/inclrtl.nim | 8 | ||||
-rw-r--r-- | lib/system/threads.nim | 4 |
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. |