diff options
-rw-r--r-- | compiler/ast.nim | 9 | ||||
-rw-r--r-- | compiler/astalgo.nim | 36 | ||||
-rw-r--r-- | compiler/cgen.nim | 5 | ||||
-rw-r--r-- | compiler/dfa.nim | 2 | ||||
-rw-r--r-- | compiler/docgen.nim | 7 | ||||
-rw-r--r-- | compiler/jsgen.nim | 27 | ||||
-rw-r--r-- | compiler/msgs.nim | 15 | ||||
-rw-r--r-- | compiler/options.nim | 4 | ||||
-rw-r--r-- | compiler/pragmas.nim | 2 | ||||
-rw-r--r-- | compiler/ropes.nim | 26 | ||||
-rw-r--r-- | compiler/sempass2.nim | 22 | ||||
-rw-r--r-- | compiler/semtypes.nim | 4 | ||||
-rw-r--r-- | compiler/semtypinst.nim | 6 | ||||
-rw-r--r-- | compiler/transf.nim | 3 | ||||
-rw-r--r-- | compiler/types.nim | 25 | ||||
-rw-r--r-- | doc/manual.rst | 37 | ||||
-rw-r--r-- | lib/packages/docutils/rst.nim | 4 | ||||
-rw-r--r-- | tests/destructor/tdiscard.nim | 1 | ||||
-rw-r--r-- | tests/destructor/tmove_objconstr.nim | 1 | ||||
-rw-r--r-- | tests/destructor/tuse_result_prevents_sinks.nim | 1 | ||||
-rw-r--r-- | tests/effects/tgcsafe3.nim | 21 | ||||
-rw-r--r-- | tests/js/tbasics.nim | 14 |
22 files changed, 161 insertions, 111 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim index b325e6d42..9ce102c2f 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -479,7 +479,7 @@ type tfNoSideEffect, # procedure type does not allow side effects tfFinal, # is the object final? tfInheritable, # is the object inheritable? - tfAcyclic, # type is acyclic (for GC optimization) + tfHasOwned, # type contains an 'owned' type and must be moved tfEnumHasHoles, # enum cannot be mapped into a range tfShallow, # type can be shallow copied on assignment tfThread, # proc type is marked as ``thread``; alias for ``gcsafe`` @@ -1472,6 +1472,13 @@ proc propagateToOwner*(owner, elem: PType) = o2.flags.incl tfHasAsgn owner.flags.incl tfHasAsgn + if tfHasOwned in elem.flags: + let o2 = owner.skipTypes({tyGenericInst, tyAlias, tySink}) + if o2.kind in {tyTuple, tyObject, tyArray, + tySequence, tyOpt, tySet, tyDistinct}: + o2.flags.incl tfHasOwned + owner.flags.incl tfHasOwned + if owner.kind notin {tyProc, tyGenericInst, tyGenericBody, tyGenericInvocation, tyPtr}: let elemB = elem.skipTypes({tyGenericInst, tyAlias, tySink}) diff --git a/compiler/astalgo.nim b/compiler/astalgo.nim index 8187341b3..be8d23b90 100644 --- a/compiler/astalgo.nim +++ b/compiler/astalgo.nim @@ -353,6 +353,12 @@ proc symToYaml(conf: ConfigRef; n: PSym, indent: int = 0, maxRecDepth: int = - 1 import tables +const backrefStyle = "\e[90m" +const enumStyle = "\e[34m" +const numberStyle = "\e[33m" +const stringStyle = "\e[32m" +const resetStyle = "\e[0m" + type DebugPrinter = object conf: ConfigRef @@ -361,6 +367,7 @@ type indent: int currentLine: int firstItem: bool + useColor: bool res: string proc indentMore(this: var DebugPrinter) = @@ -407,15 +414,29 @@ proc key(this: var DebugPrinter; key: string) = this.res.add "\": " proc value(this: var DebugPrinter; value: string) = + if this.useColor: + this.res.add stringStyle this.res.add "\"" this.res.add value this.res.add "\"" + if this.useColor: + this.res.add resetStyle proc value(this: var DebugPrinter; value: BiggestInt) = + if this.useColor: + this.res.add numberStyle this.res.add value + if this.useColor: + this.res.add resetStyle proc value[T: enum](this: var DebugPrinter; value: T) = - this.value $value + if this.useColor: + this.res.add enumStyle + this.res.add "\"" + this.res.add $value + this.res.add "\"" + if this.useColor: + this.res.add resetStyle proc value[T: enum](this: var DebugPrinter; value: set[T]) = this.openBracket @@ -436,9 +457,13 @@ template earlyExit(this: var DebugPrinter; n: PType | PNode | PSym) = if index < 0: this.visited[cast[pointer](n)] = this.currentLine else: + if this.useColor: + this.res.add backrefStyle this.res.add "<defined " this.res.add(this.currentLine - index) this.res.add " lines upwards>" + if this.useColor: + this.res.add resetStyle return proc value(this: var DebugPrinter; value: PType): void @@ -448,7 +473,7 @@ proc value(this: var DebugPrinter; value: PSym): void = this.openCurly this.key("kind") - this.value($value.kind) + this.value(value.kind) this.key("name") this.value(value.name.s) this.key("id") @@ -477,6 +502,7 @@ proc value(this: var DebugPrinter; value: PType): void = if value.sym != nil: this.key "sym" this.value value.sym + #this.value value.sym.name.s if card(value.flags) > 0: this.key "flags" @@ -529,7 +555,8 @@ proc value(this: var DebugPrinter; value: PNode): void = this.value value.strVal of nkSym: this.key "sym" - this.value(value.sym) + this.value value.sym + #this.value value.sym.name.s of nkIdent: if value.ident != nil: this.key "ident" @@ -554,6 +581,7 @@ when declared(echo): var this: DebugPrinter this.visited = initTable[pointer, int]() this.renderSymType = true + this.useColor = not defined(windows) this.value(n) echo($this.res) @@ -561,6 +589,7 @@ when declared(echo): var this: DebugPrinter this.visited = initTable[pointer, int]() this.renderSymType = true + this.useColor = not defined(windows) this.value(n) echo($this.res) @@ -568,6 +597,7 @@ when declared(echo): var this: DebugPrinter this.visited = initTable[pointer, int]() this.renderSymType = true + this.useColor = not defined(windows) this.value(n) echo($this.res) diff --git a/compiler/cgen.nim b/compiler/cgen.nim index 45daa00d9..09076c520 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -42,8 +42,6 @@ when not declared(dynlib.libCandidates): when options.hasTinyCBackend: import tccgen -# implementation - proc hcrOn(m: BModule): bool = m.config.hcrOn proc hcrOn(p: BProc): bool = p.module.config.hcrOn @@ -295,6 +293,7 @@ proc genObjectInit(p: BProc, section: TCProcSection, t: PType, a: TLoc, includeHeader(p.module, "<new>") linefmt(p, section, "new ($1) $2;$n", rdLoc(a), getTypeDesc(p.module, t)) + if optNimV2 in p.config.globalOptions: return case analyseObjectWithTypeField(t) of frNone: discard @@ -303,7 +302,7 @@ proc genObjectInit(p: BProc, section: TCProcSection, t: PType, a: TLoc, if not takeAddr: r = "(*$1)" % [r] var s = skipTypes(t, abstractInst) if not p.module.compileToCpp: - while (s.kind == tyObject) and (s.sons[0] != nil): + while s.kind == tyObject and s.sons[0] != nil: add(r, ".Sup") s = skipTypes(s.sons[0], skipPtrs) linefmt(p, section, "$1.m_type = $2;$n", r, genTypeInfo(p.module, t, a.lode.info)) diff --git a/compiler/dfa.nim b/compiler/dfa.nim index 968b16945..cecb8394c 100644 --- a/compiler/dfa.nim +++ b/compiler/dfa.nim @@ -596,7 +596,7 @@ proc genCall(c: var Con; n: PNode) = gen(c, n[i]) when false: if t != nil and i < t.len and t.sons[i].kind == tyVar: - # XXX This is wrong! Pass by var is a 'might def', not a 'must def' + # This is wrong! Pass by var is a 'might def', not a 'must def' # like the other defs we emit. This is not good enough for a move # optimizer. genDef(c, n[i]) diff --git a/compiler/docgen.nim b/compiler/docgen.nim index e6847cad3..7e7666de4 100644 --- a/compiler/docgen.nim +++ b/compiler/docgen.nim @@ -67,7 +67,7 @@ proc attachToType(d: PDoc; p: PSym): PSym = template declareClosures = proc compilerMsgHandler(filename: string, line, col: int, - msgKind: rst.MsgKind, arg: string) {.procvar.} = + msgKind: rst.MsgKind, arg: string) {.procvar, gcsafe.} = # translate msg kind: var k: TMsgKind case msgKind @@ -81,9 +81,10 @@ template declareClosures = of mwUnknownSubstitution: k = warnUnknownSubstitutionX of mwUnsupportedLanguage: k = warnLanguageXNotSupported of mwUnsupportedField: k = warnFieldXNotSupported - globalError(conf, newLineInfo(conf, AbsoluteFile filename, line, col), k, arg) + {.gcsafe.}: + globalError(conf, newLineInfo(conf, AbsoluteFile filename, line, col), k, arg) - proc docgenFindFile(s: string): string {.procvar.} = + proc docgenFindFile(s: string): string {.procvar, gcsafe.} = result = options.findFile(conf, s).string if result.len == 0: result = getCurrentDir() / s diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index e3ca6830c..627cc6cdf 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -1804,6 +1804,10 @@ proc genOf(p: PProc, n: PNode, r: var TCompRes) = r.res = "isObj($1.m_type, $2)" % [x.res, genTypeInfo(p, t)] r.kind = resExpr +proc genDefault(p: PProc, n: PNode; r: var TCompRes) = + r.res = createVar(p, n.typ, indirect = false) + r.kind = resExpr + proc genReset(p: PProc, n: PNode) = var x: TCompRes useMagic(p, "genericReset") @@ -1938,6 +1942,7 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) = of mNewSeq: genNewSeq(p, n) of mNewSeqOfCap: unaryExpr(p, n, r, "", "[]") of mOf: genOf(p, n, r) + of mDefault: genDefault(p, n, r) of mReset: genReset(p, n) of mEcho: genEcho(p, n, r) of mNLen..mNError, mSlurp, mStaticExec: @@ -2138,7 +2143,7 @@ proc genProcBody(p: PProc, prc: PSym): Rope = if hasFrameInfo(p): add(result, frameDestroy(p)) -proc optionaLine(p: Rope): Rope = +proc optionalLine(p: Rope): Rope = if p == nil: return nil else: @@ -2182,11 +2187,11 @@ proc genProc(oldProc: PProc, prc: PSym): Rope = [ returnType, name, header, - optionaLine(p.globals), - optionaLine(p.locals), - optionaLine(resultAsgn), - optionaLine(genProcBody(p, prc)), - optionaLine(p.indentLine(returnStmt))] + optionalLine(p.globals), + optionalLine(p.locals), + optionalLine(resultAsgn), + optionalLine(genProcBody(p, prc)), + optionalLine(p.indentLine(returnStmt))] else: result = ~"\L" @@ -2203,11 +2208,11 @@ proc genProc(oldProc: PProc, prc: PSym): Rope = def = "function $#($#) {$n$#$#$#$#$#" % [ name, header, - optionaLine(p.globals), - optionaLine(p.locals), - optionaLine(resultAsgn), - optionaLine(genProcBody(p, prc)), - optionaLine(p.indentLine(returnStmt))] + optionalLine(p.globals), + optionalLine(p.locals), + optionalLine(resultAsgn), + optionalLine(genProcBody(p, prc)), + optionalLine(p.indentLine(returnStmt))] dec p.extraIndent result.add p.indentLine(def) diff --git a/compiler/msgs.nim b/compiler/msgs.nim index 78f253bdc..ca0425182 100644 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -324,14 +324,15 @@ proc log*(s: string) {.procvar.} = f.writeLine(s) close(f) -proc quit(conf: ConfigRef; msg: TMsgKind) = +proc quit(conf: ConfigRef; msg: TMsgKind) {.gcsafe.} = if defined(debug) or msg == errInternal or hintStackTrace in conf.notes: - if stackTraceAvailable() and isNil(conf.writelnHook): - writeStackTrace() - else: - styledMsgWriteln(fgRed, "No stack traceback available\n" & - "To create a stacktrace, rerun compilation with ./koch temp " & - conf.command & " <file>") + {.gcsafe.}: + if stackTraceAvailable() and isNil(conf.writelnHook): + writeStackTrace() + else: + styledMsgWriteln(fgRed, "No stack traceback available\n" & + "To create a stacktrace, rerun compilation with ./koch temp " & + conf.command & " <file>") quit 1 proc handleError(conf: ConfigRef; msg: TMsgKind, eh: TErrorHandling, s: string) = diff --git a/compiler/options.nim b/compiler/options.nim index 4bb17a03f..49ec6e87c 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -249,9 +249,9 @@ type suggestVersion*: int suggestMaxResults*: int lastLineInfo*: TLineInfo - writelnHook*: proc (output: string) {.closure.} + writelnHook*: proc (output: string) {.closure.} # cannot make this gcsafe yet because of Nimble structuredErrorHook*: proc (config: ConfigRef; info: TLineInfo; msg: string; - severity: Severity) {.closure.} + severity: Severity) {.closure, gcsafe.} cppCustomNamespace*: string proc hcrOn*(conf: ConfigRef): bool = return optHotCodeReloading in conf.globalOptions diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index addc9e9f3..364006dd1 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -933,7 +933,7 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int, of wAcyclic: noVal(c, it) if sym.typ == nil: invalidPragma(c, it) - else: incl(sym.typ.flags, tfAcyclic) + # now: ignored of wShallow: noVal(c, it) if sym.typ == nil: invalidPragma(c, it) diff --git a/compiler/ropes.nim b/compiler/ropes.nim index 0d6d7d78f..2071ab46a 100644 --- a/compiler/ropes.nim +++ b/compiler/ropes.nim @@ -82,12 +82,13 @@ proc newRope(data: string = ""): Rope = result.L = -len(data) result.data = data -var - cache: array[0..2048*2 - 1, Rope] # XXX Global here! +when not compileOption("threads"): + var + cache: array[0..2048*2 - 1, Rope] -proc resetRopeCache* = - for i in low(cache)..high(cache): - cache[i] = nil + proc resetRopeCache* = + for i in low(cache)..high(cache): + cache[i] = nil proc ropeInvariant(r: Rope): bool = if r == nil: @@ -107,13 +108,16 @@ var gCacheMisses* = 0 var gCacheIntTries* = 0 proc insertInCache(s: string): Rope = - inc gCacheTries - var h = hash(s) and high(cache) - result = cache[h] - if isNil(result) or result.data != s: - inc gCacheMisses + when declared(cache): + inc gCacheTries + var h = hash(s) and high(cache) + result = cache[h] + if isNil(result) or result.data != s: + inc gCacheMisses + result = newRope(s) + cache[h] = result + else: result = newRope(s) - cache[h] = result proc rope*(s: string): Rope = ## Converts a string to a rope. diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim index 923558a8d..9d46c0b0c 100644 --- a/compiler/sempass2.nim +++ b/compiler/sempass2.nim @@ -721,6 +721,17 @@ proc cstringCheck(tracked: PEffects; n: PNode) = message(tracked.config, n.info, warnUnsafeCode, renderTree(n)) proc track(tracked: PEffects, n: PNode) = + template gcsafeAndSideeffectCheck() = + if notGcSafe(op) and not importedFromC(a): + # and it's not a recursive call: + if not (a.kind == nkSym and a.sym == tracked.owner): + if warnGcUnsafe in tracked.config.notes: warnAboutGcUnsafe(n, tracked.config) + markGcUnsafe(tracked, a) + if tfNoSideEffect notin op.flags and not importedFromC(a): + # and it's not a recursive call: + if not (a.kind == nkSym and a.sym == tracked.owner): + markSideEffect(tracked, a) + case n.kind of nkSym: useVar(tracked, n) @@ -764,18 +775,11 @@ proc track(tracked: PEffects, n: PNode) = propagateEffects(tracked, n, a.sym) elif isIndirectCall(a, tracked.owner): assumeTheWorst(tracked, n, op) + gcsafeAndSideeffectCheck() else: mergeEffects(tracked, effectList.sons[exceptionEffects], n) mergeTags(tracked, effectList.sons[tagEffects], n) - if notGcSafe(op) and not importedFromC(a): - # and it's not a recursive call: - if not (a.kind == nkSym and a.sym == tracked.owner): - if warnGcUnsafe in tracked.config.notes: warnAboutGcUnsafe(n, tracked.config) - markGcUnsafe(tracked, a) - if tfNoSideEffect notin op.flags and not importedFromC(a): - # and it's not a recursive call: - if not (a.kind == nkSym and a.sym == tracked.owner): - markSideEffect(tracked, a) + gcsafeAndSideeffectCheck() if a.kind != nkSym or a.sym.magic != mNBindSym: for i in 1 ..< len(n): trackOperand(tracked, n.sons[i], paramType(op, i), a) if a.kind == nkSym and a.sym.magic in {mNew, mNewFinalize, mNewSeq}: diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index e717c6e07..0fabd5531 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -1854,7 +1854,9 @@ proc processMagicType(c: PContext, m: PSym) = case m.name.s of "lent": setMagicType(c.config, m, tyLent, c.config.target.ptrSize) of "sink": setMagicType(c.config, m, tySink, szUncomputedSize) - of "owned": setMagicType(c.config, m, tyOwned, c.config.target.ptrSize) + of "owned": + setMagicType(c.config, m, tyOwned, c.config.target.ptrSize) + incl m.typ.flags, tfHasOwned else: localError(c.config, m.info, errTypeExpected) else: localError(c.config, m.info, errTypeExpected) diff --git a/compiler/semtypinst.nim b/compiler/semtypinst.nim index 483588e6b..e3380c0e3 100644 --- a/compiler/semtypinst.nim +++ b/compiler/semtypinst.nim @@ -16,16 +16,12 @@ const tfInstClearedFlags = {tfHasMeta, tfUnresolved} proc checkPartialConstructedType(conf: ConfigRef; info: TLineInfo, t: PType) = - if tfAcyclic in t.flags and skipTypes(t, abstractInst).kind != tyObject: - localError(conf, info, "invalid pragma: acyclic") - elif t.kind in {tyVar, tyLent} and t.sons[0].kind in {tyVar, tyLent}: + if t.kind in {tyVar, tyLent} and t.sons[0].kind in {tyVar, tyLent}: localError(conf, info, "type 'var var' is not allowed") proc checkConstructedType*(conf: ConfigRef; info: TLineInfo, typ: PType) = var t = typ.skipTypes({tyDistinct}) if t.kind in tyTypeClasses: discard - elif tfAcyclic in t.flags and skipTypes(t, abstractInst).kind != tyObject: - localError(conf, info, "invalid pragma: acyclic") elif t.kind in {tyVar, tyLent} and t.sons[0].kind in {tyVar, tyLent}: localError(conf, info, "type 'var var' is not allowed") elif computeSize(conf, t) == szIllegalRecursion: diff --git a/compiler/transf.nim b/compiler/transf.nim index ec390da9a..ed4a7018d 100644 --- a/compiler/transf.nim +++ b/compiler/transf.nim @@ -893,7 +893,8 @@ proc transform(c: PTransf, n: PNode): PTransNode = nkBlockStmt, nkBlockExpr}: oldDeferAnchor = c.deferAnchor c.deferAnchor = n - if n.typ != nil and tfHasAsgn in n.typ.flags: + if (n.typ != nil and tfHasAsgn in n.typ.flags) or + optNimV2 in c.graph.config.globalOptions: c.needsDestroyPass = true case n.kind of nkSym: diff --git a/compiler/types.nim b/compiler/types.nim index 86e5e756a..b71888906 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -68,17 +68,6 @@ const typedescPtrs* = abstractPtrs + {tyTypeDesc} typedescInst* = abstractInst + {tyTypeDesc, tyOwned} -type - TTypeFieldResult* = enum - frNone, # type has no object type field - frHeader, # type has an object type field only in the header - frEmbedded # type has an object type field somewhere embedded - -proc analyseObjectWithTypeField*(t: PType): TTypeFieldResult - # this does a complex analysis whether a call to ``objectInit`` needs to be - # made or intializing of the type field suffices or if there is no type field - # at all in this type. - proc invalidGenericInst*(f: PType): bool = result = f.kind == tyGenericInst and lastSon(f) == nil @@ -242,11 +231,16 @@ proc containsObject*(t: PType): bool = result = searchTypeFor(t, isObjectPredicate) proc isObjectWithTypeFieldPredicate(t: PType): bool = - result = t.kind == tyObject and t.sons[0] == nil and not (t.sym != nil and {sfPure, sfInfixCall} * t.sym.flags != {}) and tfFinal notin t.flags +type + TTypeFieldResult* = enum + frNone, # type has no object type field + frHeader, # type has an object type field only in the header + frEmbedded # type has an object type field somewhere embedded + proc analyseObjectWithTypeFieldAux(t: PType, marker: var IntSet): TTypeFieldResult = var res: TTypeFieldResult @@ -276,7 +270,10 @@ proc analyseObjectWithTypeFieldAux(t: PType, else: discard -proc analyseObjectWithTypeField(t: PType): TTypeFieldResult = +proc analyseObjectWithTypeField*(t: PType): TTypeFieldResult = + # this does a complex analysis whether a call to ``objectInit`` needs to be + # made or intializing of the type field suffices or if there is no type field + # at all in this type. var marker = initIntSet() result = analyseObjectWithTypeFieldAux(t, marker) @@ -323,9 +320,7 @@ proc canFormAcycleNode(marker: var IntSet, n: PNode, startId: int): bool = proc canFormAcycleAux(marker: var IntSet, typ: PType, startId: int): bool = result = false if typ == nil: return - if tfAcyclic in typ.flags: return var t = skipTypes(typ, abstractInst+{tyOwned}-{tyTypeDesc}) - if tfAcyclic in t.flags: return case t.kind of tyTuple, tyObject, tyRef, tySequence, tyArray, tyOpenArray, tyVarargs: if not containsOrIncl(marker, t.id): diff --git a/doc/manual.rst b/doc/manual.rst index a2d51cf08..09daf4a95 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -6925,41 +6925,8 @@ The ``noreturn`` pragma is used to mark a proc that never returns. acyclic pragma -------------- -The ``acyclic`` pragma can be used for object types to mark them as acyclic -even though they seem to be cyclic. This is an **optimization** for the garbage -collector to not consider objects of this type as part of a cycle: - -.. code-block:: nim - type - Node = ref NodeObj - NodeObj {.acyclic.} = object - left, right: Node - data: string - -Or if we directly use a ref object: - -.. code-block:: nim - type - Node = ref object {.acyclic.} - left, right: Node - data: string - -In the example a tree structure is declared with the ``Node`` type. Note that -the type definition is recursive and the GC has to assume that objects of -this type may form a cyclic graph. The ``acyclic`` pragma passes the -information that this cannot happen to the GC. If the programmer uses the -``acyclic`` pragma for data types that are in reality cyclic, the GC may leak -memory, but nothing worse happens. - -**Future directions**: The ``acyclic`` pragma may become a property of a -``ref`` type: - -.. code-block:: nim - type - Node = acyclic ref NodeObj - NodeObj = object - left, right: Node - data: string +The ``acyclic`` pragma applies to type declarations. It is deprecated and +ignored. final pragma diff --git a/lib/packages/docutils/rst.nim b/lib/packages/docutils/rst.nim index 0b077b1f1..6e4e3f5dd 100644 --- a/lib/packages/docutils/rst.nim +++ b/lib/packages/docutils/rst.nim @@ -45,8 +45,8 @@ type mwUnsupportedField MsgHandler* = proc (filename: string, line, col: int, msgKind: MsgKind, - arg: string) {.closure.} ## what to do in case of an error - FindFileHandler* = proc (filename: string): string {.closure.} + arg: string) {.closure, gcsafe.} ## what to do in case of an error + FindFileHandler* = proc (filename: string): string {.closure, gcsafe.} const messages: array[MsgKind, string] = [ diff --git a/tests/destructor/tdiscard.nim b/tests/destructor/tdiscard.nim index ad09a1900..57b5ecb9b 100644 --- a/tests/destructor/tdiscard.nim +++ b/tests/destructor/tdiscard.nim @@ -1,5 +1,6 @@ discard """ joinable: false +target: "C" """ type diff --git a/tests/destructor/tmove_objconstr.nim b/tests/destructor/tmove_objconstr.nim index 6e11d9b27..bfc819ceb 100644 --- a/tests/destructor/tmove_objconstr.nim +++ b/tests/destructor/tmove_objconstr.nim @@ -8,6 +8,7 @@ test destroyed 0 4 Pony is dying!''' joinable: false +target: "C" """ # bug #4214 diff --git a/tests/destructor/tuse_result_prevents_sinks.nim b/tests/destructor/tuse_result_prevents_sinks.nim index 4c32eac91..37b5af9b2 100644 --- a/tests/destructor/tuse_result_prevents_sinks.nim +++ b/tests/destructor/tuse_result_prevents_sinks.nim @@ -1,5 +1,6 @@ discard """ output: "" + target: "C" """ # bug #9594 diff --git a/tests/effects/tgcsafe3.nim b/tests/effects/tgcsafe3.nim new file mode 100644 index 000000000..5137efe4c --- /dev/null +++ b/tests/effects/tgcsafe3.nim @@ -0,0 +1,21 @@ +discard """ + errormsg: "'myproc' is not GC-safe as it accesses 'global_proc' which is a global using GC'ed memory" + line: 12 + cmd: "nim $target --hints:on --threads:on $options $file" +""" + +var useGcMem = "string here" + +var global_proc: proc(a: string) {.nimcall.} = proc (a: string) = + echo useGcMem + +proc myproc(i: int) {.gcsafe.} = + when false: + if global_proc != nil: + echo "a" + if isNil(global_proc): + return + + global_proc("ho") + +myproc(0) diff --git a/tests/js/tbasics.nim b/tests/js/tbasics.nim index 33616776f..b297bb037 100644 --- a/tests/js/tbasics.nim +++ b/tests/js/tbasics.nim @@ -46,3 +46,17 @@ proc test2 = echo int(val) test2() + + +var someGlobal = default(array[5, int]) +for x in someGlobal: doAssert(x == 0) + +proc tdefault = + var x = default(int) + doAssert(x == 0) + proc inner(v: openarray[string]) = + doAssert(v.len == 0) + + inner(default(seq[string])) + +tdefault() |