diff options
-rw-r--r-- | compiler/cgen.nim | 9 | ||||
-rw-r--r-- | compiler/extccomp.nim | 8 | ||||
-rw-r--r-- | compiler/sigmatch.nim | 5 | ||||
-rw-r--r-- | lib/pure/collections/tables.nim | 24 | ||||
-rw-r--r-- | lib/pure/math.nim | 3 | ||||
-rw-r--r-- | lib/pure/os.nim | 4 | ||||
-rw-r--r-- | lib/pure/osproc.nim | 24 | ||||
-rw-r--r-- | lib/system.nim | 19 | ||||
-rw-r--r-- | lib/system/arithm.nim | 8 | ||||
-rw-r--r-- | lib/system/chcks.nim | 6 | ||||
-rw-r--r-- | lib/windows/windows.nim | 79 | ||||
-rw-r--r-- | tests/collections/ttables.nim | 16 | ||||
-rw-r--r-- | tests/collections/ttablesref.nim | 18 | ||||
-rw-r--r-- | tests/manyloc/standalone/panicoverride.nim | 6 | ||||
-rw-r--r-- | tests/metatype/ttypedesc3.nim | 19 | ||||
-rw-r--r-- | tests/readme.txt | 5 | ||||
-rw-r--r-- | tests/realtimeGC/cmain.c | 67 | ||||
-rw-r--r-- | tests/realtimeGC/main.nim.cfg | 6 | ||||
-rw-r--r-- | tests/realtimeGC/nmain.nim | 46 | ||||
-rw-r--r-- | tests/realtimeGC/readme.txt | 21 | ||||
-rw-r--r-- | tests/realtimeGC/shared.nim | 63 | ||||
-rw-r--r-- | tests/realtimeGC/shared.nim.cfg | 5 | ||||
-rw-r--r-- | tests/testament/categories.nim | 14 | ||||
-rw-r--r-- | tests/testament/tester.nim | 35 |
24 files changed, 436 insertions, 74 deletions
diff --git a/compiler/cgen.nim b/compiler/cgen.nim index da9c6f653..4b0bac28a 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -676,8 +676,11 @@ proc genProcAux(m: BModule, prc: PSym) = closureSetup(p, prc) genStmts(p, prc.getBody) # modifies p.locals, p.init, etc. var generatedProc: Rope + if sfNoReturn in prc.flags: + if hasDeclspec in extccomp.CC[extccomp.cCompiler].props: + header = "__declspec(noreturn) " & header if sfPure in prc.flags: - if hasNakedDeclspec in extccomp.CC[extccomp.cCompiler].props: + if hasDeclspec in extccomp.CC[extccomp.cCompiler].props: header = "__declspec(naked) " & header generatedProc = rfmt(nil, "$N$1 {$n$2$3$4}$N$N", header, p.s(cpsLocals), p.s(cpsInit), p.s(cpsStmts)) @@ -720,8 +723,10 @@ proc genProcPrototype(m: BModule, sym: PSym) = var header = genProcHeader(m, sym) if sym.typ.callConv != ccInline and crossesCppBoundary(m, sym): header = "extern \"C\" " & header - if sfPure in sym.flags and hasNakedAttribute in CC[cCompiler].props: + if sfPure in sym.flags and hasAttribute in CC[cCompiler].props: header.add(" __attribute__((naked))") + if sfNoReturn in sym.flags and hasAttribute in CC[cCompiler].props: + header.add(" __attribute__((noreturn))") add(m.s[cfsProcHeaders], rfmt(nil, "$1;$n", header)) proc genProcNoForward(m: BModule, prc: PSym) = diff --git a/compiler/extccomp.nim b/compiler/extccomp.nim index 75cb1ef27..186a3884d 100644 --- a/compiler/extccomp.nim +++ b/compiler/extccomp.nim @@ -26,8 +26,8 @@ type hasAssume, # CC has __assume (Visual C extension) hasGcGuard, # CC supports GC_GUARD to keep stack roots hasGnuAsm, # CC's asm uses the absurd GNU assembler syntax - hasNakedDeclspec, # CC has __declspec(naked) - hasNakedAttribute # CC has __attribute__((naked)) + hasDeclspec, # CC has __declspec(X) + hasAttribute, # CC has __attribute__((X)) TInfoCCProps* = set[TInfoCCProp] TInfoCC* = tuple[ name: string, # the short name of the compiler @@ -85,7 +85,7 @@ compiler gcc: structStmtFmt: "$1 $3 $2 ", # struct|union [packed] $name packedPragma: "__attribute__((__packed__))", props: {hasSwitchRange, hasComputedGoto, hasCpp, hasGcGuard, hasGnuAsm, - hasNakedAttribute}) + hasAttribute}) # LLVM Frontend for GCC/G++ compiler llvmGcc: @@ -127,7 +127,7 @@ compiler vcc: asmStmtFrmt: "__asm{$n$1$n}$n", structStmtFmt: "$3$n$1 $2", packedPragma: "#pragma pack(1)", - props: {hasCpp, hasAssume, hasNakedDeclspec}) + props: {hasCpp, hasAssume, hasDeclspec}) # Intel C/C++ Compiler compiler icl: diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index 2a9d15b5a..7ea2c3d6f 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -1281,7 +1281,10 @@ proc paramTypesMatchAux(m: var TCandidate, f, argType: PType, result = implicitConv(nkHiddenStdConv, f, arg, m, c) of isSubtype: inc(m.subtypeMatches) - result = implicitConv(nkHiddenSubConv, f, arg, m, c) + if f.kind == tyTypeDesc: + result = arg + else: + result = implicitConv(nkHiddenSubConv, f, arg, m, c) of isSubrange: inc(m.subtypeMatches) if f.kind == tyVar: diff --git a/lib/pure/collections/tables.nim b/lib/pure/collections/tables.nim index a9357ce67..9496fa2fe 100644 --- a/lib/pure/collections/tables.nim +++ b/lib/pure/collections/tables.nim @@ -215,6 +215,10 @@ proc hasKey*[A, B](t: Table[A, B], key: A): bool = var hc: THash result = rawGet(t, key, hc) >= 0 +proc contains*[A, B](t: Table[A, B], key: A): bool = + ## alias of `hasKey` for use with the `in` operator. + return hasKey[A, B](t, key) + proc rawInsert[A, B](t: var Table[A, B], data: var KeyValuePairSeq[A, B], key: A, val: B, hc: THash, h: THash) = rawInsertImpl() @@ -411,6 +415,10 @@ proc hasKey*[A, B](t: TableRef[A, B], key: A): bool = ## returns true iff `key` is in the table `t`. result = t[].hasKey(key) +proc contains*[A, B](t: TableRef[A, B], key: A): bool = + ## alias of `hasKey` for use with the `in` operator. + return hasKey[A, B](t, key) + proc `[]=`*[A, B](t: TableRef[A, B], key: A, val: B) = ## puts a (key, value)-pair into `t`. t[][key] = val @@ -532,6 +540,10 @@ proc hasKey*[A, B](t: OrderedTable[A, B], key: A): bool = var hc: THash result = rawGet(t, key, hc) >= 0 +proc contains*[A, B](t: OrderedTable[A, B], key: A): bool = + ## alias of `hasKey` for use with the `in` operator. + return hasKey[A, B](t, key) + proc rawInsert[A, B](t: var OrderedTable[A, B], data: var OrderedKeyValuePairSeq[A, B], key: A, val: B, hc: THash, h: THash) = @@ -704,6 +716,10 @@ proc hasKey*[A, B](t: OrderedTableRef[A, B], key: A): bool = ## returns true iff `key` is in the table `t`. result = t[].hasKey(key) +proc contains*[A, B](t: OrderedTableRef[A, B], key: A): bool = + ## alias of `hasKey` for use with the `in` operator. + return hasKey[A, B](t, key) + proc `[]=`*[A, B](t: OrderedTableRef[A, B], key: A, val: B) = ## puts a (key, value)-pair into `t`. t[][key] = val @@ -804,6 +820,10 @@ proc hasKey*[A](t: CountTable[A], key: A): bool = ## returns true iff `key` is in the table `t`. result = rawGet(t, key) >= 0 +proc contains*[A](t: CountTable[A], key: A): bool = + ## alias of `hasKey` for use with the `in` operator. + return hasKey[A](t, key) + proc rawInsert[A](t: CountTable[A], data: var seq[tuple[key: A, val: int]], key: A, val: int) = var h: THash = hash(key) and high(data) @@ -945,6 +965,10 @@ proc hasKey*[A](t: CountTableRef[A], key: A): bool = ## returns true iff `key` is in the table `t`. result = t[].hasKey(key) +proc contains*[A](t: CountTableRef[A], key: A): bool = + ## alias of `hasKey` for use with the `in` operator. + return hasKey[A](t, key) + proc `[]=`*[A](t: CountTableRef[A], key: A, val: int) = ## puts a (key, value)-pair into `t`. `val` has to be positive. assert val > 0 diff --git a/lib/pure/math.nim b/lib/pure/math.nim index cb58ea39b..a9e9010f6 100644 --- a/lib/pure/math.nim +++ b/lib/pure/math.nim @@ -352,6 +352,9 @@ proc `^`*[T](x, y: T): T = proc gcd*[T](x, y: T): T = ## Computes the greatest common divisor of ``x`` and ``y``. + ## Note that for floats, the result cannot always be interpreted as + ## "greatest decimal `z` such that ``z*N == x and z*M == y`` + ## where N and M are positive integers." var (x,y) = (x,y) while y != 0: x = x mod y diff --git a/lib/pure/os.nim b/lib/pure/os.nim index f53abe81d..3a5bcbfa1 100644 --- a/lib/pure/os.nim +++ b/lib/pure/os.nim @@ -2033,10 +2033,10 @@ proc getFileInfo*(path: string, followSymlink = true): FileInfo = else: var rawInfo: TStat if followSymlink: - if lstat(path, rawInfo) < 0'i32: + if stat(path, rawInfo) < 0'i32: raiseOSError(osLastError()) else: - if stat(path, rawInfo) < 0'i32: + if lstat(path, rawInfo) < 0'i32: raiseOSError(osLastError()) rawToFormalFileInfo(rawInfo, result) diff --git a/lib/pure/osproc.nim b/lib/pure/osproc.nim index dce0673ba..8150f902a 100644 --- a/lib/pure/osproc.nim +++ b/lib/pure/osproc.nim @@ -195,43 +195,43 @@ proc peekExitCode*(p: Process): int {.tags: [].} proc inputStream*(p: Process): Stream {.rtl, extern: "nosp$1", tags: [].} ## returns ``p``'s input stream for writing to. ## - ## **Warning**: The returned `PStream` should not be closed manually as it - ## is closed when closing the PProcess ``p``. + ## **Warning**: The returned `Stream` should not be closed manually as it + ## is closed when closing the Process ``p``. proc outputStream*(p: Process): Stream {.rtl, extern: "nosp$1", tags: [].} ## returns ``p``'s output stream for reading from. ## - ## **Warning**: The returned `PStream` should not be closed manually as it - ## is closed when closing the PProcess ``p``. + ## **Warning**: The returned `Stream` should not be closed manually as it + ## is closed when closing the Process ``p``. proc errorStream*(p: Process): Stream {.rtl, extern: "nosp$1", tags: [].} ## returns ``p``'s error stream for reading from. ## - ## **Warning**: The returned `PStream` should not be closed manually as it - ## is closed when closing the PProcess ``p``. + ## **Warning**: The returned `Stream` should not be closed manually as it + ## is closed when closing the Process ``p``. proc inputHandle*(p: Process): FileHandle {.rtl, extern: "nosp$1", tags: [].} = ## returns ``p``'s input file handle for writing to. ## - ## **Warning**: The returned `TFileHandle` should not be closed manually as - ## it is closed when closing the PProcess ``p``. + ## **Warning**: The returned `FileHandle` should not be closed manually as + ## it is closed when closing the Process ``p``. result = p.inHandle proc outputHandle*(p: Process): FileHandle {.rtl, extern: "nosp$1", tags: [].} = ## returns ``p``'s output file handle for reading from. ## - ## **Warning**: The returned `TFileHandle` should not be closed manually as - ## it is closed when closing the PProcess ``p``. + ## **Warning**: The returned `FileHandle` should not be closed manually as + ## it is closed when closing the Process ``p``. result = p.outHandle proc errorHandle*(p: Process): FileHandle {.rtl, extern: "nosp$1", tags: [].} = ## returns ``p``'s error file handle for reading from. ## - ## **Warning**: The returned `TFileHandle` should not be closed manually as - ## it is closed when closing the PProcess ``p``. + ## **Warning**: The returned `FileHandle` should not be closed manually as + ## it is closed when closing the Process ``p``. result = p.errHandle proc countProcessors*(): int {.rtl, extern: "nosp$1".} = diff --git a/lib/system.nim b/lib/system.nim index ca4c81411..1e6f76f3d 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -1110,7 +1110,7 @@ var programResult* {.exportc: "nim_program_result".}: int ## prematurely using ``quit``, this value is ignored. proc quit*(errorcode: int = QuitSuccess) {. - magic: "Exit", importc: "exit", header: "<stdlib.h>", noReturn.} + magic: "Exit", importc: "exit", header: "<stdlib.h>", noreturn.} ## Stops the program immediately with an exit code. ## ## Before stopping the program the "quit procedures" are called in the @@ -2270,20 +2270,21 @@ when hostOS == "standalone": include panicoverride when not declared(sysFatal): - template sysFatal(exceptn: typedesc, message: string) = - when hostOS == "standalone": + when hostOS == "standalone": + proc sysFatal(exceptn: typedesc, message: string) {.inline.} = panic(message) - else: + + proc sysFatal(exceptn: typedesc, message, arg: string) {.inline.} = + rawoutput(message) + panic(arg) + else: + proc sysFatal(exceptn: typedesc, message: string) {.inline, noReturn.} = var e: ref exceptn new(e) e.msg = message raise e - template sysFatal(exceptn: typedesc, message, arg: string) = - when hostOS == "standalone": - rawoutput(message) - panic(arg) - else: + proc sysFatal(exceptn: typedesc, message, arg: string) {.inline, noReturn.} = var e: ref exceptn new(e) e.msg = message & arg diff --git a/lib/system/arithm.nim b/lib/system/arithm.nim index f68e2dcd9..ef153417c 100644 --- a/lib/system/arithm.nim +++ b/lib/system/arithm.nim @@ -10,11 +10,11 @@ # simple integer arithmetic with overflow checking -proc raiseOverflow {.compilerproc, noinline, noreturn.} = +proc raiseOverflow {.compilerproc, noinline.} = # a single proc to reduce code size to a minimum sysFatal(OverflowError, "over- or underflow") -proc raiseDivByZero {.compilerproc, noinline, noreturn.} = +proc raiseDivByZero {.compilerproc, noinline.} = sysFatal(DivByZeroError, "division by zero") proc addInt64(a, b: int64): int64 {.compilerProc, inline.} = @@ -327,13 +327,13 @@ when not declared(mulInt): # We avoid setting the FPU control word here for compatibility with libraries # written in other languages. -proc raiseFloatInvalidOp {.noinline, noreturn.} = +proc raiseFloatInvalidOp {.noinline.} = sysFatal(FloatInvalidOpError, "FPU operation caused a NaN result") proc nanCheck(x: float64) {.compilerProc, inline.} = if x != x: raiseFloatInvalidOp() -proc raiseFloatOverflow(x: float64) {.noinline, noreturn.} = +proc raiseFloatOverflow(x: float64) {.noinline.} = if x > 0.0: sysFatal(FloatOverflowError, "FPU operation caused an overflow") else: diff --git a/lib/system/chcks.nim b/lib/system/chcks.nim index 2f6d25a12..6caf99d27 100644 --- a/lib/system/chcks.nim +++ b/lib/system/chcks.nim @@ -9,16 +9,16 @@ # Implementation of some runtime checks. -proc raiseRangeError(val: BiggestInt) {.compilerproc, noreturn, noinline.} = +proc raiseRangeError(val: BiggestInt) {.compilerproc, noinline.} = when hostOS == "standalone": sysFatal(RangeError, "value out of range") else: sysFatal(RangeError, "value out of range: ", $val) -proc raiseIndexError() {.compilerproc, noreturn, noinline.} = +proc raiseIndexError() {.compilerproc, noinline.} = sysFatal(IndexError, "index out of bounds") -proc raiseFieldError(f: string) {.compilerproc, noreturn, noinline.} = +proc raiseFieldError(f: string) {.compilerproc, noinline.} = sysFatal(FieldError, f, " is not accessible") proc chckIndx(i, a, b: int): int = diff --git a/lib/windows/windows.nim b/lib/windows/windows.nim index b76dea6c5..02c87132a 100644 --- a/lib/windows/windows.nim +++ b/lib/windows/windows.nim @@ -18513,11 +18513,15 @@ proc DisableThreadLibraryCalls*(hLibModule: HMODULE): WINBOOL{.stdcall, proc GetProcAddress*(hModule: HINST, lpProcName: LPCSTR): FARPROC{.stdcall, dynlib: "kernel32", importc: "GetProcAddress".} proc GetVersion*(): DWORD{.stdcall, dynlib: "kernel32", importc: "GetVersion".} -proc GlobalAlloc*(uFlags: int32, dwBytes: DWORD): HGLOBAL{.stdcall, +proc GlobalAlloc*(uFlags: int32, dwBytes: SIZE_T): HGLOBAL{.stdcall, dynlib: "kernel32", importc: "GlobalAlloc".} -proc GlobalReAlloc*(hMem: HGLOBAL, dwBytes: DWORD, uFlags: int32): HGLOBAL{. +proc GlobalAlloc*(uFlags: int32, dwBytes: DWORD): HGLOBAL{.stdcall, + dynlib: "kernel32", importc: "GlobalAlloc", deprecated.} +proc GlobalReAlloc*(hMem: HGLOBAL, dwBytes: SIZE_T, uFlags: int32): HGLOBAL{. stdcall, dynlib: "kernel32", importc: "GlobalReAlloc".} -proc GlobalSize*(hMem: HGLOBAL): DWORD{.stdcall, dynlib: "kernel32", +proc GlobalReAlloc*(hMem: HGLOBAL, dwBytes: DWORD, uFlags: int32): HGLOBAL{. + stdcall, dynlib: "kernel32", importc: "GlobalReAlloc", deprecated.} +proc GlobalSize*(hMem: HGLOBAL): SIZE_T{.stdcall, dynlib: "kernel32", importc: "GlobalSize".} proc GlobalFlags*(hMem: HGLOBAL): WINUINT{.stdcall, dynlib: "kernel32", importc: "GlobalFlags".} @@ -18541,10 +18545,14 @@ proc GlobalUnWire*(hMem: HGLOBAL): WINBOOL{.stdcall, dynlib: "kernel32", importc: "GlobalUnWire".} proc GlobalMemoryStatus*(lpBuffer: LPMEMORYSTATUS){.stdcall, dynlib: "kernel32", importc: "GlobalMemoryStatus".} -proc LocalAlloc*(uFlags: WINUINT, uBytes: WINUINT): HLOCAL{.stdcall, +proc LocalAlloc*(uFlags: WINUINT, uBytes: SIZE_T): HLOCAL{.stdcall, dynlib: "kernel32", importc: "LocalAlloc".} -proc LocalReAlloc*(hMem: HLOCAL, uBytes: WINUINT, uFlags: WINUINT): HLOCAL{.stdcall, +proc LocalAlloc*(uFlags: WINUINT, uBytes: DWORD): HLOCAL{.stdcall, + dynlib: "kernel32", importc: "LocalAlloc", deprecated.} +proc LocalReAlloc*(hMem: HLOCAL, uBytes: SIZE_T, uFlags: WINUINT): HLOCAL{.stdcall, dynlib: "kernel32", importc: "LocalReAlloc".} +proc LocalReAlloc*(hMem: HLOCAL, uBytes: DWORD, uFlags: WINUINT): HLOCAL{.stdcall, + dynlib: "kernel32", importc: "LocalReAlloc", deprecated.} proc LocalLock*(hMem: HLOCAL): LPVOID{.stdcall, dynlib: "kernel32", importc: "LocalLock".} proc LocalHandle*(pMem: LPCVOID): HLOCAL{.stdcall, dynlib: "kernel32", @@ -18564,38 +18572,71 @@ proc LocalCompact*(uMinFree: WINUINT): WINUINT{.stdcall, dynlib: "kernel32", proc FlushInstructionCache*(hProcess: HANDLE, lpBaseAddress: LPCVOID, dwSize: DWORD): WINBOOL{.stdcall, dynlib: "kernel32", importc: "FlushInstructionCache".} -proc VirtualAlloc*(lpAddress: LPVOID, dwSize: DWORD, flAllocationType: DWORD, +proc VirtualAlloc*(lpAddress: LPVOID, dwSize: SIZE_T, flAllocationType: DWORD, flProtect: DWORD): LPVOID{.stdcall, dynlib: "kernel32", importc: "VirtualAlloc".} -proc VirtualFree*(lpAddress: LPVOID, dwSize: DWORD, dwFreeType: DWORD): WINBOOL{. +proc VirtualAlloc*(lpAddress: LPVOID, dwSize: DWORD, flAllocationType: DWORD, + flProtect: DWORD): LPVOID{.stdcall, dynlib: "kernel32", + importc: "VirtualAlloc", deprecated.} +proc VirtualAllocEx*(hProcess: HANDLE, lpAddress: LPVOID, dwSize: SIZE_T, + flAllocationType: DWORD, flProtect: DWORD): LPVOID + {.stdcall, dynlib: "kernel32", importc: "VirtualAllocEx".} +proc VirtualAllocEx*(hProcess: HANDLE, lpAddress: LPVOID, dwSize: DWORD, + flAllocationType: DWORD, flProtect: DWORD): LPVOID + {.stdcall, dynlib: "kernel32", importc: "VirtualAllocEx", + deprecated.} +proc VirtualFree*(lpAddress: LPVOID, dwSize: SIZE_T, dwFreeType: DWORD): WINBOOL{. stdcall, dynlib: "kernel32", importc: "VirtualFree".} -proc VirtualProtect*(lpAddress: LPVOID, dwSize: DWORD, flNewProtect: DWORD, +proc VirtualFree*(lpAddress: LPVOID, dwSize: DWORD, dwFreeType: DWORD): WINBOOL{. + stdcall, dynlib: "kernel32", importc: "VirtualFree", deprecated.} +proc VirtualFreeEx*(hProcess: HANDLE, lpAddress: LPVOID, dwSize: SIZE_T, + dwFreeType: DWORD): WINBOOL + {.stdcall, dynlib: "kernel32", importc: "VirtualFree".} +proc VirtualFreeEx*(hProcess: HANDLE, lpAddress: LPVOID, dwSize: DWORD, + dwFreeType: DWORD): WINBOOL + {.stdcall, dynlib: "kernel32", importc: "VirtualFree".} +proc VirtualProtect*(lpAddress: LPVOID, dwSize: SIZE_T, flNewProtect: DWORD, lpflOldProtect: PDWORD): WINBOOL{.stdcall, dynlib: "kernel32", importc: "VirtualProtect".} +proc VirtualProtect*(lpAddress: LPVOID, dwSize: DWORD, flNewProtect: DWORD, + lpflOldProtect: PDWORD): WINBOOL{.stdcall, + dynlib: "kernel32", importc: "VirtualProtect", deprecated.} proc VirtualQuery*(lpAddress: LPCVOID, lpBuffer: PMEMORY_BASIC_INFORMATION, dwLength: DWORD): DWORD{.stdcall, dynlib: "kernel32", importc: "VirtualQuery".} -proc VirtualProtectEx*(hProcess: HANDLE, lpAddress: LPVOID, dwSize: DWORD, +proc VirtualProtectEx*(hProcess: HANDLE, lpAddress: LPVOID, dwSize: SIZE_T, flNewProtect: DWORD, lpflOldProtect: PDWORD): WINBOOL{. stdcall, dynlib: "kernel32", importc: "VirtualProtectEx".} +proc VirtualProtectEx*(hProcess: HANDLE, lpAddress: LPVOID, dwSize: DWORD, + flNewProtect: DWORD, lpflOldProtect: PDWORD): WINBOOL{. + stdcall, dynlib: "kernel32", importc: "VirtualProtectEx", deprecated.} proc VirtualQueryEx*(hProcess: HANDLE, lpAddress: LPCVOID, - lpBuffer: PMEMORY_BASIC_INFORMATION, dwLength: DWORD): DWORD{. + lpBuffer: PMEMORY_BASIC_INFORMATION, dwLength: SIZE_T): DWORD{. stdcall, dynlib: "kernel32", importc: "VirtualQueryEx".} -proc HeapCreate*(flOptions: DWORD, dwInitialSize: DWORD, dwMaximumSize: DWORD): HANDLE{. +proc VirtualQueryEx*(hProcess: HANDLE, lpAddress: LPCVOID, + lpBuffer: PMEMORY_BASIC_INFORMATION, dwLength: DWORD): DWORD{. + stdcall, dynlib: "kernel32", importc: "VirtualQueryEx", deprecated.} +proc HeapCreate*(flOptions: DWORD, dwInitialSize: SIZE_T, dwMaximumSize: SIZE_T): HANDLE{. stdcall, dynlib: "kernel32", importc: "HeapCreate".} +proc HeapCreate*(flOptions: DWORD, dwInitialSize: DWORD, dwMaximumSize: DWORD): HANDLE{. + stdcall, dynlib: "kernel32", importc: "HeapCreate", deprecated.} proc HeapDestroy*(hHeap: HANDLE): WINBOOL{.stdcall, dynlib: "kernel32", importc: "HeapDestroy".} -proc HeapAlloc*(hHeap: HANDLE, dwFlags: DWORD, dwBytes: DWORD): LPVOID{.stdcall, +proc HeapAlloc*(hHeap: HANDLE, dwFlags: DWORD, dwBytes: SIZE_T): LPVOID{.stdcall, dynlib: "kernel32", importc: "HeapAlloc".} -proc HeapReAlloc*(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID, dwBytes: DWORD): LPVOID{. +proc HeapAlloc*(hHeap: HANDLE, dwFlags: DWORD, dwBytes: DWORD): LPVOID{.stdcall, + dynlib: "kernel32", importc: "HeapAlloc", deprecated.} +proc HeapReAlloc*(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID, dwBytes: SIZE_T): LPVOID{. stdcall, dynlib: "kernel32", importc: "HeapReAlloc".} +proc HeapReAlloc*(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID, dwBytes: DWORD): LPVOID{. + stdcall, dynlib: "kernel32", importc: "HeapReAlloc", deprecated.} proc HeapFree*(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID): WINBOOL{.stdcall, dynlib: "kernel32", importc: "HeapFree".} -proc HeapSize*(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPCVOID): DWORD{.stdcall, +proc HeapSize*(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPCVOID): SIZE_T{.stdcall, dynlib: "kernel32", importc: "HeapSize".} proc HeapValidate*(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPCVOID): WINBOOL{. stdcall, dynlib: "kernel32", importc: "HeapValidate".} -proc HeapCompact*(hHeap: HANDLE, dwFlags: DWORD): WINUINT{.stdcall, +proc HeapCompact*(hHeap: HANDLE, dwFlags: DWORD): SIZE_T{.stdcall, dynlib: "kernel32", importc: "HeapCompact".} proc GetProcessHeap*(): HANDLE{.stdcall, dynlib: "kernel32", importc: "GetProcessHeap".} @@ -19221,10 +19262,14 @@ proc FindNextChangeNotification*(hChangeHandle: HANDLE): WINBOOL{.stdcall, dynlib: "kernel32", importc: "FindNextChangeNotification".} proc FindCloseChangeNotification*(hChangeHandle: HANDLE): WINBOOL{.stdcall, dynlib: "kernel32", importc: "FindCloseChangeNotification".} -proc VirtualLock*(lpAddress: LPVOID, dwSize: DWORD): WINBOOL{.stdcall, +proc VirtualLock*(lpAddress: LPVOID, dwSize: SIZE_T): WINBOOL{.stdcall, dynlib: "kernel32", importc: "VirtualLock".} -proc VirtualUnlock*(lpAddress: LPVOID, dwSize: DWORD): WINBOOL{.stdcall, +proc VirtualLock*(lpAddress: LPVOID, dwSize: DWORD): WINBOOL{.stdcall, + dynlib: "kernel32", importc: "VirtualLock", deprecated.} +proc VirtualUnlock*(lpAddress: LPVOID, dwSize: SIZE_T): WINBOOL{.stdcall, dynlib: "kernel32", importc: "VirtualUnlock".} +proc VirtualUnlock*(lpAddress: LPVOID, dwSize: DWORD): WINBOOL{.stdcall, + dynlib: "kernel32", importc: "VirtualUnlock", deprecated.} proc MapViewOfFileEx*(hFileMappingObject: HANDLE, dwDesiredAccess: DWORD, dwFileOffsetHigh: DWORD, dwFileOffsetLow: DWORD, dwNumberOfBytesToMap: DWORD, lpBaseAddress: LPVOID): LPVOID{. diff --git a/tests/collections/ttables.nim b/tests/collections/ttables.nim index 3a923610e..a10606843 100644 --- a/tests/collections/ttables.nim +++ b/tests/collections/ttables.nim @@ -22,15 +22,15 @@ const "---00": 346677844, "0": 34404, "1": 344004, - "10": 34484, + "10": 34484, "11": 34474, "12": 789, "19": 34464, - "2": 344774, "20": 34454, + "2": 344774, "20": 34454, "3": 342244, "30": 34141244, "34": 123456, "4": 3412344, "40": 344114, - "5": 341232144, "50": 344490, + "5": 341232144, "50": 344490, "6": 34214544, "60": 344491, "7": 3434544, "70": 344492, "8": 344544, "80": 344497, @@ -46,7 +46,7 @@ block tableTest1: for x in 0..1: for y in 0..1: assert t[(x,y)] == $x & $y - assert($t == + assert($t == "{(x: 0, y: 1): 01, (x: 0, y: 0): 00, (x: 1, y: 0): 10, (x: 1, y: 1): 11}") block tableTest2: @@ -55,14 +55,16 @@ block tableTest2: t["111"] = 1.000043 t["123"] = 1.23 t.del("111") - + t["012"] = 67.9 t["123"] = 1.5 # test overwriting - + assert t["123"] == 1.5 assert t["111"] == 0.0 # deleted assert(not hasKey(t, "111")) - + assert "123" in t + assert("111" notin t) + for key, val in items(data): t[key] = val.toFloat for key, val in items(data): assert t[key] == val.toFloat diff --git a/tests/collections/ttablesref.nim b/tests/collections/ttablesref.nim index 16b0d831e..0b641ebc7 100644 --- a/tests/collections/ttablesref.nim +++ b/tests/collections/ttablesref.nim @@ -22,15 +22,15 @@ const "---00": 346677844, "0": 34404, "1": 344004, - "10": 34484, + "10": 34484, "11": 34474, "12": 789, "19": 34464, - "2": 344774, "20": 34454, + "2": 344774, "20": 34454, "3": 342244, "30": 34141244, "34": 123456, "4": 3412344, "40": 344114, - "5": 341232144, "50": 344490, + "5": 341232144, "50": 344490, "6": 34214544, "60": 344491, "7": 3434544, "70": 344492, "8": 344544, "80": 344497, @@ -46,7 +46,7 @@ block tableTest1: for x in 0..1: for y in 0..1: assert t[(x,y)] == $x & $y - assert($t == + assert($t == "{(x: 0, y: 1): 01, (x: 0, y: 0): 00, (x: 1, y: 0): 10, (x: 1, y: 1): 11}") block tableTest2: @@ -55,17 +55,19 @@ block tableTest2: t["111"] = 1.000043 t["123"] = 1.23 t.del("111") - + t["012"] = 67.9 t["123"] = 1.5 # test overwriting - + assert t["123"] == 1.5 assert t["111"] == 0.0 # deleted + assert "123" in t assert(not hasKey(t, "111")) - + assert "111" notin t + for key, val in items(data): t[key] = val.toFloat for key, val in items(data): assert t[key] == val.toFloat - + block orderedTableTest1: var t = newOrderedTable[string, int](2) diff --git a/tests/manyloc/standalone/panicoverride.nim b/tests/manyloc/standalone/panicoverride.nim index efd2b21f9..d9b3f4388 100644 --- a/tests/manyloc/standalone/panicoverride.nim +++ b/tests/manyloc/standalone/panicoverride.nim @@ -7,13 +7,13 @@ proc exit(code: int) {.importc, header: "<stdlib.h>", cdecl.} proc rawoutput(s: string) = printf("%s\n", s) -proc panic(s: string) = +proc panic(s: string) {.noreturn.} = rawoutput(s) exit(1) # Alternatively we also could implement these 2 here: # -# template sysFatal(exceptn: typeDesc, message: string) -# template sysFatal(exceptn: typeDesc, message, arg: string) +# proc sysFatal(exceptn: typeDesc, message: string) {.noReturn.} +# proc sysFatal(exceptn: typeDesc, message, arg: string) {.noReturn.} {.pop.} diff --git a/tests/metatype/ttypedesc3.nim b/tests/metatype/ttypedesc3.nim new file mode 100644 index 000000000..3d40b25b2 --- /dev/null +++ b/tests/metatype/ttypedesc3.nim @@ -0,0 +1,19 @@ +import typetraits + +type + Base = object of RootObj + Child = object of Base + +proc pr(T: typedesc[Base]) = echo "proc " & T.name +method me(T: typedesc[Base]) = echo "method " & T.name +iterator it(T: typedesc[Base]) = yield "yield " & T.name + +Base.pr +Child.pr + +Base.me +when false: + Child.me #<- bug #2710 + +for s in Base.it: echo s +for s in Child.it: echo s #<- bug #2662 diff --git a/tests/readme.txt b/tests/readme.txt index 0d33a81c7..2cfc79f9a 100644 --- a/tests/readme.txt +++ b/tests/readme.txt @@ -3,8 +3,11 @@ Each test must have a filename of the form: ``t*.nim`` Each test can contain a spec in a ``discard """"""`` block. -The folder ``rodfiles`` contains special tests that test incremental +The folder ``rodfiles`` contains special tests that test incremental compilation via symbol files. The folder ``dll`` contains simple DLL tests. +The folder ``realtimeGC`` contains a test for validating that the realtime GC +can run properly without linking against the nimrtl.dll/so. It includes a C +client and platform specific build files for manual compilation. diff --git a/tests/realtimeGC/cmain.c b/tests/realtimeGC/cmain.c new file mode 100644 index 000000000..e9a46d7ce --- /dev/null +++ b/tests/realtimeGC/cmain.c @@ -0,0 +1,67 @@ + +#ifdef WIN +#include <windows.h> +#else +#include <dlfcn.h> +#endif +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> +#include <time.h> + +#define RUNTIME (15*60) + + +typedef void (*pFunc)(void); + +int main(int argc, char* argv[]) +{ + int i; + void* hndl; + pFunc status; + pFunc count; + pFunc checkOccupiedMem; + +#ifdef WIN + hndl = (void*) LoadLibrary((char const*)"./tests/realtimeGC/shared.dll"); + status = (pFunc)GetProcAddress((HMODULE) hndl, (char const*)"status"); + count = (pFunc)GetProcAddress((HMODULE) hndl, (char const*)"count"); + checkOccupiedMem = (pFunc)GetProcAddress((HMODULE) hndl, (char const*)"checkOccupiedMem"); +#else /* OSX || NIX */ + hndl = (void*) dlopen((char const*)"./tests/realtimeGC/libshared.so", RTLD_LAZY); + status = (pFunc) dlsym(hndl, (char const*)"status"); + count = (pFunc) dlsym(hndl, (char const*)"count"); + checkOccupiedMem = (pFunc) dlsym(hndl, (char const*)"checkOccupiedMem"); +#endif + + assert(hndl); + assert(status); + assert(count); + assert(checkOccupiedMem); + + time_t startTime = time((time_t*)0); + time_t runTime = (time_t)(RUNTIME); + time_t accumTime = 0; + while (accumTime < runTime) { + for (i = 0; i < 10; i++) + count(); + /* printf("1. sleeping...\n"); */ + sleep(1); + for (i = 0; i < 10; i++) + status(); + /* printf("2. sleeping...\n"); */ + sleep(1); + checkOccupiedMem(); + accumTime = time((time_t*)0) - startTime; + /* printf("--- Minutes left to run: %d\n", (int)(runTime-accumTime)/60); */ + } + printf("Cleaning up the shared object pointer...\n"); +#ifdef WIN + FreeLibrary((HMODULE)hndl); +#else /* OSX || NIX */ + dlclose(hndl); +#endif + printf("Done\n"); + return 0; +} diff --git a/tests/realtimeGC/main.nim.cfg b/tests/realtimeGC/main.nim.cfg new file mode 100644 index 000000000..fed4fa471 --- /dev/null +++ b/tests/realtimeGC/main.nim.cfg @@ -0,0 +1,6 @@ + +--app:console +--threads:on + +-d:release +-d:useRealtimeGC diff --git a/tests/realtimeGC/nmain.nim b/tests/realtimeGC/nmain.nim new file mode 100644 index 000000000..c9f558dbc --- /dev/null +++ b/tests/realtimeGC/nmain.nim @@ -0,0 +1,46 @@ +discard """ + cmd: "nim $target --debuginfo $options $file" + output: "Done" +""" + +import times, os, threadpool + +const RUNTIME = 15 * 60 # 15 minutes + +when defined(windows): + const dllname = "./tests/realtimeGC/shared.dll" +elif defined(macosx): + const dllname = "./tests/realtimeGC/libshared.dylib" +else: + const dllname = "./tests/realtimeGC/libshared.so" + +proc status() {.importc: "status", dynlib: dllname.} +proc count() {.importc: "count", dynlib: dllname.} +proc checkOccupiedMem() {.importc: "checkOccupiedMem", dynlib: dllname.} + +proc process() = + let startTime = getTime() + let runTime = cast[Time](RUNTIME) # + var accumTime: Time + while accumTime < runTime: + for i in 0..10: + count() + # echo("1. sleeping... ") + sleep(500) + for i in 0..10: + status() + # echo("2. sleeping... ") + sleep(500) + checkOccupiedMem() + accumTime = cast[Time]((getTime() - startTime)) + # echo("--- Minutes left to run: ", int(int(runTime-accumTime)/60)) + +proc main() = + process() + # parallel: + # for i in 0..0: + # spawn process() + # sync() + echo("Done") + +main() diff --git a/tests/realtimeGC/readme.txt b/tests/realtimeGC/readme.txt new file mode 100644 index 000000000..035a00001 --- /dev/null +++ b/tests/realtimeGC/readme.txt @@ -0,0 +1,21 @@ +Test the realtime GC without linking nimrtl.dll/so. + +Note, this is a long running test, default is 35 minutes. To change the +the run time see RUNTIME in main.nim and main.c. + +You can build shared.nim, main.nim, and main.c by running make (nix systems) +or maike.bat (Windows systems). They both assume GCC and that it's in your +path. Output: shared.(dll/so), camin(.exe), nmain(.exe). + +To run the test: execute either nmain or cmain in a shell window. + +To build buy hand: + + - build the shared object (shared.nim): + + $ nim c shared.nim + + - build the client executables: + + $ nim c -o:nmain main.nim + $ gcc -o cmain main.c -ldl diff --git a/tests/realtimeGC/shared.nim b/tests/realtimeGC/shared.nim new file mode 100644 index 000000000..2d1dd6c3c --- /dev/null +++ b/tests/realtimeGC/shared.nim @@ -0,0 +1,63 @@ +discard """ + cmd: "nim $target --debuginfo --hints:on --app:lib $options $file" +""" + +import strutils + +# Global state, accessing with threads, no locks. Don't do this at +# home. +var gCounter: uint64 +var gTxStatus: bool +var gRxStatus: bool +var gConnectStatus: bool +var gPttStatus: bool +var gComm1Status: bool +var gComm2Status: bool + +proc getTxStatus(): string = + result = if gTxStatus: "On" else: "Off" + gTxStatus = not gTxStatus + +proc getRxStatus(): string = + result = if gRxStatus: "On" else: "Off" + gRxStatus = not gRxStatus + +proc getConnectStatus(): string = + result = if gConnectStatus: "Yes" else: "No" + gConnectStatus = not gConnectStatus + +proc getPttStatus(): string = + result = if gPttStatus: "PTT: On" else: "PTT: Off" + gPttStatus = not gPttStatus + +proc getComm1Status(): string = + result = if gComm1Status: "On" else: "Off" + gComm1Status = not gComm1Status + +proc getComm2Status(): string = + result = if gComm2Status: "On" else: "Off" + gComm2Status = not gComm2Status + +proc status() {.exportc: "status", dynlib.} = + var tx_status = getTxStatus() + var rx_status = getRxStatus() + var connected = getConnectStatus() + var ptt_status = getPttStatus() + var str1: string = "[PilotEdge] Connected: $1 TX: $2 RX: $3" % [connected, tx_status, rx_status] + var a = getComm1Status() + var b = getComm2Status() + var str2: string = "$1 COM1: $2 COM2: $3" % [ptt_status, a, b] + # echo(str1) + # echo(str2) + +proc count() {.exportc: "count", dynlib.} = + var temp: uint64 + for i in 0..100_000: + temp += 1 + gCounter += 1 + # echo("gCounter: ", gCounter) + +proc checkOccupiedMem() {.exportc: "checkOccupiedMem", dynlib.} = + if getOccupiedMem() > 10_000_000: + quit 1 + discard diff --git a/tests/realtimeGC/shared.nim.cfg b/tests/realtimeGC/shared.nim.cfg new file mode 100644 index 000000000..e153b26fa --- /dev/null +++ b/tests/realtimeGC/shared.nim.cfg @@ -0,0 +1,5 @@ +--app:lib +--threads:on + +-d:release +-d:useRealtimeGC diff --git a/tests/testament/categories.nim b/tests/testament/categories.nim index 07a2421a6..4de1edeee 100644 --- a/tests/testament/categories.nim +++ b/tests/testament/categories.nim @@ -138,6 +138,18 @@ proc gcTests(r: var TResults, cat: Category, options: string) = test "stackrefleak" test "cyclecollector" +proc longGCTests(r: var TResults, cat: Category, options: string) = + when defined(windows): + let cOptions = "gcc -ldl -DWIN" + else: + let cOptions = "gcc -ldl" + + var c = initResults() + # According to ioTests, this should compile the file + testNoSpec c, makeTest("tests/realtimeGC/shared", options, cat, actionCompile) + testC r, makeTest("tests/realtimeGC/cmain", cOptions, cat, actionRun) + testSpec r, makeTest("tests/realtimeGC/nmain", options & "--threads: on", cat, actionRun) + # ------------------------- threading tests ----------------------------------- proc threadTests(r: var TResults, cat: Category, options: string) = @@ -340,6 +352,8 @@ proc processCategory(r: var TResults, cat: Category, options: string) = dllTests(r, cat, options) of "gc": gcTests(r, cat, options) + of "longgc": + longGCTests(r, cat, options) of "debugger": debuggerTests(r, cat, options) of "manyloc": diff --git a/tests/testament/tester.nim b/tests/testament/tester.nim index b3e65959a..0308ce940 100644 --- a/tests/testament/tester.nim +++ b/tests/testament/tester.nim @@ -89,6 +89,25 @@ proc callCompiler(cmdTemplate, filename, options: string, elif suc =~ pegSuccess: result.err = reSuccess +proc callCCompiler(cmdTemplate, filename, options: string, + target: TTarget): TSpec = + let c = parseCmdLine(cmdTemplate % ["target", targetToCmd[target], + "options", options, "file", filename.quoteShell]) + var p = startProcess(command="gcc", args=c[5.. ^1], + options={poStdErrToStdOut, poUsePath}) + let outp = p.outputStream + var x = newStringOfCap(120) + result.nimout = "" + result.msg = "" + result.file = "" + result.outp = "" + result.line = -1 + while outp.readLine(x.TaintedString) or running(p): + result.nimout.add(x & "\n") + close(p) + if p.peekExitCode == 0: + result.err = reSuccess + proc initResults: TResults = result.total = 0 result.passed = 0 @@ -257,8 +276,22 @@ proc testNoSpec(r: var TResults, test: TTest) = r.addResult(test, "", given.msg, given.err) if given.err == reSuccess: inc(r.passed) +proc testC(r: var TResults, test: TTest) = + # runs C code. Doesn't support any specs, just goes by exit code. + let tname = test.name.addFileExt(".c") + inc(r.total) + styledEcho "Processing ", fgCyan, extractFilename(tname) + var given = callCCompiler(cmdTemplate, test.name & ".c", test.options, test.target) + if given.err != reSuccess: + r.addResult(test, "", given.msg, given.err) + elif test.action == actionRun: + let exeFile = changeFileExt(test.name, ExeExt) + var (buf, exitCode) = execCmdEx(exeFile, options = {poStdErrToStdOut, poUseShell}) + if exitCode != 0: given.err = reExitCodesDiffer + if given.err == reSuccess: inc(r.passed) + proc makeTest(test, options: string, cat: Category, action = actionCompile, - target = targetC): TTest = + target = targetC, env: string = ""): TTest = # start with 'actionCompile', will be overwritten in the spec: result = TTest(cat: cat, name: test, options: options, target: target, action: action) |