diff --git a/compiler/cgen.nim b/compiler/cgen.nim index c67dd65814..3797a92c23 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -601,8 +601,18 @@ proc generateHeaders(m: BModule) = addf(m.s[cfsHeaders], "#include \"$1\"$N", [rope(it)]) else: addf(m.s[cfsHeaders], "#include $1$N", [rope(it)]) + add(m.s[cfsHeaders], "#undef LANGUAGE_C" & tnl) + add(m.s[cfsHeaders], "#undef MIPSEB" & tnl) + add(m.s[cfsHeaders], "#undef MIPSEL" & tnl) + add(m.s[cfsHeaders], "#undef PPC" & tnl) + add(m.s[cfsHeaders], "#undef R3000" & tnl) + add(m.s[cfsHeaders], "#undef R4000" & tnl) + add(m.s[cfsHeaders], "#undef i386" & tnl) add(m.s[cfsHeaders], "#undef linux" & tnl) + add(m.s[cfsHeaders], "#undef mips" & tnl) add(m.s[cfsHeaders], "#undef near" & tnl) + add(m.s[cfsHeaders], "#undef powerpc" & tnl) + add(m.s[cfsHeaders], "#undef unix" & tnl) proc initFrame(p: BProc, procname, filename: Rope): Rope = discard cgsym(p.module, "nimFrame") diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 9c93d54a3c..67a718b91c 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -152,6 +152,8 @@ proc isCastable(dst, src: PType): bool = result = false elif typeAllowed(dst, skParam) != nil: result = false + elif dst.kind == tyProc and dst.callConv == ccClosure: + result = src.kind == tyProc and src.callConv == ccClosure else: result = (dstSize >= srcSize) or (skipTypes(dst, abstractInst).kind in IntegralTypes) or @@ -227,7 +229,10 @@ proc semCast(c: PContext, n: PNode): PNode = if tfHasMeta in targetType.flags: localError(n.sons[0].info, errCastToANonConcreteType, $targetType) if not isCastable(targetType, castedExpr.typ): - localError(n.info, errExprCannotBeCastToX, $targetType) + let tar = $targetType + let alt = typeToString(targetType, preferDesc) + let msg = if tar != alt: tar & "=" & alt else: tar + localError(n.info, errExprCannotBeCastToX, msg) result = newNodeI(nkCast, n.info) result.typ = targetType addSon(result, copyTree(n.sons[0])) diff --git a/compiler/seminst.nim b/compiler/seminst.nim index b5dca4c1bc..486065563d 100644 --- a/compiler/seminst.nim +++ b/compiler/seminst.nim @@ -88,7 +88,8 @@ proc sameInstantiation(a, b: TInstantiation): bool = if a.concreteTypes.len == b.concreteTypes.len: for i in 0..a.concreteTypes.high: if not compareTypes(a.concreteTypes[i], b.concreteTypes[i], - flags = {ExactTypeDescValues}): return + flags = {ExactTypeDescValues, + ExactGcSafety}): return result = true proc genericCacheGet(genericSym: PSym, entry: TInstantiation; diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim index 96bdc6cba2..c383f352fa 100644 --- a/compiler/sempass2.nim +++ b/compiler/sempass2.nim @@ -218,12 +218,11 @@ proc listGcUnsafety(s: PSym; onlyWarning: bool; cycleCheck: var IntSet) = message(s.info, msgKind, "'$#' is not GC-safe as it calls '$#'" % [s.name.s, u.name.s]) - of skParam: + of skParam, skForVar: message(s.info, msgKind, "'$#' is not GC-safe as it performs an indirect call via '$#'" % [s.name.s, u.name.s]) else: - internalAssert u.kind == skUnknown message(u.info, msgKind, "'$#' is not GC-safe as it performs an indirect call here" % s.name.s) diff --git a/compiler/semtypinst.nim b/compiler/semtypinst.nim index 80fb9168b5..037b075107 100644 --- a/compiler/semtypinst.nim +++ b/compiler/semtypinst.nim @@ -243,6 +243,7 @@ proc instCopyType*(cl: var TReplTypeVars, t: PType): PType = proc handleGenericInvocation(cl: var TReplTypeVars, t: PType): PType = # tyGenericInvocation[A, tyGenericInvocation[A, B]] # is difficult to handle: + const eqFlags = eqTypeFlags + {tfGcSafe} var body = t.sons[0] if body.kind != tyGenericBody: internalError(cl.info, "no generic body") var header: PType = t @@ -252,7 +253,7 @@ proc handleGenericInvocation(cl: var TReplTypeVars, t: PType): PType = else: result = searchInstTypes(t) - if result != nil and eqTypeFlags*result.flags == eqTypeFlags*t.flags: return + if result != nil and eqFlags*result.flags == eqFlags*t.flags: return for i in countup(1, sonsLen(t) - 1): var x = t.sons[i] if x.kind in {tyGenericParam}: @@ -267,7 +268,7 @@ proc handleGenericInvocation(cl: var TReplTypeVars, t: PType): PType = if header != t: # search again after first pass: result = searchInstTypes(header) - if result != nil and eqTypeFlags*result.flags == eqTypeFlags*t.flags: return + if result != nil and eqFlags*result.flags == eqFlags*t.flags: return else: header = instCopyType(cl, t) diff --git a/compiler/types.nim b/compiler/types.nim index 2886ac619a..13b24ccf80 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -139,6 +139,9 @@ proc getProcHeader*(sym: PSym; prefer: TPreferedDesc = preferName): string = add(result, ')') if n.sons[0].typ != nil: result.add(": " & typeToString(n.sons[0].typ, prefer)) + result.add "[declared in " + result.add($sym.info) + result.add "]" proc elemType*(t: PType): PType = assert(t != nil) @@ -688,6 +691,7 @@ type ExactTypeDescValues ExactGenericParams ExactConstraints + ExactGcSafety AllowCommonBase TTypeCmpFlags* = set[TTypeCmpFlag] @@ -976,6 +980,8 @@ proc sameTypeAux(x, y: PType, c: var TSameTypeClosure): bool = cycleCheck() if a.kind == tyUserTypeClass and a.n != nil: return a.n == b.n result = sameChildrenAux(a, b, c) and sameFlags(a, b) + if result and ExactGcSafety in c.flags: + result = a.flags * {tfThread} == b.flags * {tfThread} if result and a.kind == tyProc: result = ((IgnoreCC in c.flags) or a.callConv == b.callConv) and ((ExactConstraints notin c.flags) or sameConstraints(a.n, b.n)) diff --git a/koch.nim b/koch.nim index 743445094f..aaa03d5589 100644 --- a/koch.nim +++ b/koch.nim @@ -470,6 +470,17 @@ proc temp(args: string) = copyExe(output, finalDest) if programArgs.len > 0: exec(finalDest & " " & programArgs) +proc xtemp(cmd: string) = + let d = getAppDir() + copyExe(d / "bin" / "nim".exe, d / "bin" / "nim_backup".exe) + try: + withDir(d): + temp"-d:debug" + copyExe(d / "bin" / "nim_temp".exe, d / "bin" / "nim".exe) + exec(cmd) + finally: + copyExe(d / "bin" / "nim_backup".exe, d / "bin" / "nim".exe) + proc pushCsources() = if not dirExists("../csources/.git"): quit "[Error] no csources git repository found" @@ -545,6 +556,7 @@ of cmdArgument: of "testinstall": testUnixInstall() of "test", "tests": tests(op.cmdLineRest) of "temp": temp(op.cmdLineRest) + of "xtemp": xtemp(op.cmdLineRest) of "winrelease": winRelease() of "wintools": bundleWinTools() of "nimble": buildNimble(existsDir(".git")) diff --git a/lib/pure/asynchttpserver.nim b/lib/pure/asynchttpserver.nim index 8d059dbbc6..a374e80e89 100644 --- a/lib/pure/asynchttpserver.nim +++ b/lib/pure/asynchttpserver.nim @@ -127,7 +127,7 @@ proc parseProtocol(protocol: string): tuple[orig: string, major, minor: int] = i.inc protocol.parseInt(result.minor, i) proc sendStatus(client: AsyncSocket, status: string): Future[void] = - client.send("HTTP/1.1 " & status & "\c\L") + client.send("HTTP/1.1 " & status & "\c\L\c\L") proc processClient(client: AsyncSocket, address: string, callback: proc (request: Request): diff --git a/lib/pure/hashes.nim b/lib/pure/hashes.nim index e8c8776c63..b015ed3115 100644 --- a/lib/pure/hashes.nim +++ b/lib/pure/hashes.nim @@ -139,9 +139,14 @@ proc hash*(x: cstring): Hash = ## efficient hashing of null-terminated strings var h: Hash = 0 var i = 0 - while x[i] != 0.char: - h = h !& ord(x[i]) - inc i + when defined(js): + while i < x.len: + h = h !& ord(x[i]) + inc i + else: + while x[i] != 0.char: + h = h !& ord(x[i]) + inc i result = !$h proc hash*(sBuf: string, sPos, ePos: int): Hash = diff --git a/lib/pure/parseopt.nim b/lib/pure/parseopt.nim index 218f5ab814..23568edb91 100644 --- a/lib/pure/parseopt.nim +++ b/lib/pure/parseopt.nim @@ -149,26 +149,41 @@ proc cmdLineRest*(p: OptParser): TaintedString {.rtl, extern: "npo$1".} = ## retrieves the rest of the command line that has not been parsed yet. result = strip(substr(p.cmd, p.pos, len(p.cmd) - 1)).TaintedString +iterator getopt*(p: var OptParser): tuple[kind: CmdLineKind, key, val: TaintedString] = + ## This is an convenience iterator for iterating over the given OptParser object. + ## Example: + ## + ## .. code-block:: nim + ## var p = initOptParser("--left --debug:3 -l=4 -r:2") + ## for kind, key, val in p.getopt(): + ## case kind + ## of cmdArgument: + ## filename = key + ## of cmdLongOption, cmdShortOption: + ## case key + ## of "help", "h": writeHelp() + ## of "version", "v": writeVersion() + ## of cmdEnd: assert(false) # cannot happen + ## if filename == "": + ## # no filename has been given, so we show the help: + ## writeHelp() + p.pos = 0 + while true: + next(p) + if p.kind == cmdEnd: break + yield (p.kind, p.key, p.val) + when declared(initOptParser): iterator getopt*(): tuple[kind: CmdLineKind, key, val: TaintedString] = - ## This is an convenience iterator for iterating over the command line. - ## This uses the OptParser object. Example: + ## This is an convenience iterator for iterating over the command line arguments. + ## This create a new OptParser object. + ## See above for a more detailed example ## ## .. code-block:: nim - ## var - ## filename = "" ## for kind, key, val in getopt(): - ## case kind - ## of cmdArgument: - ## filename = key - ## of cmdLongOption, cmdShortOption: - ## case key - ## of "help", "h": writeHelp() - ## of "version", "v": writeVersion() - ## of cmdEnd: assert(false) # cannot happen - ## if filename == "": - ## # no filename has been given, so we show the help: - ## writeHelp() + ## # this will iterate over all arguments passed to the cmdline. + ## continue + ## var p = initOptParser() while true: next(p) diff --git a/lib/pure/parseopt2.nim b/lib/pure/parseopt2.nim index 7fd9c60fec..2e8dbe1402 100644 --- a/lib/pure/parseopt2.nim +++ b/lib/pure/parseopt2.nim @@ -123,26 +123,41 @@ type {.deprecated: [TGetoptResult: GetoptResult].} +iterator getopt*(p: var OptParser): GetoptResult = + ## This is an convenience iterator for iterating over the given OptParser object. + ## Example: + ## + ## .. code-block:: nim + ## var p = initOptParser("--left --debug:3 -l=4 -r:2") + ## for kind, key, val in p.getopt(): + ## case kind + ## of cmdArgument: + ## filename = key + ## of cmdLongOption, cmdShortOption: + ## case key + ## of "help", "h": writeHelp() + ## of "version", "v": writeVersion() + ## of cmdEnd: assert(false) # cannot happen + ## if filename == "": + ## # no filename has been given, so we show the help: + ## writeHelp() + p.pos = 0 + while true: + next(p) + if p.kind == cmdEnd: break + yield (p.kind, p.key, p.val) + when declared(paramCount): iterator getopt*(): GetoptResult = - ## This is an convenience iterator for iterating over the command line. - ## This uses the OptParser object. Example: + ## This is an convenience iterator for iterating over the command line arguments. + ## This create a new OptParser object. + ## See above for a more detailed example ## ## .. code-block:: nim - ## var - ## filename = "" ## for kind, key, val in getopt(): - ## case kind - ## of cmdArgument: - ## filename = key - ## of cmdLongOption, cmdShortOption: - ## case key - ## of "help", "h": writeHelp() - ## of "version", "v": writeVersion() - ## of cmdEnd: assert(false) # cannot happen - ## if filename == "": - ## # no filename has been given, so we show the help: - ## writeHelp() + ## # this will iterate over all arguments passed to the cmdline. + ## continue + ## var p = initOptParser() while true: next(p) diff --git a/lib/system/mmdisp.nim b/lib/system/mmdisp.nim index 431f84bfd4..5b5ba94908 100644 --- a/lib/system/mmdisp.nim +++ b/lib/system/mmdisp.nim @@ -255,12 +255,21 @@ elif defined(gogc): next_gc: uint64 # next GC (in heap_alloc time) last_gc: uint64 # last GC (in absolute time) pause_total_ns: uint64 - pause_ns: array[256, uint64] + pause_ns: array[256, uint64] # circular buffer of recent gc pause lengths + pause_end: array[256, uint64] # circular buffer of recent gc end times (nanoseconds since 1970) numgc: uint32 + numforcedgc: uint32 # number of user-forced GCs + gc_cpu_fraction: float64 # fraction of CPU time used by GC enablegc: cbool debuggc: cbool # Statistics about allocation size classes. by_size: array[goNumSizeClasses, goMStats_inner_struct] + # Statistics below here are not exported to MemStats directly. + tinyallocs: uint64 # number of tiny allocations that didn't cause actual allocation; not exported to go directly + gc_trigger: uint64 + heap_live: uint64 + heap_scan: uint64 + heap_marked: uint64 proc goRuntime_ReadMemStats(a2: ptr goMStats) {.cdecl, importc: "runtime_ReadMemStats", diff --git a/tests/generics/tproctypecache_falsepositive.nim b/tests/generics/tproctypecache_falsepositive.nim new file mode 100644 index 0000000000..4f24a1fc8f --- /dev/null +++ b/tests/generics/tproctypecache_falsepositive.nim @@ -0,0 +1,17 @@ + +import asyncdispatch + +type + Callback = proc() {.closure, gcsafe.} + GameState = ref object + playerChangeHandlers: seq[Callback] + +#proc dummy() = +# var x = newSeq[proc() {.cdecl, gcsafe.}]() + +proc newGameState(): GameState = + result = GameState( + playerChangeHandlers: newSeq[Callback]() # this fails + ) + +#dummy() diff --git a/tests/misc/tcast.nim b/tests/misc/tcast.nim new file mode 100644 index 0000000000..4e27040fb0 --- /dev/null +++ b/tests/misc/tcast.nim @@ -0,0 +1,23 @@ +discard """ + output: ''' +Hello World +Hello World''' +""" +type MyProc = proc() {.cdecl.} +type MyProc2 = proc() {.nimcall.} +type MyProc3 = proc() #{.closure.} is implicit + +proc testProc() = echo "Hello World" + +proc callPointer(p: pointer) = + # can cast to proc(){.cdecl.} + let ffunc0 = cast[MyProc](p) + # can cast to proc(){.nimcall.} + let ffunc1 = cast[MyProc2](p) + # cannot cast to proc(){.closure.} + doAssert(not compiles(cast[MyProc3](p))) + + ffunc0() + ffunc1() + +callPointer(cast[pointer](testProc)) diff --git a/tests/misc/tparseopt.nim b/tests/misc/tparseopt.nim new file mode 100644 index 0000000000..1f8375dfd1 --- /dev/null +++ b/tests/misc/tparseopt.nim @@ -0,0 +1,57 @@ +discard """ + file: "tparseopt.nim" + output: ''' +parseopt +first round +kind: cmdLongOption key:val -- left: +second round +kind: cmdLongOption key:val -- left: +kind: cmdLongOption key:val -- debug:3 +kind: cmdShortOption key:val -- l:4 +kind: cmdShortOption key:val -- r:2 +parseopt2 +first round +kind: cmdLongOption key:val -- left: +second round +kind: cmdLongOption key:val -- left: +kind: cmdLongOption key:val -- debug:3 +kind: cmdShortOption key:val -- l:4 +kind: cmdShortOption key:val -- r:2''' +""" +from parseopt import nil +from parseopt2 import nil + + +block: + echo "parseopt" + for kind, key, val in parseopt.getopt(): + echo "kind: ", kind, "\tkey:val -- ", key, ":", val + + # pass custom cmdline arguments + echo "first round" + var argv = "--left --debug:3 -l=4 -r:2" + var p = parseopt.initOptParser(argv) + for kind, key, val in parseopt.getopt(p): + echo "kind: ", kind, "\tkey:val -- ", key, ":", val + break + # reset getopt iterator and check arguments are returned correctly. + echo "second round" + for kind, key, val in parseopt.getopt(p): + echo "kind: ", kind, "\tkey:val -- ", key, ":", val + +block: + echo "parseopt2" + for kind, key, val in parseopt2.getopt(): + echo "kind: ", kind, "\tkey:val -- ", key, ":", val + + # pass custom cmdline arguments + echo "first round" + var argv: seq[string] = @["--left", "--debug:3", "-l=4", "-r:2"] + var p = parseopt2.initOptParser(argv) + for kind, key, val in parseopt2.getopt(p): + echo "kind: ", kind, "\tkey:val -- ", key, ":", val + break + # reset getopt iterator and check arguments are returned correctly. + echo "second round" + for kind, key, val in parseopt2.getopt(p): + echo "kind: ", kind, "\tkey:val -- ", key, ":", val diff --git a/tests/modules/tmismatchedvisibility.nim b/tests/modules/tmismatchedvisibility.nim index 325c729c05..91b639a278 100644 --- a/tests/modules/tmismatchedvisibility.nim +++ b/tests/modules/tmismatchedvisibility.nim @@ -1,6 +1,6 @@ discard """ line: 8 - errormsg: "public implementation 'tmismatchedvisibility.foo(a: int)' has non-public forward declaration in " + errormsg: "public implementation 'tmismatchedvisibility.foo(a: int)[declared in tmismatchedvisibility.nim(6,5)]' has non-public forward declaration in " """ proc foo(a: int): int diff --git a/tests/pragmas/tused.nim b/tests/pragmas/tused.nim index 4a317f8741..389863aef4 100644 --- a/tests/pragmas/tused.nim +++ b/tests/pragmas/tused.nim @@ -1,7 +1,7 @@ discard """ nimout: ''' compile start -tused.nim(15, 8) Hint: 'tused.echoSub(a: int, b: int)' is declared but not used [XDeclaredButNotUsed] +tused.nim(15, 8) Hint: 'tused.echoSub(a: int, b: int)[declared in tused.nim(15,7)]' is declared but not used [XDeclaredButNotUsed] compile end''' output: "8\n8" """