Compare commits

...

42 Commits

Author SHA1 Message Date
narimiran
9084d9bc02 bump NimVersion to 1.6.2 2021-12-16 17:25:05 +01:00
Miran
48c62ca48b [backport:1.0] json: limit recursion depth (#19252)
* json: limit recursion depth

* do not run this check for JS backend

(cherry picked from commit c17baaefbc)
2021-12-14 18:19:08 +01:00
Nan Xiao
70320482be basicopt.txt: Unify the format (#19251)
(cherry picked from commit 78b86b7942)
2021-12-14 18:18:57 +01:00
Dominik Picheta
e3a07f1997 Update uri.nim (#19148) [backport:1.0]
(cherry picked from commit a3ef5df680)
2021-12-11 09:25:18 +01:00
Ștefan Talpalaru
bcf9448a75 nimc.rst: fix table markup (#19239)
(cherry picked from commit 1a92edeb89)
2021-12-11 05:47:36 +01:00
Ștefan Talpalaru
a2f5e98baa nimRawSetjmp: support Windows (#19197)
* nimRawSetjmp: support Windows

Using `_setjmp()` directly is required to avoid some rare (but very
annoying) exception-related stack corruption leading to segfaults on
Windows, with Mingw-w64 and SEH.
More details: https://github.com/status-im/nimbus-eth2/issues/3121

Also add "nimBuiltinSetjmp" - mostly for benchmarking.

* fix for Apple's Clang++

(cherry picked from commit 69aabdab80)
2021-12-11 05:47:32 +01:00
Andreas Rumpf
a3b370fa87 let Nim support Nimble 0.14 with lock-file support [backport:1.6] (#19236)
(cherry picked from commit 908fc2a22e)
2021-12-10 21:40:06 +01:00
Andreas Rumpf
b7a0c08b4f added --nimMainPrefix switch; fixes #15955; refs #16945 [backport:1.6] (#19235)
(cherry picked from commit 7ff43d07b2)
2021-12-10 21:39:58 +01:00
Andreas Rumpf
46275126b8 fixes a possible 'javascript:' protocol exploit [backport:1.0] (#19134)
* fixes a possible 'javascript:' protocol exploit [backport:1.0]

* add tests

* Update tests/stdlib/trstgen.nim

* add the same logic for hyperlinks

* move the logic into a proc

Co-authored-by: narimiran <narimiran@disroot.org>
(cherry picked from commit 9338aa2497)
2021-12-10 11:47:06 +01:00
MichalMarsalek
83c472c40d move toDeque to after addLast (#19233) [backport:1.0]
Changes the order of procs definitions in order to avoid calling an undefined proc.

(cherry picked from commit c989542339)
2021-12-10 11:46:45 +01:00
Andreas Rumpf
ac57c3193d fixes an old ARC bug: the produced copy/sink operations don't copy the hidden type field for objects with enabled inheritance; fixes #19205 [backport:1.6] (#19232)
(cherry picked from commit 32d4bf3525)
2021-12-10 11:46:35 +01:00
Andreas Rumpf
7cf5e73fb7 fixes a converter handling regression that caused private converters to leak into client modules; fixes #19213; [backport:1.6] (#19229)
(cherry picked from commit 502ac4ed5e)
2021-12-10 11:46:26 +01:00
Tanguy
c14008d77f fix #19193 (#19195) [backport:1.2]
(cherry picked from commit cd592ed85b)
2021-12-08 08:33:12 +01:00
Andreas Rumpf
168a8784f4 re-enable chronos testing once again [backport:1.2] (#19222)
(cherry picked from commit 93c8427fca)
2021-12-08 08:33:05 +01:00
Etan Kissling
ee876aee28 allow HSlice bounded by constants of distinct types (#19219) [backport:1.2]
When creating heterogenous slices of distinct types, the compiler does
not initialize the internal type's `size` before accessing it.
This then leads to this crash message:
```
compiler/int128.nim(594, 11) `false` masking only implemented for 1, 2, 4 and 8 bytes [AssertionError]
```
This patch initializes the `size` properly, fixing the problem.

(cherry picked from commit 0213c7313b)
2021-12-08 08:32:57 +01:00
Andreas Rumpf
8ed903d1d0 fixes #19159 [backport:1.6] (#19210)
(cherry picked from commit 1cbdc1573a)
2021-12-06 11:19:26 +01:00
Andreas Rumpf
bfa8188dac fixes #19198 [backport:1.6] (#19209)
* fixes #19198 [backport:1.6]

* added a test case

(cherry picked from commit f90620fb32)
2021-12-06 11:19:17 +01:00
Andreas Rumpf
56409c15c0 fixes #19015 [backport:1.6] (#19204)
(cherry picked from commit d584dd5b99)
2021-12-06 11:19:08 +01:00
Andreas Rumpf
b614d97a2d misc bugfixes [backport:1.2] (#19203)
(cherry picked from commit 23c117a950)
2021-12-06 11:18:58 +01:00
Andreas Rumpf
2bb3a85a7c renamed 'gc' switch to 'mm'; [backport:1.6] (#19187)
* renamed 'gc' switch to 'mm'; [backport:1.6]
* better docs

(cherry picked from commit a0073d2d4c)
2021-11-26 07:32:15 +01:00
flywind
1247043c90 fix marshal bugs in VM (#19161) [backport:1.6]
(cherry picked from commit fe46c8b5f1)
2021-11-22 16:30:41 +01:00
Clay Sweetser
0ba76622a3 Merge file size fields correctly on Windows (#19141)
* Merge file size fields correctly on Windows

Merge file size fields correctly on Windows

- Merge the two 32-bit file size fields from `BY_HANDLE_FILE_INFORMATION` correctly in `rawToFormalFileInfo`.
- Fixes #19135

* Update os.nim

(cherry picked from commit 0a1049881e)
2021-11-22 16:30:26 +01:00
Anuken
ab6770e77f Fix undeclared 'SYS_getrandom' on emscripten (#19144)
(cherry picked from commit 270a5a372d)
2021-11-22 16:29:54 +01:00
Andreas Rumpf
c7920e9f87 fixes .raises inference for newSeq builtin under --gc:orc [backport] (#19158)
(cherry picked from commit 309ec7167e)
2021-11-17 09:26:25 +01:00
Andreas Rumpf
167881bb83 fixes #19051 [backport:1.6] (#19133)
(cherry picked from commit c6fc3b2eae)
2021-11-17 09:26:08 +01:00
flywind
73366c015f update manual (#19130) [backport]
(cherry picked from commit 3aaa12dbe5)
2021-11-17 09:25:57 +01:00
orthoplex
cfee71e779 fixed colorNames sorting mistake (#19125) [backport]
(cherry picked from commit 528ef6c218)
2021-11-17 09:25:47 +01:00
Ryan Oldenburg
1090b0c4af Remove tlsEmulation enabled from Windows + GCC config (#19119) [backport:1.6]
This flag has a very significant performance impact on programs compiled with --threads:on. It is also apparently not needed anymore for standard circumstances. Can we remove the config? See https://github.com/nim-lang/Nim/issues/18146#issuecomment-876802676 for discussion and perf impact. [backport:1.6]

(cherry picked from commit 77b696c2c9)
2021-11-11 16:16:45 +01:00
Andreas Rumpf
3f6de926f0 fixes #14470 [backport:1.2] (#19115)
(cherry picked from commit 15157d06c3)
2021-11-11 16:16:31 +01:00
Andrey Makarov
13343180b8 fix nimindexterm in rst2tex/doc2tex [backport] (#19106)
* fix nimindexterm (rst2tex/doc2tex) [backport]

* Add support for indexing in rst

(cherry picked from commit 997ccc5889)
2021-11-11 16:16:23 +01:00
Andreas Rumpf
95dce90467 fixes #19011 [backport:1.6] (#19114)
(cherry picked from commit 6ff61766da)
2021-11-11 16:16:11 +01:00
Andreas Rumpf
f85e09633d fixes #19013 [backport:1.6] (#19111)
* fixes #19013 [backport:1.6]

* added test case

(cherry picked from commit b7c66ce860)
2021-11-11 16:16:03 +01:00
Andreas Rumpf
575450dfec fixes another effect inference bug [backport:1.6] (#19100)
* fixes another effect inference bug [backport:1.6]

(cherry picked from commit fce89cb60a)
2021-11-11 16:15:51 +01:00
Andreas Rumpf
6a2babac47 fixes #19078 [backport] (#19090)
(cherry picked from commit 9d51197aa4)
2021-11-03 15:06:53 +01:00
haxscramper
a6e192f020 [FIX] Do not break formatted string line (#19085) [backport]
Otherwise, compiler produces broken error message - `$1` is not interpolated

`Error: The $1 type doesn't have a default value. The following fields must be initialized: importGraph.`

(cherry picked from commit 4c510d5577)
2021-11-03 15:06:40 +01:00
flywind
233c6e9fb3 fix #18410 (Errors initializing an object of RootObj with the C++ backend) [backport] (#18836)
* fix #18410

* one line comment

* typo

* typo

* cover cpp

(cherry picked from commit 2f730afe9e)
2021-11-03 15:06:31 +01:00
Derek 呆
97286db546 fix #18971 (#19070) [backport:1.6]
since the example code return value from global variable, instead
of first argument, the `n.len` is 1 which causes compiler crashes.

(cherry picked from commit f755e452d2)
2021-11-03 15:06:24 +01:00
Timothy Alexander
1ac029c0f6 Fix #19052; [backport:1.6.0] (#19053)
* Fix #19052; [backport:1.6.0]

Adds a compile flag to avoid a getrandom syscall, fixing #19052.

This is neccesary when the getrandom syscall is missing, as noted in #19052, particularly in kernel versions < 3.17 when getrandom was introduced. Specifically relevant is this is missing from kernel 3.10, which is the supported kernel throughout RHEL 7 and CentOS 7, which is widely used at many organizations. Without this, versions of nim that include sysrand (i.e. versions >= 1.6.0) will not compile without modification, however with this change a compile flag may be used to fall back using /dev/urandom as done with any unknown Posix OS (preferred here as a fallback since it already supplies a cryptographically secure PRNG and existing code deals with entropy pool init, etc).

The change is placed behind a compile flag, as discussed in github ticket #19052 (summed up here):
* First, I can't seem to catch that a importc such as SYS_getrandom is declared without using it (the declared proc returns true, but compiler throws an undeclared identifier flag when referencing it).
* Second, it seemed preferable to be behaviorally explicit vs implicit when considering this is intended to be a cryptographically secure PRNG.
* Third, if I intend to compile on a kernel >= 3.17 while running the binary on at least one system < 3.17, I'll want to be able to target this without relying on a compile time determination if the getrandom syscall is available.

* Documenting compile flag for -d:nimNoGetRandom and adding changelog entry
Related to #19052 and comments in PR #19053. Also created a new changelog file since none currently exists.

Co-authored-by: Timothy Alexander <talexander@midwestlabs.com>
(cherry picked from commit dde556665a)
2021-11-03 15:05:32 +01:00
Andreas Rumpf
b18b636ea6 use two underscores for easy demangling [backport:1.6] (#19028)
(cherry picked from commit 1a45da9150)
2021-10-27 11:06:42 +02:00
narimiran
ac89e06c6e bump NimVersion to 1.6.1 2021-10-27 11:05:16 +02:00
Etan Kissling
861b625a66 allow converting static vars to openArray (#19047)
When assigning constant output to a seq, and then passing that static
seq to other functions that take `openArray`, the compiler may end up
producing errors, as it does not know how to convert `static[seq[T]]`
to `openArray[T]`. By ignoring the `static` wrapper on the type for
the purpose of determining data memory location and length, this gets
resolved cleanly. Unfortunately, it is relatively tricky to come up
with a minimal example, as there are followup problems from the failing
conversion, e.g., this may lead to `internal error: inconsistent
environment type`, instead of the relevant `openArrayLoc` error message.

(cherry picked from commit 490c4226a5)
2021-10-27 11:03:22 +02:00
narimiran
727c6378d2 bump NimVersion to 1.6.0 2021-10-18 16:36:47 +02:00
73 changed files with 962 additions and 294 deletions

View File

@@ -4,6 +4,10 @@
## Changes affecting backward compatibility
- Optional parameters in combination with `: body` syntax (RFC #405) are now opt-in via
`experimental:flexibleOptionalParams`.
## Standard library additions and changes
## Standard library additions and changes
@@ -12,6 +16,38 @@
## Language changes
- Pragma macros on type definitions can now return `nnkTypeSection` nodes as well as `nnkTypeDef`,
allowing multiple type definitions to be injected in place of the original type definition.
```nim
import macros
macro multiply(amount: static int, s: untyped): untyped =
let name = $s[0].basename
result = newNimNode(nnkTypeSection)
for i in 1 .. amount:
result.add(newTree(nnkTypeDef, ident(name & $i), s[1], s[2]))
type
Foo = object
Bar {.multiply: 3.} = object
x, y, z: int
Baz = object
# becomes
type
Foo = object
Bar1 = object
x, y, z: int
Bar2 = object
x, y, z: int
Bar3 = object
x, y, z: int
Baz = object
```
- [Case statement macros](manual.html#macros-case-statement-macros) are no longer experimental,
meaning you no longer need to enable the experimental switch `caseStmtMacros` to use them.
## Compiler changes
@@ -21,5 +57,12 @@
## Tool changes
- The `gc` switch has been renamed to `mm` ("memory management") in order to reflect the
reality better. (Nim moved away from all techniques based on "tracing".)
- Nim now supports Nimble version 0.14 which added support for lock-files. This is done by
a simple configuration change setting that you can do yourself too. In `$nim/config/nim.cfg`
replace `pkgs` by `pkgs2`.
- There is a new switch `--nimMainPrefix:prefix` to influence the `NimMain` that the
compiler produces. This is particularly useful for generating static libraries.

31
changelogs/changelog.md Normal file
View File

@@ -0,0 +1,31 @@
# v1.xx.x - yyyy-mm-dd
## Changes affecting backward compatibility
## Standard library additions and changes
### New compile flag (`-d:nimNoGetRandom`) when building `std/sysrand` to remove dependency on linux `getrandom` syscall
This compile flag only affects linux builds and is necessary if either compiling on a linux kernel version < 3.17, or if code built will be executing on kernel < 3.17.
On linux kernels < 3.17 (such as kernel 3.10 in RHEL7 and CentOS7), the `getrandom` syscall was not yet introduced. Without this, the `std/sysrand` module will not build properly, and if code is built on a kernel >= 3.17 without the flag, any usage of the `std/sysrand` module will fail to execute on a kernel < 3.17 (since it attempts to perform a syscall to `getrandom`, which isn't present in the current kernel). A compile flag has been added to force the `std/sysrand` module to use /dev/urandom (available since linux kernel 1.3.30), rather than the `getrandom` syscall. This allows for use of a cryptographically secure PRNG, regardless of kernel support for the `getrandom` syscall.
When building for RHEL7/CentOS7 for example, the entire build process for nim from a source package would then be:
```sh
$ yum install devtoolset-8 # Install GCC version 8 vs the standard 4.8.5 on RHEL7/CentOS7. Alternatively use -d:nimEmulateOverflowChecks. See issue #13692 for details
$ scl enable devtoolset-8 bash # Run bash shell with default toolchain of gcc 8
$ sh build.sh # per unix install instructions
$ bin/nim c koch # per unix install instructions
$ ./koch boot -d:release # per unix install instructions
$ ./koch tools -d:nimNoGetRandom # pass the nimNoGetRandom flag to compile std/sysrand without support for getrandom syscall
```
This is necessary to pass when building nim on kernel versions < 3.17 in particular to avoid an error of "SYS_getrandom undeclared" during the build process for stdlib (sysrand in particular).
## Language changes
## Compiler changes
## Tool changes

View File

@@ -673,7 +673,7 @@ type
mSwap, mIsNil, mArrToSeq,
mNewString, mNewStringOfCap, mParseBiggestFloat,
mMove, mWasMoved, mDestroy, mTrace,
mDefault, mUnown, mFinished, mIsolate, mAccessEnv, mReset,
mDefault, mUnown, mFinished, mIsolate, mAccessEnv, mAccessTypeField, mReset,
mArray, mOpenArray, mRange, mSet, mSeq, mVarargs,
mRef, mPtr, mVar, mDistinct, mVoid, mTuple,
mOrdinal, mIterableType,
@@ -2101,3 +2101,11 @@ proc skipAddr*(n: PNode): PNode {.inline.} =
proc isNewStyleConcept*(n: PNode): bool {.inline.} =
assert n.kind == nkTypeClassTy
result = n[0].kind == nkEmpty
const
nodesToIgnoreSet* = {nkNone..pred(nkSym), succ(nkSym)..nkNilLit,
nkTypeSection, nkProcDef, nkConverterDef,
nkMethodDef, nkIteratorDef, nkMacroDef, nkTemplateDef, nkLambda, nkDo,
nkFuncDef, nkConstSection, nkConstDef, nkIncludeStmt, nkImportStmt,
nkExportStmt, nkPragma, nkCommentStmt, nkBreakState,
nkTypeOfExpr, nkMixinStmt, nkBindStmt}

View File

@@ -214,7 +214,7 @@ proc openArrayLoc(p: BProc, formalType: PType, n: PNode): Rope =
else:
var a: TLoc
initLocExpr(p, if n.kind == nkHiddenStdConv: n[1] else: n, a)
case skipTypes(a.t, abstractVar).kind
case skipTypes(a.t, abstractVar+{tyStatic}).kind
of tyOpenArray, tyVarargs:
if reifiedOpenArray(n):
if a.t.kind in {tyVar, tyLent}:

View File

@@ -1741,6 +1741,13 @@ proc genGetTypeInfoV2(p: BProc, e: PNode, d: var TLoc) =
# use the dynamic type stored at offset 0:
putIntoDest(p, d, e, rdMType(p, a, nilCheck))
proc genAccessTypeField(p: BProc; e: PNode; d: var TLoc) =
var a: TLoc
initLocExpr(p, e[1], a)
var nilCheck = Rope(nil)
# use the dynamic type stored at offset 0:
putIntoDest(p, d, e, rdMType(p, a, nilCheck))
template genDollar(p: BProc, n: PNode, d: var TLoc, frmt: string) =
var a: TLoc
initLocExpr(p, n[1], a)
@@ -2449,6 +2456,7 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
of mMove: genMove(p, e, d)
of mDestroy: genDestroy(p, e)
of mAccessEnv: unaryExpr(p, e, d, "$1.ClE_0")
of mAccessTypeField: genAccessTypeField(p, e, d)
of mSlice: genSlice(p, e, d)
of mTrace: discard "no code to generate"
else:

View File

@@ -1356,8 +1356,19 @@ proc genTrySetjmp(p: BProc, t: PNode, d: var TLoc) =
linefmt(p, cpsStmts, "$1.status = setjmp($1.context);$n", [safePoint])
elif isDefined(p.config, "nimSigSetjmp"):
linefmt(p, cpsStmts, "$1.status = sigsetjmp($1.context, 0);$n", [safePoint])
elif isDefined(p.config, "nimBuiltinSetjmp"):
linefmt(p, cpsStmts, "$1.status = __builtin_setjmp($1.context);$n", [safePoint])
elif isDefined(p.config, "nimRawSetjmp"):
linefmt(p, cpsStmts, "$1.status = _setjmp($1.context);$n", [safePoint])
if isDefined(p.config, "mswindows"):
# The Windows `_setjmp()` takes two arguments, with the second being an
# undocumented buffer used by the SEH mechanism for stack unwinding.
# Mingw-w64 has been trying to get it right for years, but it's still
# prone to stack corruption during unwinding, so we disable that by setting
# it to NULL.
# More details: https://github.com/status-im/nimbus-eth2/issues/3121
linefmt(p, cpsStmts, "$1.status = _setjmp($1.context, 0);$n", [safePoint])
else:
linefmt(p, cpsStmts, "$1.status = _setjmp($1.context);$n", [safePoint])
else:
linefmt(p, cpsStmts, "$1.status = setjmp($1.context);$n", [safePoint])
lineCg(p, cpsStmts, "if ($1.status == 0) {$n", [safePoint])

View File

@@ -39,7 +39,7 @@ proc mangleName(m: BModule; s: PSym): Rope =
result = s.loc.r
if result == nil:
result = s.name.s.mangle.rope
result.add "_"
result.add "__"
result.add m.g.graph.ifaces[s.itemId.module].uniqueName
result.add "_"
result.add rope s.itemId.item
@@ -220,7 +220,8 @@ proc isInvalidReturnType(conf: ConfigRef; rettype: PType): bool =
# such a poor programming language.
# We exclude records with refs too. This enhances efficiency and
# is necessary for proper code generation of assignments.
if rettype == nil: result = true
if rettype == nil or getSize(conf, rettype) > conf.target.floatSize*3:
result = true
else:
case mapType(conf, rettype, skResult)
of ctArray:
@@ -582,7 +583,7 @@ proc getRecordDesc(m: BModule, typ: PType, name: Rope,
if typ.kind == tyObject:
if typ[0] == nil:
if (typ.sym != nil and sfPure in typ.sym.flags) or tfFinal in typ.flags:
if lacksMTypeField(typ):
appcg(m, result, " {$n", [])
else:
if optTinyRtti in m.config.globalOptions:

View File

@@ -154,6 +154,11 @@ macro ropecg(m: BModule, frmt: static[FormatStr], args: untyped): Rope =
inc(i)
result.add newCall(formatValue, resVar, args[num])
inc(num)
of '^':
flushStrLit()
inc(i)
result.add newCall(formatValue, resVar, args[^1])
inc(num)
of '0'..'9':
var j = 0
while true:
@@ -363,7 +368,8 @@ proc genObjectInit(p: BProc, section: TCProcSection, t: PType, a: var TLoc,
else:
linefmt(p, section, "$1.m_type = $2;$n", [r, genTypeInfoV1(p.module, t, a.lode.info)])
of frEmbedded:
if optTinyRtti in p.config.globalOptions:
# inheritance in C++ does not allow struct initialization: bug #18410
if not p.module.compileToCpp and optTinyRtti in p.config.globalOptions:
var tmp: TLoc
if mode == constructRefObj:
let objType = t.skipTypes(abstractInst+{tyRef})
@@ -442,8 +448,14 @@ proc constructLoc(p: BProc, loc: var TLoc, isTemp = false) =
if optSeqDestructors in p.config.globalOptions and skipTypes(typ, abstractInst + {tyStatic}).kind in {tyString, tySequence}:
linefmt(p, cpsStmts, "$1.len = 0; $1.p = NIM_NIL;$n", [rdLoc(loc)])
elif not isComplexValueType(typ):
linefmt(p, cpsStmts, "$1 = ($2)0;$n", [rdLoc(loc),
getTypeDesc(p.module, typ, mapTypeChooser(loc))])
if containsGarbageCollectedRef(loc.t):
var nilLoc: TLoc
initLoc(nilLoc, locTemp, loc.lode, OnStack)
nilLoc.r = rope("NIM_NIL")
genRefAssign(p, loc, nilLoc)
else:
linefmt(p, cpsStmts, "$1 = ($2)0;$n", [rdLoc(loc),
getTypeDesc(p.module, typ, mapTypeChooser(loc))])
else:
if not isTemp or containsGarbageCollectedRef(loc.t):
# don't use nimZeroMem for temporary values for performance if we can
@@ -1359,7 +1371,7 @@ proc genMainProc(m: BModule) =
"}$N$N"
MainProcs =
"\tNimMain();$N"
"\t$^NimMain();$N"
MainProcsWithResult =
MainProcs & ("\treturn $1nim_program_result;$N")
@@ -1369,7 +1381,7 @@ proc genMainProc(m: BModule) =
"}$N$N"
NimMainProc =
"N_CDECL(void, NimMain)(void) {$N" &
"N_CDECL(void, $5NimMain)(void) {$N" &
"\tvoid (*volatile inner)(void);$N" &
"$4" &
"\tinner = NimMainInner;$N" &
@@ -1449,28 +1461,27 @@ proc genMainProc(m: BModule) =
if optGenGuiApp in m.config.globalOptions:
const nimMain = WinNimMain
appcg(m, m.s[cfsProcs], nimMain,
[m.g.mainModInit, initStackBottomCall, m.labels, preMainCode])
[m.g.mainModInit, initStackBottomCall, m.labels, preMainCode, m.config.nimMainPrefix])
else:
const nimMain = WinNimDllMain
appcg(m, m.s[cfsProcs], nimMain,
[m.g.mainModInit, initStackBottomCall, m.labels, preMainCode])
[m.g.mainModInit, initStackBottomCall, m.labels, preMainCode, m.config.nimMainPrefix])
elif m.config.target.targetOS == osGenode:
const nimMain = GenodeNimMain
appcg(m, m.s[cfsProcs], nimMain,
[m.g.mainModInit, initStackBottomCall, m.labels, preMainCode])
[m.g.mainModInit, initStackBottomCall, m.labels, preMainCode, m.config.nimMainPrefix])
elif optGenDynLib in m.config.globalOptions:
const nimMain = PosixNimDllMain
appcg(m, m.s[cfsProcs], nimMain,
[m.g.mainModInit, initStackBottomCall, m.labels, preMainCode])
[m.g.mainModInit, initStackBottomCall, m.labels, preMainCode, m.config.nimMainPrefix])
elif m.config.target.targetOS == osStandalone:
const nimMain = NimMainBody
appcg(m, m.s[cfsProcs], nimMain,
[m.g.mainModInit, initStackBottomCall, m.labels, preMainCode])
[m.g.mainModInit, initStackBottomCall, m.labels, preMainCode, m.config.nimMainPrefix])
else:
const nimMain = NimMainBody
appcg(m, m.s[cfsProcs], nimMain,
[m.g.mainModInit, initStackBottomCall, m.labels, preMainCode])
[m.g.mainModInit, initStackBottomCall, m.labels, preMainCode, m.config.nimMainPrefix])
if optNoMain notin m.config.globalOptions:
if m.config.cppCustomNamespace.len > 0:
@@ -1480,23 +1491,22 @@ proc genMainProc(m: BModule) =
m.config.globalOptions * {optGenGuiApp, optGenDynLib} != {}:
if optGenGuiApp in m.config.globalOptions:
const otherMain = WinCMain
appcg(m, m.s[cfsProcs], otherMain, [if m.hcrOn: "*" else: ""])
appcg(m, m.s[cfsProcs], otherMain, [if m.hcrOn: "*" else: "", m.config.nimMainPrefix])
else:
const otherMain = WinCDllMain
appcg(m, m.s[cfsProcs], otherMain, [])
appcg(m, m.s[cfsProcs], otherMain, [m.config.nimMainPrefix])
elif m.config.target.targetOS == osGenode:
const otherMain = ComponentConstruct
appcg(m, m.s[cfsProcs], otherMain, [])
appcg(m, m.s[cfsProcs], otherMain, [m.config.nimMainPrefix])
elif optGenDynLib in m.config.globalOptions:
const otherMain = PosixCDllMain
appcg(m, m.s[cfsProcs], otherMain, [])
appcg(m, m.s[cfsProcs], otherMain, [m.config.nimMainPrefix])
elif m.config.target.targetOS == osStandalone:
const otherMain = StandaloneCMain
appcg(m, m.s[cfsProcs], otherMain, [])
appcg(m, m.s[cfsProcs], otherMain, [m.config.nimMainPrefix])
else:
const otherMain = PosixCMain
appcg(m, m.s[cfsProcs], otherMain, [if m.hcrOn: "*" else: ""])
appcg(m, m.s[cfsProcs], otherMain, [if m.hcrOn: "*" else: "", m.config.nimMainPrefix])
if m.config.cppCustomNamespace.len > 0:
m.s[cfsProcs].add openNamespaceNim(m.config.cppCustomNamespace)
@@ -1878,7 +1888,7 @@ proc writeHeader(m: BModule) =
if optGenDynLib in m.config.globalOptions:
result.add("N_LIB_IMPORT ")
result.addf("N_CDECL(void, NimMain)(void);$n", [])
result.addf("N_CDECL(void, $1NimMain)(void);$n", [rope m.config.nimMainPrefix])
if m.config.cppCustomNamespace.len > 0: result.add closeNamespaceNim()
result.addf("#endif /* $1 */$n", [guard])
if not writeRope(result, m.filename):

View File

@@ -248,7 +248,7 @@ template deprecatedAlias(oldName, newName: string) =
proc testCompileOptionArg*(conf: ConfigRef; switch, arg: string, info: TLineInfo): bool =
case switch.normalize
of "gc":
of "gc", "mm":
case arg.normalize
of "boehm": result = conf.selectedGC == gcBoehm
of "refc": result = conf.selectedGC == gcRefc
@@ -596,7 +596,7 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
processOnOffSwitchG(conf, {optForceFullMake}, arg, pass, info)
of "project":
processOnOffSwitchG(conf, {optWholeProject, optGenIndex}, arg, pass, info)
of "gc":
of "gc", "mm":
if conf.backend == backendJs: return # for: bug #16033
expectArg(conf, switch, arg, pass, info)
if pass in {passCmd2, passPP}:
@@ -1052,6 +1052,7 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
of "": # comes from "-" in for example: `nim c -r -` (gets stripped from -)
handleStdinInput(conf)
of "nilseqs", "nilchecks", "mainmodule", "m", "symbol", "taintmode", "cs", "deadcodeelim": warningOptionNoop(switch)
of "nimmainprefix": conf.nimMainPrefix = arg
else:
if strutils.find(switch, '.') >= 0: options.setConfigVar(conf, switch, arg)
else: invalidCmdLineOption(conf, pass, switch, info)

View File

@@ -138,3 +138,5 @@ proc initDefines*(symbols: StringTableRef) =
defineSymbol("nimHasHintAll")
defineSymbol("nimHasTrace")
defineSymbol("nimHasEffectsOf")
defineSymbol("nimHasEnforceNoRaises")

View File

@@ -185,11 +185,13 @@ template addUnnamedIt(c: PContext, fromMod: PSym; filter: untyped) {.dirty.} =
for it in mitems c.graph.ifaces[fromMod.position].converters:
if filter:
loadPackedSym(c.graph, it)
addConverter(c, it)
if sfExported in it.sym.flags:
addConverter(c, it)
for it in mitems c.graph.ifaces[fromMod.position].patterns:
if filter:
loadPackedSym(c.graph, it)
addPattern(c, it)
if sfExported in it.sym.flags:
addPattern(c, it)
for it in mitems c.graph.ifaces[fromMod.position].pureEnums:
if filter:
loadPackedSym(c.graph, it)

View File

@@ -77,6 +77,17 @@ proc canAlias*(arg, ret: PType): bool =
var marker = initIntSet()
result = canAlias(arg, ret, marker)
proc containsVariable(n: PNode): bool =
case n.kind
of nodesToIgnoreSet:
result = false
of nkSym:
result = n.sym.kind in {skForVar, skParam, skVar, skLet, skConst, skResult, skTemp}
else:
for ch in n:
if containsVariable(ch): return true
result = false
proc checkIsolate*(n: PNode): bool =
if types.containsTyRef(n.typ):
# XXX Maybe require that 'n.typ' is acyclic. This is not much
@@ -96,7 +107,11 @@ proc checkIsolate*(n: PNode): bool =
else:
let argType = n[i].typ
if argType != nil and not isCompileTimeOnly(argType) and containsTyRef(argType):
if argType.canAlias(n.typ):
if argType.canAlias(n.typ) or containsVariable(n[i]):
# bug #19013: Alias information is not enough, we need to check for potential
# "overlaps". I claim the problem can only happen by reading again from a location
# that materialized which is only possible if a variable that contains a `ref`
# is involved.
return false
result = true
of nkIfStmt, nkIfExpr:

View File

@@ -941,6 +941,12 @@ proc symPrototype(g: ModuleGraph; typ: PType; owner: PSym; kind: TTypeAttachedOp
incl result.flags, sfFromGeneric
incl result.flags, sfGeneratedOp
proc genTypeFieldCopy(c: var TLiftCtx; t: PType; body, x, y: PNode) =
let xx = genBuiltin(c, mAccessTypeField, "accessTypeField", x)
let yy = genBuiltin(c, mAccessTypeField, "accessTypeField", y)
xx.typ = getSysType(c.g, c.info, tyPointer)
yy.typ = xx.typ
body.add newAsgnStmt(xx, yy)
proc produceSym(g: ModuleGraph; c: PContext; typ: PType; kind: TTypeAttachedOp;
info: TLineInfo; idgen: IdGenerator): PSym =
@@ -980,6 +986,10 @@ proc produceSym(g: ModuleGraph; c: PContext; typ: PType; kind: TTypeAttachedOp;
fillStrOp(a, typ, result.ast[bodyPos], d, src)
else:
fillBody(a, typ, result.ast[bodyPos], d, src)
if tk == tyObject and a.kind in {attachedAsgn, attachedSink, attachedDeepCopy} and not lacksMTypeField(typ):
# bug #19205: Do not forget to also copy the hidden type field:
genTypeFieldCopy(a, typ, result.ast[bodyPos], d, src)
if not a.canRaise: incl result.flags, sfNeverRaises
completePartialOp(g, idgen.module, typ, kind, result)

View File

@@ -207,7 +207,8 @@ type
strictNotNil,
overloadableEnums,
strictEffects,
unicodeOperators
unicodeOperators,
flexibleOptionalParams
LegacyFeature* = enum
allowSemcheckedAstModification,
@@ -389,6 +390,7 @@ type
structuredErrorHook*: proc (config: ConfigRef; info: TLineInfo; msg: string;
severity: Severity) {.closure, gcsafe.}
cppCustomNamespace*: string
nimMainPrefix*: string
vmProfileData*: ProfileData
proc parseNimVersion*(a: string): NimVer =

View File

@@ -1877,7 +1877,7 @@ proc parseEnum(p: var Parser): PNode =
var symPragma = a
var pragma: PNode
if p.tok.tokType == tkCurlyDotLe:
if (p.tok.indent < 0 or p.tok.indent >= p.currInd) and p.tok.tokType == tkCurlyDotLe:
pragma = optPragmas(p)
symPragma = newNodeP(nkPragmaExpr, p)
symPragma.add(a)

View File

@@ -31,7 +31,7 @@ const
wAsmNoStackFrame, wDiscardable, wNoInit, wCodegenDecl,
wGensym, wInject, wRaises, wEffectsOf, wTags, wLocks, wDelegator, wGcSafe,
wConstructor, wLiftLocals, wStackTrace, wLineTrace, wNoDestroy,
wRequires, wEnsures}
wRequires, wEnsures, wEnforceNoRaises}
converterPragmas* = procPragmas
methodPragmas* = procPragmas+{wBase}-{wImportCpp}
templatePragmas* = {wDeprecated, wError, wGensym, wInject, wDirty,
@@ -1237,6 +1237,8 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
pragmaProposition(c, it)
of wEnsures:
pragmaEnsures(c, it)
of wEnforceNoRaises:
sym.flags.incl sfNeverRaises
else: invalidPragma(c, it)
elif comesFromPush and whichKeyword(ident) != wInvalid:
discard "ignore the .push pragma; it doesn't apply"

View File

@@ -133,7 +133,7 @@ proc evalOp(m: TMagic, n, a, b, c: PNode; idgen: IdGenerator; g: ModuleGraph): P
of mCard: result = newIntNodeT(toInt128(nimsets.cardSet(g.config, a)), n, idgen, g)
of mBitnotI:
if n.typ.isUnsigned:
result = newIntNodeT(bitnot(getInt(a)).maskBytes(int(n.typ.size)), n, idgen, g)
result = newIntNodeT(bitnot(getInt(a)).maskBytes(int(getSize(g.config, n.typ))), n, idgen, g)
else:
result = newIntNodeT(bitnot(getInt(a)), n, idgen, g)
of mLengthArray: result = newIntNodeT(lengthOrd(g.config, a.typ), n, idgen, g)
@@ -248,23 +248,23 @@ proc evalOp(m: TMagic, n, a, b, c: PNode; idgen: IdGenerator; g: ModuleGraph): P
of mBitorI, mOr: result = newIntNodeT(bitor(getInt(a), getInt(b)), n, idgen, g)
of mBitxorI, mXor: result = newIntNodeT(bitxor(getInt(a), getInt(b)), n, idgen, g)
of mAddU:
let val = maskBytes(getInt(a) + getInt(b), int(n.typ.size))
let val = maskBytes(getInt(a) + getInt(b), int(getSize(g.config, n.typ)))
result = newIntNodeT(val, n, idgen, g)
of mSubU:
let val = maskBytes(getInt(a) - getInt(b), int(n.typ.size))
let val = maskBytes(getInt(a) - getInt(b), int(getSize(g.config, n.typ)))
result = newIntNodeT(val, n, idgen, g)
# echo "subU: ", val, " n: ", n, " result: ", val
of mMulU:
let val = maskBytes(getInt(a) * getInt(b), int(n.typ.size))
let val = maskBytes(getInt(a) * getInt(b), int(getSize(g.config, n.typ)))
result = newIntNodeT(val, n, idgen, g)
of mModU:
let argA = maskBytes(getInt(a), int(a.typ.size))
let argB = maskBytes(getInt(b), int(a.typ.size))
let argA = maskBytes(getInt(a), int(getSize(g.config, a.typ)))
let argB = maskBytes(getInt(b), int(getSize(g.config, a.typ)))
if argB != Zero:
result = newIntNodeT(argA mod argB, n, idgen, g)
of mDivU:
let argA = maskBytes(getInt(a), int(a.typ.size))
let argB = maskBytes(getInt(b), int(a.typ.size))
let argA = maskBytes(getInt(a), int(getSize(g.config, a.typ)))
let argB = maskBytes(getInt(b), int(getSize(g.config, a.typ)))
if argB != Zero:
result = newIntNodeT(argA div argB, n, idgen, g)
of mLeSet: result = newIntNodeT(toInt128(ord(containsSets(g.config, a, b))), n, idgen, g)

View File

@@ -366,10 +366,9 @@ proc defaultConstructionError(c: PContext, t: PType, info: TLineInfo) =
if objType.kind == tyObject:
var constrCtx = initConstrContext(objType, newNodeI(nkObjConstr, info))
let initResult = semConstructTypeAux(c, constrCtx, {})
assert constrCtx.missingFields.len > 0
localError(c.config, info,
"The $1 type doesn't have a default value. The following fields must " &
"be initialized: $2." % [typeToString(t), listSymbolNames(constrCtx.missingFields)])
if constrCtx.missingFields.len > 0:
localError(c.config, info,
"The $1 type doesn't have a default value. The following fields must be initialized: $2." % [typeToString(t), listSymbolNames(constrCtx.missingFields)])
elif objType.kind == tyDistinct:
localError(c.config, info,
"The $1 distinct type doesn't have a default value." % typeToString(t))

View File

@@ -851,11 +851,15 @@ proc trackCall(tracked: PEffects; n: PNode) =
elif isIndirectCall(tracked, a):
assumeTheWorst(tracked, n, op)
gcsafeAndSideeffectCheck()
else:
if strictEffects in tracked.c.features and a.kind == nkSym and
a.sym.kind in routineKinds:
propagateEffects(tracked, n, a.sym)
else:
mergeRaises(tracked, effectList[exceptionEffects], n)
mergeTags(tracked, effectList[tagEffects], n)
gcsafeAndSideeffectCheck()
if a.kind != nkSym or a.sym.magic notin {mNBindSym, mFinished}:
if a.kind != nkSym or a.sym.magic notin {mNBindSym, mFinished, mExpandToAst, mQuoteAst}:
for i in 1..<n.len:
trackOperandForIndirectCall(tracked, n[i], op, i, a)
if a.kind == nkSym and a.sym.magic in {mNew, mNewFinalize, mNewSeq}:
@@ -880,7 +884,7 @@ proc trackCall(tracked: PEffects; n: PNode) =
optStaticBoundsCheck in tracked.currOptions:
checkBounds(tracked, n[1], n[2])
if a.kind != nkSym or a.sym.magic != mRunnableExamples:
if a.kind != nkSym or a.sym.magic notin {mRunnableExamples, mNBindSym, mExpandToAst, mQuoteAst}:
for i in 0..<n.safeLen:
track(tracked, n[i])

View File

@@ -2461,7 +2461,8 @@ proc matchesAux(c: PContext, n, nOrig: PNode, m: var TCandidate, marker: var Int
if m.callee.n[f].kind != nkSym:
internalError(c.config, n[a].info, "matches")
noMatch()
if a >= firstArgBlock: f = max(f, m.callee.n.len - (n.len - a))
if flexibleOptionalParams in c.features and a >= firstArgBlock:
f = max(f, m.callee.n.len - (n.len - a))
formal = m.callee.n[f].sym
m.firstMismatch.kind = kTypeMismatch
if containsOrIncl(marker, formal.position) and container.isNil:

View File

@@ -196,6 +196,11 @@ proc computeUnionObjectOffsetsFoldFunction(conf: ConfigRef; n: PNode; packed: bo
accum.offset = szUnknownSize
proc computeSizeAlign(conf: ConfigRef; typ: PType) =
template setSize(typ, s) =
typ.size = s
typ.align = s
typ.paddingAtEnd = 0
## computes and sets ``size`` and ``align`` members of ``typ``
assert typ != nil
let hasSize = typ.size != szUncomputedSize
@@ -258,14 +263,14 @@ proc computeSizeAlign(conf: ConfigRef; typ: PType) =
of tyArray:
computeSizeAlign(conf, typ[1])
let elemSize = typ[1].size
let elemSize = typ[1].size
let len = lengthOrd(conf, typ[0])
if elemSize < 0:
typ.size = elemSize
typ.align = int16(elemSize)
elif len < 0:
typ.size = szUnknownSize
typ.align = szUnknownSize
typ.align = szUnknownSize
else:
typ.size = toInt64Checked(len * int32(elemSize), szTooBigSize)
typ.align = typ[1].align
@@ -445,6 +450,16 @@ proc computeSizeAlign(conf: ConfigRef; typ: PType) =
typ.size = szUnknownSize
typ.align = szUnknownSize
typ.paddingAtEnd = szUnknownSize
of tyInt, tyUInt:
setSize typ, conf.target.intSize.int16
of tyBool, tyChar, tyUInt8, tyInt8:
setSize typ, 1
of tyInt16, tyUInt16:
setSize typ, 2
of tyInt32, tyUInt32:
setSize typ, 4
of tyInt64, tyUInt64:
setSize typ, 8
else:
typ.size = szUnknownSize
typ.align = szUnknownSize

View File

@@ -1700,3 +1700,6 @@ proc isCharArrayPtr*(t: PType; allowPointerToChar: bool): bool =
result = allowPointerToChar
else:
discard
proc lacksMTypeField*(typ: PType): bool {.inline.} =
(typ.sym != nil and sfPure in typ.sym.flags) or tfFinal in typ.flags

View File

@@ -479,7 +479,7 @@ proc destMightOwn(c: var Partitions; dest: var VarIndex; n: PNode) =
# calls do construct, what we construct must be destroyed,
# so dest cannot be a cursor:
dest.flags.incl ownsData
elif n.typ.kind in {tyLent, tyVar}:
elif n.typ.kind in {tyLent, tyVar} and n.len > 1:
# we know the result is derived from the first argument:
var roots: seq[(PSym, int)]
allRoots(n[1], roots, RootEscapes)
@@ -647,13 +647,6 @@ proc deps(c: var Partitions; dest, src: PNode) =
when explainCursors: echo "D not a cursor ", d.sym, " reassignedTo ", c.s[srcid].reassignedTo
c.s[vid].flags.incl preventCursor
const
nodesToIgnoreSet = {nkNone..pred(nkSym), succ(nkSym)..nkNilLit,
nkTypeSection, nkProcDef, nkConverterDef,
nkMethodDef, nkIteratorDef, nkMacroDef, nkTemplateDef, nkLambda, nkDo,
nkFuncDef, nkConstSection, nkConstDef, nkIncludeStmt, nkImportStmt,
nkExportStmt, nkPragma, nkCommentStmt, nkBreakState,
nkTypeOfExpr, nkMixinStmt, nkBindStmt}
proc potentialMutationViaArg(c: var Partitions; n: PNode; callee: PType) =
if constParameters in c.goals and tfNoSideEffect in callee.flags:

View File

@@ -434,8 +434,10 @@ proc opConv(c: PCtx; dest: var TFullReg, src: TFullReg, desttyp, srctyp: PType):
of tyFloat..tyFloat64:
dest.intVal = int(src.floatVal)
else:
let srcDist = (sizeof(src.intVal) - styp.size) * 8
let destDist = (sizeof(dest.intVal) - desttyp.size) * 8
let srcSize = getSize(c.config, styp)
let destSize = getSize(c.config, desttyp)
let srcDist = (sizeof(src.intVal) - srcSize) * 8
let destDist = (sizeof(dest.intVal) - destSize) * 8
var value = cast[BiggestUInt](src.intVal)
value = (value shl srcDist) shr srcDist
value = (value shl destDist) shr destDist

View File

@@ -749,18 +749,20 @@ proc genNarrow(c: PCtx; n: PNode; dest: TDest) =
let t = skipTypes(n.typ, abstractVar-{tyTypeDesc})
# uint is uint64 in the VM, we we only need to mask the result for
# other unsigned types:
if t.kind in {tyUInt8..tyUInt32} or (t.kind == tyUInt and t.size < 8):
c.gABC(n, opcNarrowU, dest, TRegister(t.size*8))
elif t.kind in {tyInt8..tyInt32} or (t.kind == tyInt and t.size < 8):
c.gABC(n, opcNarrowS, dest, TRegister(t.size*8))
let size = getSize(c.config, t)
if t.kind in {tyUInt8..tyUInt32} or (t.kind == tyUInt and size < 8):
c.gABC(n, opcNarrowU, dest, TRegister(size*8))
elif t.kind in {tyInt8..tyInt32} or (t.kind == tyInt and size < 8):
c.gABC(n, opcNarrowS, dest, TRegister(size*8))
proc genNarrowU(c: PCtx; n: PNode; dest: TDest) =
let t = skipTypes(n.typ, abstractVar-{tyTypeDesc})
# uint is uint64 in the VM, we we only need to mask the result for
# other unsigned types:
let size = getSize(c.config, t)
if t.kind in {tyUInt8..tyUInt32, tyInt8..tyInt32} or
(t.kind in {tyUInt, tyInt} and t.size < 8):
c.gABC(n, opcNarrowU, dest, TRegister(t.size*8))
(t.kind in {tyUInt, tyInt} and size < 8):
c.gABC(n, opcNarrowU, dest, TRegister(size*8))
proc genBinaryABCnarrow(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode) =
genBinaryABC(c, n, dest, opc)
@@ -1088,10 +1090,11 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
genBinaryABC(c, n, dest, opcShlInt)
# genNarrowU modified
let t = skipTypes(n.typ, abstractVar-{tyTypeDesc})
if t.kind in {tyUInt8..tyUInt32} or (t.kind == tyUInt and t.size < 8):
c.gABC(n, opcNarrowU, dest, TRegister(t.size*8))
elif t.kind in {tyInt8..tyInt32} or (t.kind == tyInt and t.size < 8):
c.gABC(n, opcSignExtend, dest, TRegister(t.size*8))
let size = getSize(c.config, t)
if t.kind in {tyUInt8..tyUInt32} or (t.kind == tyUInt and size < 8):
c.gABC(n, opcNarrowU, dest, TRegister(size*8))
elif t.kind in {tyInt8..tyInt32} or (t.kind == tyInt and size < 8):
c.gABC(n, opcSignExtend, dest, TRegister(size*8))
of mAshrI: genBinaryABC(c, n, dest, opcAshrInt)
of mBitandI: genBinaryABC(c, n, dest, opcBitandInt)
of mBitorI: genBinaryABC(c, n, dest, opcBitorInt)
@@ -1125,8 +1128,9 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
genUnaryABC(c, n, dest, opcBitnotInt)
#genNarrowU modified, do not narrow signed types
let t = skipTypes(n.typ, abstractVar-{tyTypeDesc})
if t.kind in {tyUInt8..tyUInt32} or (t.kind == tyUInt and t.size < 8):
c.gABC(n, opcNarrowU, dest, TRegister(t.size*8))
let size = getSize(c.config, t)
if t.kind in {tyUInt8..tyUInt32} or (t.kind == tyUInt and size < 8):
c.gABC(n, opcNarrowU, dest, TRegister(size*8))
of mCharToStr, mBoolToStr, mIntToStr, mInt64ToStr, mFloatToStr, mCStrToStr, mStrToStr, mEnumToStr:
genConv(c, n, n[1], dest)
of mEqStr, mEqCString: genBinaryABC(c, n, dest, opcEqStr)

View File

@@ -92,7 +92,8 @@ proc storeAny(s: var string; t: PType; a: PNode; stored: var IntSet;
if a[i].kind == nkRange:
var x = copyNode(a[i][0])
storeAny(s, t.lastSon, x, stored, conf)
while x.intVal+1 <= a[i][1].intVal:
inc x.intVal
while x.intVal <= a[i][1].intVal:
s.add(", ")
storeAny(s, t.lastSon, x, stored, conf)
inc x.intVal
@@ -231,7 +232,6 @@ proc loadAny(p: var JsonParser, t: PType,
result = newNode(nkCurly)
while p.kind != jsonArrayEnd and p.kind != jsonEof:
result.add loadAny(p, t.lastSon, tab, cache, conf, idgen)
next(p)
if p.kind == jsonArrayEnd: next(p)
else: raiseParseErr(p, "']' end of array expected")
of tyPtr, tyRef:

View File

@@ -86,7 +86,7 @@ type
wAsmNoStackFrame = "asmNoStackFrame", wImplicitStatic = "implicitStatic",
wGlobal = "global", wCodegenDecl = "codegenDecl", wUnchecked = "unchecked",
wGuard = "guard", wLocks = "locks", wPartial = "partial", wExplain = "explain",
wLiftLocals = "liftlocals",
wLiftLocals = "liftlocals", wEnforceNoRaises = "enforceNoRaises",
wAuto = "auto", wBool = "bool", wCatch = "catch", wChar = "char",
wClass = "class", wCompl = "compl", wConst_cast = "const_cast", wDefault = "default",

View File

@@ -44,10 +44,12 @@ path="$lib/core"
path="$lib/pure"
@if not windows:
nimblepath="/opt/nimble/pkgs2/"
nimblepath="/opt/nimble/pkgs/"
@else:
# TODO:
@end
nimblepath="$home/.nimble/pkgs2/"
nimblepath="$home/.nimble/pkgs/"
# Syncronize with compiler/commands.specialDefine
@@ -154,9 +156,6 @@ nimblepath="$home/.nimble/pkgs/"
# Configuration for the GNU C/C++ compiler:
@if windows:
#gcc.path = r"$nim\dist\mingw\bin"
@if gcc or tcc:
tlsEmulation:on
@end
@end
gcc.maxerrorsimpl = "-fmax-errors=3"

View File

@@ -55,6 +55,11 @@ doc.file = """
%
% Compile it by: xelatex (up to 3 times to get labels generated)
% -------
% For example:
% xelatex file.tex
% xelatex file.tex
% makeindex file
% xelatex file.tex
%
\documentclass[a4paper,11pt]{article}
\usepackage[a4paper,xetex,left=3cm,right=3cm,top=1.5cm,bottom=2cm]{geometry}
@@ -97,7 +102,9 @@ doc.file = """
\usepackage{parskip} % paragraphs delimited by vertical space, no indent
\usepackage{graphicx}
\newcommand{\nimindexterm}[2]{#2\label{#1}}
\usepackage{makeidx}
\newcommand{\nimindexterm}[2]{#2\index{#2}\label{#1}}
\makeindex
\usepackage{dingbat} % for \carriagereturn, etc
\usepackage{fvextra} % for code blocks (works better than original fancyvrb)
@@ -241,5 +248,8 @@ doc.file = """
\maketitle
$content
\printindex
\end{document}
"""

View File

@@ -122,8 +122,9 @@ Advanced options:
--skipUserCfg:on|off do not read the user's configuration file
--skipParentCfg:on|off do not read the parent dirs' configuration files
--skipProjCfg:on|off do not read the project's configuration file
--gc:refc|arc|orc|markAndSweep|boehm|go|none|regions
select the GC to use; default is 'refc'
--mm:orc|arc|refc|markAndSweep|boehm|go|none|regions
select which memory management to use; default is 'refc'
recommended is 'orc'
--exceptions:setjmp|cpp|goto|quirky
select the exception handling implementation
--index:on|off turn index file generation on|off
@@ -134,6 +135,8 @@ Advanced options:
--cppCompileToNamespace:namespace
use the provided namespace for the generated C++ code,
if no namespace is provided "Nim" will be used
--nimMainPrefix:prefix use `{prefix}NimMain` instead of `NimMain` in the produced
C/C++ code
--expandMacro:MACRO dump every generated AST from MACRO
--expandArc:PROCNAME show how PROCNAME looks like after diverse optimizations
before the final backend phase (mostly ARC/ORC specific)
@@ -163,4 +166,4 @@ Advanced options:
--profileVM:on|off turn compile time VM profiler on|off
--sinkInference:on|off turn sink parameter inference on|off (default: on)
--panics:on|off turn panics into process terminations (default: off)
--deepcopy:on|off enable 'system.deepCopy' for ``--gc:arc|orc``
--deepcopy:on|off enable 'system.deepCopy' for ``--mm:arc|orc``

View File

@@ -52,7 +52,7 @@ The commands to compile to either C, C++ or Objective-C are:
The most significant difference between these commands is that if you look
into the ``nimcache`` directory you will find ``.c``, ``.cpp`` or ``.m``
files, other than that all of them will produce a native binary for your
project. This allows you to take the generated code and place it directly
project. This allows you to take the generated code and place it directly
into a project using any of these languages. Here are some typical command-
line invocations:
@@ -105,7 +105,7 @@ file. However, you can also run the code with `nodejs`:idx:
If you experience errors saying that `globalThis` is not defined, be
sure to run a recent version of Node.js (at least 12.0).
Interfacing
===========
@@ -123,7 +123,7 @@ Nim code can interface with the backend through the `Foreign function
interface <manual.html#foreign-function-interface>`_ mainly through the
`importc pragma <manual.html#foreign-function-interface-importc-pragma>`_.
The `importc` pragma is the *generic* way of making backend symbols available
in Nim and is available in all the target backends (JavaScript too). The C++
in Nim and is available in all the target backends (JavaScript too). The C++
or Objective-C backends have their respective `ImportCpp
<manual.html#implementation-specific-pragmas-importcpp-pragma>`_ and
`ImportObjC <manual.html#implementation-specific-pragmas-importobjc-pragma>`_
@@ -246,10 +246,8 @@ Also, C code requires you to specify a forward declaration for functions or
the compiler will assume certain types for the return value and parameters
which will likely make your program crash at runtime.
The Nim compiler can generate a C interface header through the `--header`:option:
command-line switch. The generated header will contain all the exported
symbols and the `NimMain` proc which you need to call before any other
Nim code.
The name `NimMain` can be influenced via the `--nimMainPrefix:prefix` switch.
Use `--nimMainPrefix:MyLib` and the function to call is named `MyLibNimMain`.
Nim invocation example from C
@@ -269,9 +267,10 @@ Create a ``maths.c`` file with the following content:
.. code-block:: c
#include "fib.h"
#include <stdio.h>
extern int fib(int a);
int main(void)
{
NimMain();
@@ -286,13 +285,12 @@ program:
.. code:: cmd
nim c --noMain --noLinking --header:fib.h fib.nim
nim c --noMain --noLinking fib.nim
gcc -o m -I$HOME/.cache/nim/fib_d -Ipath/to/nim/lib $HOME/.cache/nim/fib_d/*.c maths.c
The first command runs the Nim compiler with three special options to avoid
generating a `main()`:c: function in the generated files, avoid linking the
object files into a final binary, and explicitly generate a header file for C
integration. All the generated files are placed into the ``nimcache``
generating a `main()`:c: function in the generated files and to avoid linking the
object files into a final binary. All the generated files are placed into the ``nimcache``
directory. That's why the next command compiles the ``maths.c`` source plus
all the ``.c`` files from ``nimcache``. In addition to this path, you also
have to tell the C compiler where to find Nim's ``nimbase.h`` header file.
@@ -302,12 +300,12 @@ also ask the Nim compiler to generate a statically linked library:
.. code:: cmd
nim c --app:staticLib --noMain --header fib.nim
nim c --app:staticLib --noMain fib.nim
gcc -o m -Inimcache -Ipath/to/nim/lib libfib.nim.a maths.c
The Nim compiler will handle linking the source files generated in the
``nimcache`` directory into the ``libfib.nim.a`` static library, which you can
then link into your C program. Note that these commands are generic and will
then link into your C program. Note that these commands are generic and will
vary for each system. For instance, on Linux systems you will likely need to
use `-ldl`:option: too to link in required dlopen functionality.
@@ -387,14 +385,8 @@ A similar thing happens with C code invoking Nim code which returns a
proc gimme(): cstring {.exportc.} =
result = "Hey there C code! " & $rand(100)
Since Nim's garbage collector is not aware of the C code, once the
Since Nim's reference counting mechanism is not aware of the C code, once the
`gimme` proc has finished it can reclaim the memory of the `cstring`.
However, from a practical standpoint, the C code invoking the `gimme`
function directly will be able to use it since Nim's garbage collector has
not had a chance to run *yet*. This gives you enough time to make a copy for
the C side of the program, as calling any further Nim procs *might* trigger
garbage collection making the previously returned string garbage. Or maybe you
are `yourself triggering the collection <gc.html>`_.
Custom data types
@@ -414,31 +406,3 @@ you can clean it up. And of course, once cleaned you should avoid accessing it
from Nim (or C for that matter). Typically C data structures have their own
`malloc_structure`:c: and `free_structure`:c: specific functions, so wrapping
these for the Nim side should be enough.
Thread coordination
-------------------
When the `NimMain()` function is called Nim initializes the garbage
collector to the current thread, which is usually the main thread of your
application. If your C code later spawns a different thread and calls Nim
code, the garbage collector will fail to work properly and you will crash.
As long as you don't use the threadvar emulation Nim uses native thread
variables, of which you get a fresh version whenever you create a thread. You
can then attach a GC to this thread via
.. code-block:: nim
system.setupForeignThreadGc()
It is **not** safe to disable the garbage collector and enable it after the
call from your background thread even if the code you are calling is short
lived.
Before the thread exits, you should tear down the thread's GC to prevent memory
leaks by calling
.. code-block:: nim
system.tearDownForeignThreadGc()

View File

@@ -27,11 +27,11 @@ Options:
-a, --assertions:on|off turn assertions on|off
--opt:none|speed|size optimize not at all or for speed|size
Note: use -d:release for a release build!
--debugger:native Use native debugger (gdb)
--debugger:native use native debugger (gdb)
--app:console|gui|lib|staticlib
generate a console app|GUI app|DLL|static library
-r, --run run the compiled program with given arguments
--eval:cmd evaluates nim code directly; e.g.: `nim --eval:"echo 1"`
--eval:cmd evaluate nim code directly; e.g.: `nim --eval:"echo 1"`
defaults to `e` (nimscript) but customizable:
`nim r --eval:'for a in stdin.lines: echo a'`
--fullhelp show all command line switches

View File

@@ -43,7 +43,7 @@ written as:
dealloc(x.data)
proc `=trace`[T](x: var myseq[T]; env: pointer) =
# `=trace` allows the cycle collector `--gc:orc`
# `=trace` allows the cycle collector `--mm:orc`
# to understand how to trace the object graph.
if x.data != nil:
for i in 0..<x.len: `=trace`(x.data[i], env)
@@ -208,7 +208,7 @@ by the compiler. Notice that there is no `=` before the `{.error.}` pragma.
`=trace` hook
-------------
A custom **container** type can support Nim's cycle collector `--gc:orc` via
A custom **container** type can support Nim's cycle collector `--mm:orc` via
the `=trace` hook. If the container does not implement `=trace`, cyclic data
structures which are constructed with the help of the container might leak
memory or resources, but memory safety is not compromised.
@@ -224,7 +224,7 @@ to calls of the built-in `=trace` operation.
Usually there will only be a need for a custom `=trace` when a custom `=destroy` that deallocates
manually allocated resources is also used, and then only when there is a chance of cyclic
references from items within the manually allocated resources when it is desired that `--gc:orc`
references from items within the manually allocated resources when it is desired that `--mm:orc`
is able to break and collect these cyclic referenced resources. Currently however, there is a
mutual use problem in that whichever of `=destroy`/`=trace` is used first will automatically
create a version of the other which will then conflict with the creation of the second of the
@@ -256,7 +256,7 @@ The general pattern in using `=destroy` with `=trace` looks like:
# following may be other custom "hooks" as required...
**Note**: The `=trace` hooks (which are only used by `--gc:orc`) are currently more experimental and less refined
**Note**: The `=trace` hooks (which are only used by `--mm:orc`) are currently more experimental and less refined
than the other hooks.
@@ -558,10 +558,10 @@ for expressions of type `lent T` or of type `var T`.
The .cursor annotation
======================
Under the `--gc:arc|orc`:option: modes Nim's `ref` type is implemented
Under the `--mm:arc|orc`:option: modes Nim's `ref` type is implemented
via the same runtime "hooks" and thus via reference counting.
This means that cyclic structures cannot be freed
immediately (`--gc:orc`:option: ships with a cycle collector).
immediately (`--mm:orc`:option: ships with a cycle collector).
With the `.cursor` annotation one can break up cycles declaratively:
.. code-block:: nim

View File

@@ -22,8 +22,8 @@ The documentation consists of several documents:
- | `Tools documentation <tools.html>`_
| Description of some tools that come with the standard distribution.
- | `GC <gc.html>`_
| Additional documentation about Nim's multi-paradigm memory management strategies
- | `Memory management <mm.html>`_
| Additional documentation about Nim's memory management strategies
| and how to operate them in a realtime setting.
- | `Source code filters <filters.html>`_

View File

@@ -6699,11 +6699,11 @@ statement, as seen in stack backtraces:
if not cond:
# change run-time line information of the 'raise' statement:
{.line: instantiationInfo().}:
raise newException(EAssertionFailed, msg)
raise newException(AssertionDefect, msg)
If the `line` pragma is used with a parameter, the parameter needs be a
`tuple[filename: string, line: int]`. If it is used without a parameter,
`system.InstantiationInfo()` is used.
`system.instantiationInfo()` is used.
linearScanEnd pragma

95
doc/mm.rst Normal file
View File

@@ -0,0 +1,95 @@
=======================
Nim's Memory Management
=======================
.. default-role:: code
.. include:: rstcommon.rst
:Author: Andreas Rumpf
:Version: |nimversion|
..
"The road to hell is paved with good intentions."
Multi-paradigm Memory Management Strategies
===========================================
.. default-role:: option
Nim offers multiple different memory management strategies.
To choose the memory management strategy use the `--mm:` switch.
**The recommended switch for newly written Nim code is `--mm:orc`.**
ARC/ORC
-------
`--mm:orc` is a memory management mode primarily based on reference counting. Cycles
in the object graph are handled by a "cycle collector" which is based on "trial deletion".
Since algorithms based on "tracing" are not used, the runtime behavior is oblivious to
the involved heap sizes.
The reference counting operations (= "RC ops") do not use atomic instructions and do not have to --
instead entire subgraphs are *moved* between threads. The Nim compiler also aggressively
optimizes away RC ops and exploits `move semantics <destructors.html#move-semantics>`_.
Nim performs a fair share of optimizations for ARC/ORC; you can inspect what it did
to your time critical function via `--expandArc:functionName`.
`--mm:arc` uses the same mechanism as `--mm:orc`, but it leaves out the cycle collector.
Both ARC and ORC offer deterministic performance for `hard realtime`:idx: systems, but
ARC can be easier to reason about for people coming from Ada/C++/C -- roughly speaking
the memory for a variable is freed when it goes "out of scope".
We generally advise you to use the `acyclic` annotation in order to optimize away the
cycle collector's overhead
but `--mm:orc` also produces more machine code than `--mm:arc`, so if you're on a target
where code size matters and you know that your code does not produce cycles, you can
use `--mm:arc`. Notice that the default `async`:idx: implementation produces cycles
and leaks memory with `--mm:arc`, in other words, for `async` you need to use `--mm:orc`.
Other MM modes
--------------
.. note:: The default `refc` GC is incremental, thread-local and not "stop-the-world".
--mm:refc This is the default memory management strategy. It's a
deferred reference counting based garbage collector
with a simple Mark&Sweep backup GC in order to collect cycles. Heaps are thread-local.
`This document <refc.html>`_ contains further information.
--mm:markAndSweep Simple Mark-And-Sweep based garbage collector.
Heaps are thread-local.
--mm:boehm Boehm based garbage collector, it offers a shared heap.
--mm:go Go's garbage collector, useful for interoperability with Go.
Offers a shared heap.
--mm:none No memory management strategy nor a garbage collector. Allocated memory is
simply never freed. You should use `--mm:arc` instead.
Here is a comparison of the different memory management modes:
================== ======== ================= ============== ===================
Memory Management Heap Reference Cycles Stop-The-World Command line switch
================== ======== ================= ============== ===================
ORC Shared Cycle Collector No `--mm:orc`
ARC Shared Leak No `--mm:arc`
RefC Local Cycle Collector No `--mm:refc`
Mark & Sweep Local Cycle Collector No `--mm:markAndSweep`
Boehm Shared Cycle Collector Yes `--mm:boehm`
Go Shared Cycle Collector Yes `--mm:go`
None Manual Manual Manual `--mm:none`
================== ======== ================= ============== ===================
.. default-role:: code
.. include:: rstcommon.rst
JavaScript's garbage collector is used for the `JavaScript and NodeJS
<backends.html#backends-the-javascript-target>`_ compilation targets.
The `NimScript <nims.html>`_ target uses the memory management strategy built into
the Nim compiler.

View File

@@ -165,6 +165,22 @@ ignored too. `--define:FOO`:option: and `--define:foo`:option: are identical.
Compile-time symbols starting with the `nim` prefix are reserved for the
implementation and should not be used elsewhere.
========================== ============================================
Name Description
========================== ============================================
nimStdSetjmp Use the standard `setjmp()/longjmp()` library
functions for setjmp-based exceptions. This is
the default on most platforms.
nimSigSetjmp Use `sigsetjmp()/siglongjmp()` for setjmp-based exceptions.
nimRawSetjmp Use `_setjmp()/_longjmp()` on POSIX and `_setjmp()/longjmp()`
on Windows, for setjmp-based exceptions. It's the default on
BSDs and BSD-like platforms, where it's significantly faster
than the standard functions.
nimBuiltinSetjmp Use `__builtin_setjmp()/__builtin_longjmp()` for setjmp-based
exceptions. This will not work if an exception is being thrown
and caught inside the same procedure. Useful for benchmarking.
========================== ============================================
Configuration files
-------------------
@@ -371,6 +387,10 @@ of your program.
NimMain() # initialize garbage collector memory, types and stack
The name `NimMain` can be influenced via the `--nimMainPrefix:prefix` switch.
Use `--nimMainPrefix:MyLib` and the function to call is named `MyLibNimMain`.
Cross-compilation for iOS
=========================
@@ -399,6 +419,9 @@ of your program.
Note: XCode's "make clean" gets confused about the generated nim.c files,
so you need to clean those files manually to do a clean build.
The name `NimMain` can be influenced via the `--nimMainPrefix:prefix` switch.
Use `--nimMainPrefix:MyLib` and the function to call is named `MyLibNimMain`.
Cross-compilation for Nintendo Switch
=====================================
@@ -408,13 +431,13 @@ to your usual `nim c`:cmd: or `nim cpp`:cmd: command and set the `passC`:option:
and `passL`:option: command line switches to something like:
.. code-block:: cmd
nim c ... --d:nimAllocPagesViaMalloc --gc:orc --passC="-I$DEVKITPRO/libnx/include" ...
nim c ... --d:nimAllocPagesViaMalloc --mm:orc --passC="-I$DEVKITPRO/libnx/include" ...
--passL="-specs=$DEVKITPRO/libnx/switch.specs -L$DEVKITPRO/libnx/lib -lnx"
or setup a ``nim.cfg`` file like so::
#nim.cfg
--gc:orc
--mm:orc
--d:nimAllocPagesViaMalloc
--passC="-I$DEVKITPRO/libnx/include"
--passL="-specs=$DEVKITPRO/libnx/switch.specs -L$DEVKITPRO/libnx/lib -lnx"
@@ -485,10 +508,10 @@ Define Effect
`useMalloc` Makes Nim use C's `malloc`:idx: instead of Nim's
own memory manager, albeit prefixing each allocation with
its size to support clearing memory on reallocation.
This only works with `--gc:none`:option:,
`--gc:arc`:option: and `--gc:orc`:option:.
This only works with `--mm:none`:option:,
`--mm:arc`:option: and `--mm:orc`:option:.
`useRealtimeGC` Enables support of Nim's GC for *soft* realtime
systems. See the documentation of the `gc <gc.html>`_
systems. See the documentation of the `mm <mm.html>`_
for further information.
`logGC` Enable GC logging to stdout.
`nodejs` The JS target is actually ``node.js``.
@@ -614,9 +637,9 @@ A good start is to use the `any` operating target together with the
.. code:: cmd
nim c --os:any --gc:arc -d:useMalloc [...] x.nim
nim c --os:any --mm:arc -d:useMalloc [...] x.nim
- `--gc:arc`:option: will enable the reference counting memory management instead
- `--mm:arc`:option: will enable the reference counting memory management instead
of the default garbage collector. This enables Nim to use heap memory which
is required for strings and seqs, for example.
@@ -654,13 +677,13 @@ devices. This allocator gets blocks/pages of memory via a currently undocumented
`osalloc` API which usually uses POSIX's `mmap` call. On many environments `mmap`
is not available but C's `malloc` is. You can use the `nimAllocPagesViaMalloc`
define to use `malloc` instead of `mmap`. `nimAllocPagesViaMalloc` is currently
only supported with `--gc:arc` or `--gc:orc`. (Since version 1.6)
only supported with `--mm:arc` or `--mm:orc`. (Since version 1.6)
Nim for realtime systems
========================
See the documentation of Nim's soft realtime `GC <gc.html>`_ for further
See the `--mm:arc` or `--mm:orc` memory management settings in `MM <mm.html>`_ for further
information.

View File

@@ -1,81 +1,3 @@
=======================
Nim's Memory Management
=======================
.. default-role:: code
.. include:: rstcommon.rst
:Author: Andreas Rumpf
:Version: |nimversion|
..
"The road to hell is paved with good intentions."
Introduction
============
A memory-management algorithm optimal for every use-case cannot exist.
Nim provides multiple paradigms for needs ranging from large multi-threaded
applications, to games, hard-realtime systems and small microcontrollers.
This document describes how the management strategies work;
How to tune the garbage collectors for your needs, like (soft) `realtime systems`:idx:,
and how the memory management strategies other than garbage collectors work.
.. note:: the default GC is incremental, thread-local and not "stop-the-world"
Multi-paradigm Memory Management Strategies
===========================================
.. default-role:: option
To choose the memory management strategy use the `--gc:` switch.
--gc:refc This is the default GC. It's a
deferred reference counting based garbage collector
with a simple Mark&Sweep backup GC in order to collect cycles. Heaps are thread-local.
--gc:markAndSweep Simple Mark-And-Sweep based garbage collector.
Heaps are thread-local.
--gc:boehm Boehm based garbage collector, it offers a shared heap.
--gc:go Go's garbage collector, useful for interoperability with Go.
Offers a shared heap.
--gc:arc Plain reference counting with
`move semantic optimizations <destructors.html#move-semantics>`_, offers a shared heap.
It offers deterministic performance for `hard realtime`:idx: systems. Reference cycles
cause memory leaks, beware.
--gc:orc Same as `--gc:arc` but adds a cycle collector based on "trial deletion".
Unfortunately, that makes its performance profile hard to reason about so it is less
useful for hard real-time systems.
--gc:none No memory management strategy nor a garbage collector. Allocated memory is
simply never freed. You should use `--gc:arc` instead.
================== ======== ================= ============== ===================
Memory Management Heap Reference Cycles Stop-The-World Command line switch
================== ======== ================= ============== ===================
RefC Local Cycle Collector No `--gc:refc`
Mark & Sweep Local Cycle Collector No `--gc:markAndSweep`
ARC Shared Leak No `--gc:arc`
ORC Shared Cycle Collector No `--gc:orc`
Boehm Shared Cycle Collector Yes `--gc:boehm`
Go Shared Cycle Collector Yes `--gc:go`
None Manual Manual Manual `--gc:none`
================== ======== ================= ============== ===================
.. default-role:: code
.. include:: rstcommon.rst
JavaScript's garbage collector is used for the `JavaScript and NodeJS
<backends.html#backends-the-javascript-target>`_ compilation targets.
The `NimScript <nims.html>`_ target uses the memory management strategy built into
the Nim compiler.
Tweaking the refc GC
====================
@@ -164,6 +86,35 @@ that up to 100 objects are traversed and freed before it checks again. Thus
highly specialized environments or for older hardware.
Thread coordination
-------------------
When the `NimMain()` function is called Nim initializes the garbage
collector to the current thread, which is usually the main thread of your
application. If your C code later spawns a different thread and calls Nim
code, the garbage collector will fail to work properly and you will crash.
As long as you don't use the threadvar emulation Nim uses native thread
variables, of which you get a fresh version whenever you create a thread. You
can then attach a GC to this thread via
.. code-block:: nim
system.setupForeignThreadGc()
It is **not** safe to disable the garbage collector and enable it after the
call from your background thread even if the code you are calling is short
lived.
Before the thread exits, you should tear down the thread's GC to prevent memory
leaks by calling
.. code-block:: nim
system.tearDownForeignThreadGc()
Keeping track of memory
=======================
@@ -178,7 +129,7 @@ Other useful procs from `system <system.html>`_ you can use to keep track of mem
* `GC_getStatistics()` Garbage collector statistics as a human-readable string.
These numbers are usually only for the running thread, not for the whole heap,
with the exception of `--gc:boehm`:option: and `--gc:go`:option:.
with the exception of `--mm:boehm`:option: and `--mm:go`:option:.
In addition to `GC_ref` and `GC_unref` you can avoid the garbage collector by manually
allocating memory with procs like `alloc`, `alloc0`, `allocShared`, `allocShared0` or `allocCStringArray`.

View File

@@ -604,7 +604,7 @@ proc runCI(cmd: string) =
when not defined(bsd):
if not doUseCpp:
# the BSDs are overwhelmed already, so only run this test on the other machines:
kochExecFold("Boot Nim ORC", "boot -d:release --gc:orc --lib:lib")
kochExecFold("Boot Nim ORC", "boot -d:release --mm:orc --lib:lib")
proc testUnixInstall(cmdLineRest: string) =
csource("-d:danger" & cmdLineRest)

View File

@@ -40,7 +40,7 @@
## can be done by simply searching for [footnoteName].
import strutils, os, hashes, strtabs, rstast, rst, highlite, tables, sequtils,
algorithm, parseutils, std/strbasics
algorithm, parseutils, std/strbasics, strscans
import ../../std/private/since
@@ -406,7 +406,7 @@ proc renderIndexTerm*(d: PDoc, n: PRstNode, result: var string) =
var term = ""
renderAux(d, n, term)
setIndexTerm(d, changeFileExt(extractFilename(d.filename), HtmlExt), id, term, d.currentSection)
dispA(d.target, result, "<span id=\"$1\">$2</span>", "\\nimindexterm{$2}{$1}",
dispA(d.target, result, "<span id=\"$1\">$2</span>", "\\nimindexterm{$1}{$2}",
[id, term])
type
@@ -823,6 +823,16 @@ proc renderOverline(d: PDoc, n: PRstNode, result: var string) =
rstnodeToRefname(n).idS, tmp, $chr(n.level - 1 + ord('A')), tocName])
proc safeProtocol(linkStr: var string) =
var protocol = ""
if scanf(linkStr, "$w:", protocol):
# if it has a protocol at all, ensure that it's not 'javascript:' or worse:
if cmpIgnoreCase(protocol, "http") == 0 or cmpIgnoreCase(protocol, "https") == 0 or
cmpIgnoreCase(protocol, "ftp") == 0:
discard "it's fine"
else:
linkStr = ""
proc renderTocEntry(d: PDoc, e: TocEntry, result: var string) =
dispA(d.target, result,
"<li><a class=\"reference\" id=\"$1_toc\" href=\"#$1\">$2</a></li>\n",
@@ -887,6 +897,8 @@ proc renderImage(d: PDoc, n: PRstNode, result: var string) =
# support for `:target:` links for images:
var target = esc(d.target, getFieldValue(n, "target").strip(), escMode=emUrl)
safeProtocol(target)
if target.len > 0:
# `htmlOut` needs to be of the following format for link to work for images:
# <a class="reference external" href="target"><img src=\"$1\"$2/></a>
@@ -1187,6 +1199,7 @@ proc renderHyperlink(d: PDoc, text, link: PRstNode, result: var string, external
d.escMode = emUrl
renderRstToOut(d, link, linkStr)
d.escMode = mode
safeProtocol(linkStr)
var textStr = ""
renderRstToOut(d, text, textStr)
if external:

View File

@@ -733,7 +733,7 @@ when defined(windows) or defined(nimdoc):
proc acceptAddr*(socket: AsyncFD, flags = {SocketFlag.SafeDisconn},
inheritable = defined(nimInheritHandles)):
owned(Future[tuple[address: string, client: AsyncFD]]) =
owned(Future[tuple[address: string, client: AsyncFD]]) {.gcsafe.} =
## Accepts a new connection. Returns a future containing the client socket
## corresponding to that connection and the remote address of the client.
## The future will complete when the connection is successfully accepted.
@@ -800,7 +800,7 @@ when defined(windows) or defined(nimdoc):
var ol = newCustom()
ol.data = CompletionData(fd: socket, cb:
proc (fd: AsyncFD, bytesCount: DWORD, errcode: OSErrorCode) =
proc (fd: AsyncFD, bytesCount: DWORD, errcode: OSErrorCode) {.gcsafe.} =
if not retFuture.finished:
if errcode == OSErrorCode(-1):
completeAccept()

View File

@@ -87,20 +87,6 @@ proc initDeque*[T](initialSize: int = defaultInitialSize): Deque[T] =
## * `toDeque proc <#toDeque,openArray[T]>`_
result.initImpl(initialSize)
proc toDeque*[T](x: openArray[T]): Deque[T] {.since: (1, 3).} =
## Creates a new deque that contains the elements of `x` (in the same order).
##
## **See also:**
## * `initDeque proc <#initDeque,int>`_
runnableExamples:
let a = toDeque([7, 8, 9])
assert len(a) == 3
assert $a == "[7, 8, 9]"
result.initImpl(x.len)
for item in items(x):
result.addLast(item)
proc len*[T](deq: Deque[T]): int {.inline.} =
## Returns the number of elements of `deq`.
result = deq.count
@@ -303,6 +289,20 @@ proc addLast*[T](deq: var Deque[T], item: sink T) =
deq.data[deq.tail] = item
deq.tail = (deq.tail + 1) and deq.mask
proc toDeque*[T](x: openArray[T]): Deque[T] {.since: (1, 3).} =
## Creates a new deque that contains the elements of `x` (in the same order).
##
## **See also:**
## * `initDeque proc <#initDeque,int>`_
runnableExamples:
let a = toDeque([7, 8, 9])
assert len(a) == 3
assert $a == "[7, 8, 9]"
result.initImpl(x.len)
for item in items(x):
result.addLast(item)
proc peekFirst*[T](deq: Deque[T]): lent T {.inline.} =
## Returns the first element of `deq`, but does not remove it from the deque.
##

View File

@@ -353,8 +353,8 @@ const
("lightcoral", colLightCoral),
("lightcyan", colLightCyan),
("lightgoldenrodyellow", colLightGoldenRodYellow),
("lightgrey", colLightGrey),
("lightgreen", colLightGreen),
("lightgrey", colLightGrey),
("lightpink", colLightPink),
("lightsalmon", colLightSalmon),
("lightseagreen", colLightSeaGreen),

View File

@@ -202,6 +202,8 @@ type
of JArray:
elems*: seq[JsonNode]
const DepthLimit = 1000
proc newJString*(s: string): JsonNode =
## Creates a new `JString JsonNode`.
result = JsonNode(kind: JString, str: s)
@@ -437,7 +439,7 @@ macro `%*`*(x: untyped): untyped =
## `%` for every element.
result = toJsonImpl(x)
proc `==`*(a, b: JsonNode): bool =
proc `==`*(a, b: JsonNode): bool {.noSideEffect.} =
## Check two nodes for equality
if a.isNil:
if b.isNil: return true
@@ -464,12 +466,16 @@ proc `==`*(a, b: JsonNode): bool =
if a.fields.len != b.fields.len: return false
for key, val in a.fields:
if not b.fields.hasKey(key): return false
if b.fields[key] != val: return false
when defined(nimHasEffectsOf):
{.noSideEffect.}:
if b.fields[key] != val: return false
else:
if b.fields[key] != val: return false
result = true
proc hash*(n: OrderedTable[string, JsonNode]): Hash {.noSideEffect.}
proc hash*(n: JsonNode): Hash =
proc hash*(n: JsonNode): Hash {.noSideEffect.} =
## Compute the hash for a JSON node
case n.kind
of JArray:
@@ -845,7 +851,7 @@ iterator mpairs*(node: var JsonNode): tuple[key: string, val: var JsonNode] =
for key, val in mpairs(node.fields):
yield (key, val)
proc parseJson(p: var JsonParser; rawIntegers, rawFloats: bool): JsonNode =
proc parseJson(p: var JsonParser; rawIntegers, rawFloats: bool, depth = 0): JsonNode =
## Parses JSON from a JSON Parser `p`.
case p.tok
of tkString:
@@ -881,6 +887,8 @@ proc parseJson(p: var JsonParser; rawIntegers, rawFloats: bool): JsonNode =
result = newJNull()
discard getTok(p)
of tkCurlyLe:
if depth > DepthLimit:
raiseParseErr(p, "}")
result = newJObject()
discard getTok(p)
while p.tok != tkCurlyRi:
@@ -889,16 +897,18 @@ proc parseJson(p: var JsonParser; rawIntegers, rawFloats: bool): JsonNode =
var key = p.a
discard getTok(p)
eat(p, tkColon)
var val = parseJson(p, rawIntegers, rawFloats)
var val = parseJson(p, rawIntegers, rawFloats, depth+1)
result[key] = val
if p.tok != tkComma: break
discard getTok(p)
eat(p, tkCurlyRi)
of tkBracketLe:
if depth > DepthLimit:
raiseParseErr(p, "]")
result = newJArray()
discard getTok(p)
while p.tok != tkBracketRi:
result.add(parseJson(p, rawIntegers, rawFloats))
result.add(parseJson(p, rawIntegers, rawFloats, depth+1))
if p.tok != tkComma: break
discard getTok(p)
eat(p, tkBracketRi)

View File

@@ -3263,7 +3263,11 @@ template rawToFormalFileInfo(rawInfo, path, formalInfo): untyped =
## 'rawInfo' is either a 'BY_HANDLE_FILE_INFORMATION' structure on Windows,
## or a 'Stat' structure on posix
when defined(windows):
template merge(a, b): untyped = a or (b shl 32)
template merge(a, b): untyped =
int64(
(uint64(cast[uint32](a))) or
(uint64(cast[uint32](b)) shl 32)
)
formalInfo.id.device = rawInfo.dwVolumeSerialNumber
formalInfo.id.file = merge(rawInfo.nFileIndexLow, rawInfo.nFileIndexHigh)
formalInfo.size = merge(rawInfo.nFileSizeLow, rawInfo.nFileSizeHigh)

View File

@@ -216,6 +216,8 @@ func parseAuthority(authority: string, result: var Uri) =
result.isIpv6 = true
of ']':
inIPv6 = false
of '\0':
break
else:
if inPort:
result.port.add(authority[i])

View File

@@ -78,14 +78,17 @@ func addIntImpl(result: var string, x: uint64) {.inline.} =
dec next
addChars(result, tmp, next, tmp.len - next)
func addInt*(result: var string, x: uint64) =
when not defined(nimHasEnforceNoRaises):
{.pragma: enforceNoRaises.}
func addInt*(result: var string, x: uint64) {.enforceNoRaises.} =
when nimvm: addIntImpl(result, x)
else:
when not defined(js): addIntImpl(result, x)
else:
addChars(result, numToString(x))
proc addInt*(result: var string; x: int64) =
proc addInt*(result: var string; x: int64) {.enforceNoRaises.} =
## Converts integer to its string representation and appends it to `result`.
runnableExamples:
var s = "foo"
@@ -110,5 +113,5 @@ proc addInt*(result: var string; x: int64) =
addChars(result, numToString(x))
else: impl()
proc addInt*(result: var string; x: int) {.inline.} =
proc addInt*(result: var string; x: int) {.inline, enforceNoRaises.} =
addInt(result, int64(x))

View File

@@ -38,6 +38,11 @@
## .. _randomFillSync: https://nodejs.org/api/crypto.html#crypto_crypto_randomfillsync_buffer_offset_size
## .. _/dev/urandom: https://en.wikipedia.org/wiki//dev/random
##
## On a Linux target, a call to the `getrandom` syscall can be avoided (e.g.
## for targets running kernel version < 3.17) by passing a compile flag of
## `-d:nimNoGetRandom`. If this flag is passed, sysrand will use `/dev/urandom`
## as with any other POSIX compliant OS.
##
runnableExamples:
doAssert urandom(0).len == 0
@@ -159,7 +164,7 @@ elif defined(windows):
result = randomBytes(addr dest[0], size)
elif defined(linux):
elif defined(linux) and not defined(nimNoGetRandom) and not defined(emscripten):
# TODO using let, pending bootstrap >= 1.4.0
var SYS_getrandom {.importc: "SYS_getrandom", header: "<sys/syscall.h>".}: clong
const syscallHeader = """#include <unistd.h>

View File

@@ -2121,11 +2121,11 @@ const
## when (NimMajor, NimMinor, NimPatch) >= (1, 3, 1): discard
# see also std/private/since
NimMinor* {.intdefine.}: int = 5
NimMinor* {.intdefine.}: int = 6
## is the minor number of Nim's version.
## Odd for devel, even for releases.
NimPatch* {.intdefine.}: int = 1
NimPatch* {.intdefine.}: int = 2
## is the patch number of Nim's version.
## Odd for devel, even for releases.

View File

@@ -31,7 +31,10 @@ proc c_abort*() {.
importc: "abort", header: "<stdlib.h>", noSideEffect, noreturn.}
when defined(linux) and defined(amd64):
when defined(nimBuiltinSetjmp):
type
C_JmpBuf* = array[5, pointer]
elif defined(linux) and defined(amd64):
type
C_JmpBuf* {.importc: "jmp_buf", header: "<setjmp.h>", bycopy.} = object
abi: array[200 div sizeof(clong), clong]
@@ -92,18 +95,47 @@ when defined(macosx):
elif defined(haiku):
const SIGBUS* = cint(30)
when defined(nimSigSetjmp) and not defined(nimStdSetjmp):
# "nimRawSetjmp" is defined by default for certain platforms, so we need the
# "nimStdSetjmp" escape hatch with it.
when defined(nimSigSetjmp):
proc c_longjmp*(jmpb: C_JmpBuf, retval: cint) {.
header: "<setjmp.h>", importc: "siglongjmp".}
template c_setjmp*(jmpb: C_JmpBuf): cint =
proc c_setjmp*(jmpb: C_JmpBuf): cint =
proc c_sigsetjmp(jmpb: C_JmpBuf, savemask: cint): cint {.
header: "<setjmp.h>", importc: "sigsetjmp".}
c_sigsetjmp(jmpb, 0)
elif defined(nimBuiltinSetjmp):
proc c_longjmp*(jmpb: C_JmpBuf, retval: cint) =
# Apple's Clang++ has trouble converting array names to pointers, so we need
# to be very explicit here.
proc c_builtin_longjmp(jmpb: ptr pointer, retval: cint) {.
importc: "__builtin_longjmp", nodecl.}
# The second parameter needs to be 1 and sometimes the C/C++ compiler checks it.
c_builtin_longjmp(unsafeAddr jmpb[0], 1)
proc c_setjmp*(jmpb: C_JmpBuf): cint =
proc c_builtin_setjmp(jmpb: ptr pointer): cint {.
importc: "__builtin_setjmp", nodecl.}
c_builtin_setjmp(unsafeAddr jmpb[0])
elif defined(nimRawSetjmp) and not defined(nimStdSetjmp):
proc c_longjmp*(jmpb: C_JmpBuf, retval: cint) {.
header: "<setjmp.h>", importc: "_longjmp".}
proc c_setjmp*(jmpb: C_JmpBuf): cint {.
header: "<setjmp.h>", importc: "_setjmp".}
when defined(windows):
# No `_longjmp()` on Windows.
proc c_longjmp*(jmpb: C_JmpBuf, retval: cint) {.
header: "<setjmp.h>", importc: "longjmp".}
# The Windows `_setjmp()` takes two arguments, with the second being an
# undocumented buffer used by the SEH mechanism for stack unwinding.
# Mingw-w64 has been trying to get it right for years, but it's still
# prone to stack corruption during unwinding, so we disable that by setting
# it to NULL.
# More details: https://github.com/status-im/nimbus-eth2/issues/3121
proc c_setjmp*(jmpb: C_JmpBuf): cint =
proc c_setjmp_win(jmpb: C_JmpBuf, ctx: pointer): cint {.
header: "<setjmp.h>", importc: "_setjmp".}
c_setjmp_win(jmpb, nil)
else:
proc c_longjmp*(jmpb: C_JmpBuf, retval: cint) {.
header: "<setjmp.h>", importc: "_longjmp".}
proc c_setjmp*(jmpb: C_JmpBuf): cint {.
header: "<setjmp.h>", importc: "_setjmp".}
else:
proc c_longjmp*(jmpb: C_JmpBuf, retval: cint) {.
header: "<setjmp.h>", importc: "longjmp".}

View File

@@ -354,7 +354,7 @@ var onUnhandledException*: (proc (errorMsg: string) {.
## The default is to write a stacktrace to `stderr` and then call `quit(1)`.
## Unstable API.
proc reportUnhandledErrorAux(e: ref Exception) {.nodestroy.} =
proc reportUnhandledErrorAux(e: ref Exception) {.nodestroy, gcsafe.} =
when hasSomeStackTrace:
var buf = newStringOfCap(2000)
if e.trace.len == 0:
@@ -362,7 +362,8 @@ proc reportUnhandledErrorAux(e: ref Exception) {.nodestroy.} =
else:
var trace = $e.trace
add(buf, trace)
`=destroy`(trace)
{.gcsafe.}:
`=destroy`(trace)
add(buf, "Error: unhandled exception: ")
add(buf, e.msg)
add(buf, " [")
@@ -373,7 +374,8 @@ proc reportUnhandledErrorAux(e: ref Exception) {.nodestroy.} =
onUnhandledException(buf)
else:
showErrorMessage2(buf)
`=destroy`(buf)
{.gcsafe.}:
`=destroy`(buf)
else:
# ugly, but avoids heap allocations :-)
template xadd(buf, s, slen) =
@@ -387,7 +389,8 @@ proc reportUnhandledErrorAux(e: ref Exception) {.nodestroy.} =
if e.trace.len != 0:
var trace = $e.trace
add(buf, trace)
`=destroy`(trace)
{.gcsafe.}:
`=destroy`(trace)
add(buf, "Error: unhandled exception: ")
add(buf, e.msg)
add(buf, " [")
@@ -398,7 +401,7 @@ proc reportUnhandledErrorAux(e: ref Exception) {.nodestroy.} =
else:
showErrorMessage(buf.addr, L)
proc reportUnhandledError(e: ref Exception) {.nodestroy.} =
proc reportUnhandledError(e: ref Exception) {.nodestroy, gcsafe.} =
if unhandledExceptionHook != nil:
unhandledExceptionHook(e)
when hostOS != "any":

View File

@@ -73,7 +73,7 @@ proc prepareSeqAdd(len: int; p: pointer; addlen, elemSize, elemAlign: int): poin
q.cap = newCap
result = q
proc shrink*[T](x: var seq[T]; newLen: Natural) =
proc shrink*[T](x: var seq[T]; newLen: Natural) {.tags: [], raises: [].} =
when nimvm:
setLen(x, newLen)
else:

View File

@@ -51,7 +51,7 @@ pkg "cascade"
pkg "cello"
pkg "chroma"
pkg "chronicles", "nim c -o:chr -r chronicles.nim"
pkg "chronos", "nim c -r -d:release tests/testall", allowFailure = true # pending https://github.com/nim-lang/Nim/issues/17130
pkg "chronos", "nim c -r -d:release tests/testall"
pkg "cligen", "nim c --path:. -r cligen.nim"
pkg "combparser", "nimble test --gc:orc"
pkg "compactdict"

10
tests/arc/t18971.nim Normal file
View File

@@ -0,0 +1,10 @@
discard """
cmd: "nim c --gc:arc $file"
"""
type MyObj = ref object
var o = MyObj()
proc x: var MyObj = o
var o2 = x()

View File

@@ -30,6 +30,7 @@ ok
true
copying
123
42
closed
destroying variable: 20
destroying variable: 10
@@ -482,3 +483,17 @@ method testMethod(self: BrokenObject) {.base.} =
let mikasa = BrokenObject()
mikasa.testMethod()
# bug #19205
type
InputSectionBase* = object of RootObj
relocations*: seq[int] # traced reference. string has a similar SIGSEGV.
InputSection* = object of InputSectionBase
proc fooz(sec: var InputSectionBase) =
if sec of InputSection: # this line SIGSEGV.
echo 42
var sec = create(InputSection)
sec[] = InputSection(relocations: newSeq[int]())
fooz sec[]

View File

@@ -1,6 +1,7 @@
discard """
output: '''@[(s1: "333", s2: ""), (s1: "abc", s2: "def"), (s1: "3x", s2: ""), (s1: "3x", s2: ""), (s1: "3x", s2: ""), (s1: "3x", s2: ""), (s1: "lastone", s2: "")]'''
cmd: "nim c --gc:arc $file"
matrix: "--gc:arc"
targets: "c cpp"
"""
# bug #13240

View File

@@ -1,6 +1,7 @@
discard """
cmd: "nim c -d:release $file"
output: 1
output: '''1
-1'''
"""
proc bug() : void =
@@ -12,3 +13,9 @@ proc bug() : void =
echo x
bug()
# bug #19051
type GInt[T] = int
var a = 1
echo -a

View File

@@ -4,7 +4,11 @@ discard """
import marshal
let orig: set[char] = {'A'..'Z'}
let m = $$orig
let old = to[set[char]](m)
doAssert orig - old == {}
template main() =
let orig: set[char] = {'A'..'Z'}
let m = $$orig
let old = to[set[char]](m)
doAssert orig - old == {}
static: main()
main()

View File

@@ -0,0 +1,3 @@
converter toBool(x: uint32): bool = x != 0
# Note: This convertes is not exported!

View File

@@ -0,0 +1,10 @@
discard """
output: '''5'''
joinable: false
"""
import mdontleak
# bug #19213
let a = 5'u32
echo a

15
tests/cpp/torc.nim Normal file
View File

@@ -0,0 +1,15 @@
discard """
targets: "cpp"
matrix: "--gc:orc"
"""
import std/options
# bug #18410
type
O = object of RootObj
val: pointer
proc p(): Option[O] = none(O)
doAssert $p() == "none(O)"

View File

@@ -0,0 +1,63 @@
discard """
cmd: "nim check --hints:off $file"
nimout: '''tnestedprocs.nim(27, 8) Error: 'inner' can have side effects
> tnestedprocs.nim(29, 13) Hint: 'inner' calls `.sideEffect` 'outer2'
>> tnestedprocs.nim(26, 6) Hint: 'outer2' called by 'inner'
tnestedprocs.nim(45, 8) Error: 'inner' can have side effects
> tnestedprocs.nim(47, 13) Hint: 'inner' calls `.sideEffect` 'outer6'
>> tnestedprocs.nim(44, 6) Hint: 'outer6' called by 'inner'
tnestedprocs.nim(58, 41) Error: type mismatch: got <proc ()> but expected 'proc (){.closure, noSideEffect.}'
Pragma mismatch: got '{..}', but expected '{.noSideEffect.}'.
'''
errormsg: "type mismatch: got <proc ()> but expected 'proc (){.closure, noSideEffect.}'"
"""
{.experimental: "strictEffects".}
proc outer {.noSideEffect.} =
proc inner(p: int) =
if p == 0:
outer()
inner(4)
outer()
proc outer2 =
proc inner(p: int) {.noSideEffect.} =
if p == 0:
outer2()
inner(4)
outer2()
proc outer3(p: int) {.noSideEffect.} =
proc inner(p: int) {.noSideEffect.} =
if p == 0:
p.outer3()
inner(4)
outer3(5)
proc outer6 =
proc inner(p: int) {.noSideEffect.} =
if p == 0:
outer6()
inner(4)
echo "bad"
outer6()
proc outer4 =
proc inner(p: int) {.noSideEffect.} =
if p == 0:
let x: proc () {.noSideEffect.} = outer4
x()
inner(4)
outer4()

View File

@@ -15,3 +15,15 @@ proc fn(a: int, p1, p2: proc()) {.effectsOf: p1.} =
proc main() {.raises: [ValueError].} =
fn(1, proc()=discard, proc() = raise newException(IOError, "foo"))
main()
# bug #19159
import macros
func mkEnter() =
template helper =
discard
when defined pass:
helper()
else:
let ast = getAst(helper())

View File

@@ -1,4 +1,6 @@
discard """
disabled: "windows" # no sigsetjmp() there
matrix: "-d:nimStdSetjmp; -d:nimSigSetjmp; -d:nimRawSetjmp; -d:nimBuiltinSetjmp"
output: '''
BEFORE
@@ -17,7 +19,7 @@ FINALLY
echo ""
proc no_expcetion =
proc no_exception =
try:
echo "BEFORE"
@@ -28,7 +30,7 @@ proc no_expcetion =
finally:
echo "FINALLY"
try: no_expcetion()
try: no_exception()
except: echo "RECOVER"
echo ""

View File

@@ -0,0 +1,130 @@
discard """
disabled: "posix" # already covered by texceptions.nim
matrix: "-d:nimStdSetjmp; -d:nimRawSetjmp; -d:nimBuiltinSetjmp"
output: '''
BEFORE
FINALLY
BEFORE
EXCEPT
FINALLY
RECOVER
BEFORE
EXCEPT: IOError: hi
FINALLY
'''
"""
echo ""
proc no_exception =
try:
echo "BEFORE"
except:
echo "EXCEPT"
raise
finally:
echo "FINALLY"
try: no_exception()
except: echo "RECOVER"
echo ""
proc reraise_in_except =
try:
echo "BEFORE"
raise newException(IOError, "")
except IOError:
echo "EXCEPT"
raise
finally:
echo "FINALLY"
try: reraise_in_except()
except: echo "RECOVER"
echo ""
proc return_in_except =
try:
echo "BEFORE"
raise newException(IOError, "hi")
except:
echo "EXCEPT: ", getCurrentException().name, ": ", getCurrentExceptionMsg()
return
finally:
echo "FINALLY"
try: return_in_except()
except: echo "RECOVER"
block: #10417
proc moo() {.noreturn.} = discard
let bar =
try:
1
except:
moo()
doAssert(bar == 1)
# Make sure the VM handles the exceptions correctly
block:
proc fun1(): seq[int] =
try:
try:
raise newException(ValueError, "xx")
except:
doAssert("xx" == getCurrentExceptionMsg())
raise newException(KeyError, "yy")
except:
doAssert("yy" == getCurrentExceptionMsg())
result.add(1212)
try:
try:
raise newException(AssertionDefect, "a")
finally:
result.add(42)
except AssertionDefect:
result.add(99)
finally:
result.add(10)
result.add(4)
result.add(0)
try:
result.add(1)
except KeyError:
result.add(-1)
except ValueError:
result.add(-1)
except IndexDefect:
result.add(2)
except:
result.add(3)
try:
try:
result.add(1)
return
except:
result.add(-1)
finally:
result.add(2)
except KeyError:
doAssert(false)
finally:
result.add(3)
let x1 = fun1()
const x2 = fun1()
doAssert(x1 == x2)

View File

@@ -0,0 +1,22 @@
discard """
errormsg: "expression cannot be isolated: a_to_b(a)"
line: 22
"""
# bug #19013
import std/isolation
type Z = ref object
i: int
type A = object
z: Z
type B = object
z: Z
func a_to_b(a: A): B =
result = B(z: a.z)
let a = A(z: Z(i: 3))
let b = isolate(a_to_b(a))

View File

@@ -1,3 +1,6 @@
{.experimental: "flexibleOptionalParams".}
# https://github.com/nim-lang/RFCs/issues/405
template main =

View File

@@ -1,5 +1,6 @@
discard """
output: '''34'''
joinable: false
"""
{.compile("cfunction.c", "-DNUMBER_HERE=34").}

View File

@@ -0,0 +1,2 @@
type Foo = distinct uint64
const slice = 0 ..< 42.Foo

View File

@@ -345,3 +345,35 @@ block:
doAssert c == "18446744073709552000"
else:
doAssert c == "18446744073709551615"
block:
let a = """
[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
"""
when not defined(js):
try:
discard parseJson(a)
except JsonParsingError:
doAssert getCurrentExceptionMsg().contains("] expected")

View File

@@ -398,7 +398,7 @@ Some chapter
Level2
------
Level3
~~~~~~
@@ -407,7 +407,7 @@ Some chapter
More
~~~~
Another
-------
@@ -683,7 +683,7 @@ Test1
test "RST line blocks":
let input2 = dedent"""
Paragraph1
|
Paragraph2"""
@@ -704,7 +704,7 @@ Test1
# check that '| ' with a few spaces is still parsed as new line
let input4 = dedent"""
| xxx
|
|
| zzz"""
let output4 = input4.toHtml
@@ -1548,3 +1548,30 @@ suite "RST/Code highlight":
check strip(rstToHtml(pythonCode, {}, newStringTable(modeCaseSensitive))) ==
strip(expected)
suite "invalid targets":
test "invalid image target":
let input1 = dedent """.. image:: /images/myimage.jpg
:target: https://bar.com
:alt: Alt text for the image"""
let output1 = input1.toHtml
check output1 == """<a class="reference external" href="https://bar.com"><img src="/images/myimage.jpg" alt="Alt text for the image"/></a>"""
let input2 = dedent """.. image:: /images/myimage.jpg
:target: javascript://bar.com
:alt: Alt text for the image"""
let output2 = input2.toHtml
check output2 == """<img src="/images/myimage.jpg" alt="Alt text for the image"/>"""
let input3 = dedent """.. image:: /images/myimage.jpg
:target: bar.com
:alt: Alt text for the image"""
let output3 = input3.toHtml
check output3 == """<a class="reference external" href="bar.com"><img src="/images/myimage.jpg" alt="Alt text for the image"/></a>"""
test "invalid links":
check("(([Nim](https://nim-lang.org/)))".toHtml ==
"""((<a class="reference external" href="https://nim-lang.org/">Nim</a>))""")
check("(([Nim](javascript://nim-lang.org/)))".toHtml ==
"""((<a class="reference external" href="">Nim</a>))""")

View File

@@ -290,10 +290,10 @@ block: # bug #10815
const a = P()
doAssert $a == ""
when defined osx: # xxx bug https://github.com/nim-lang/Nim/issues/10815#issuecomment-476380734
block:
type CharSet {.union.} = object
type CharSet {.union.} = object
cs: set[char]
vs: array[4, uint64]
const a = Charset(cs: {'a'..'z'})
@@ -553,3 +553,22 @@ block: # bug #8015
doAssert $viaProc.table[0] == "(kind: Fixed, cost: 999)"
doAssert viaProc.table[1].handler() == 100
doAssert viaProc.table[2].handler() == 200
# bug #19198
block:
type
Foo[n: static int] = int
block:
static:
let x = int 1
echo x.type # Foo
block:
static:
let x = int 1
let y = x + 1
# Error: unhandled exception: value out of range: -8 notin 0 .. 65535 [RangeDefect]
echo y

View File

@@ -126,7 +126,7 @@ tut2.rst
tut3.rst
nimc.rst
niminst.rst
gc.rst
mm.rst
""".splitWhitespace().mapIt("doc" / it)
doc0 = """
@@ -298,6 +298,12 @@ proc nim2pdf(src: string, dst: string, nimArgs: string) =
# `>` should work on windows, if not, we can use `execCmdEx`
let cmd = "xelatex -interaction=nonstopmode -output-directory=$# $# > $#" % [outDir.quoteShell, texFile.quoteShell, xelatexLog.quoteShell]
exec(cmd) # on error, user can inspect `xelatexLog`
if i == 1: # build .ind file
var texFileBase = texFile
texFileBase.removeSuffix(".tex")
let cmd = "makeindex $# > $#" % [
texFileBase.quoteShell, xelatexLog.quoteShell]
exec(cmd)
moveFile(texFile.changeFileExt("pdf"), dst)
proc buildPdfDoc*(nimArgs, destPath: string) =