diff --git a/compiler/ccgcalls.nim b/compiler/ccgcalls.nim index 5dc6b39a6b87..607f6d51e64b 100644 --- a/compiler/ccgcalls.nim +++ b/compiler/ccgcalls.nim @@ -84,6 +84,10 @@ proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc, # getUniqueType() is too expensive here: var typ = skipTypes(ri[0].typ, abstractInst) if typ.returnType != nil: + var flags: TAssignmentFlags = {} + if typ.returnType.kind in {tyOpenArray, tyVarargs}: + # perhaps generate no temp if the call doesn't have side effects + flags.incl needTempForOpenArray if isInvalidReturnType(p.config, typ): if params.len != 0: pl.add(", ") # beware of 'result = p(result)'. We may need to allocate a temporary: @@ -128,13 +132,13 @@ proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc, assert(d.t != nil) # generate an assignment to d: var list = initLoc(locCall, d.lode, OnUnknown) list.r = pl - genAssignment(p, d, list, {}) # no need for deep copying + genAssignment(p, d, list, flags) # no need for deep copying if canRaise: raiseExit(p) else: var tmp: TLoc = getTemp(p, typ.returnType, needsInit=true) var list = initLoc(locCall, d.lode, OnUnknown) list.r = pl - genAssignment(p, tmp, list, {}) # no need for deep copying + genAssignment(p, tmp, list, flags) # no need for deep copying if canRaise: raiseExit(p) genAssignment(p, d, tmp, {}) else: diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 17e0da57558b..66a4d9a930fb 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -285,15 +285,22 @@ proc genGenericAsgn(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) = linefmt(p, cpsStmts, "#genericAssign((void*)$1, (void*)$2, $3);$n", [addrLoc(p.config, dest), addrLoc(p.config, src), genTypeInfoV1(p.module, dest.t, dest.lode.info)]) -proc genOpenArrayConv(p: BProc; d: TLoc; a: TLoc) = +proc genOpenArrayConv(p: BProc; d: TLoc; a: TLoc; flags: TAssignmentFlags) = assert d.k != locNone # getTemp(p, d.t, d) case a.t.skipTypes(abstractVar).kind of tyOpenArray, tyVarargs: if reifiedOpenArray(a.lode): - linefmt(p, cpsStmts, "$1.Field0 = $2.Field0; $1.Field1 = $2.Field1;$n", - [rdLoc(d), a.rdLoc]) + if needTempForOpenArray in flags: + var tmp: TLoc = getTemp(p, a.t) + linefmt(p, cpsStmts, "$2 = $1; $n", + [a.rdLoc, tmp.rdLoc]) + linefmt(p, cpsStmts, "$1.Field0 = $2.Field0; $1.Field1 = $2.Field1;$n", + [rdLoc(d), tmp.rdLoc]) + else: + linefmt(p, cpsStmts, "$1.Field0 = $2.Field0; $1.Field1 = $2.Field1;$n", + [rdLoc(d), a.rdLoc]) else: linefmt(p, cpsStmts, "$1.Field0 = $2; $1.Field1 = $2Len_0;$n", [rdLoc(d), a.rdLoc]) @@ -391,7 +398,7 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) = # open arrays are always on the stack - really? What if a sequence is # passed to an open array? if reifiedOpenArray(dest.lode): - genOpenArrayConv(p, dest, src) + genOpenArrayConv(p, dest, src, flags) elif containsGarbageCollectedRef(dest.t): linefmt(p, cpsStmts, # XXX: is this correct for arrays? "#genericAssignOpenArray((void*)$1, (void*)$2, $1Len_0, $3);$n", diff --git a/compiler/cgen.nim b/compiler/cgen.nim index b18ddb63cb21..3c309db989de 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -406,6 +406,7 @@ proc rdCharLoc(a: TLoc): Rope = type TAssignmentFlag = enum needToCopy + needTempForOpenArray TAssignmentFlags = set[TAssignmentFlag] proc genObjConstr(p: BProc, e: PNode, d: var TLoc) @@ -1032,7 +1033,7 @@ proc easyResultAsgn(n: PNode): PNode = type InitResultEnum = enum Unknown, InitSkippable, InitRequired -proc allPathsAsgnResult(n: PNode): InitResultEnum = +proc allPathsAsgnResult(p: BProc; n: PNode): InitResultEnum = # Exceptions coming from calls don't have not be considered here: # # proc bar(): string = raise newException(...) @@ -1047,7 +1048,7 @@ proc allPathsAsgnResult(n: PNode): InitResultEnum = # echo "a was not written to" # template allPathsInBranch(it) = - let a = allPathsAsgnResult(it) + let a = allPathsAsgnResult(p, it) case a of InitRequired: return InitRequired of InitSkippable: discard @@ -1059,7 +1060,7 @@ proc allPathsAsgnResult(n: PNode): InitResultEnum = case n.kind of nkStmtList, nkStmtListExpr: for it in n: - result = allPathsAsgnResult(it) + result = allPathsAsgnResult(p, it) if result != Unknown: return result of nkAsgn, nkFastAsgn, nkSinkAsgn: if n[0].kind == nkSym and n[0].sym.kind == skResult: @@ -1067,6 +1068,8 @@ proc allPathsAsgnResult(n: PNode): InitResultEnum = else: result = InitRequired elif containsResult(n): result = InitRequired + else: + result = allPathsAsgnResult(p, n[1]) of nkReturnStmt: if n.len > 0: if n[0].kind == nkEmpty and result != InitSkippable: @@ -1075,7 +1078,7 @@ proc allPathsAsgnResult(n: PNode): InitResultEnum = # initialized. This avoids cases like #9286 where this heuristic lead to # wrong code being generated. result = InitRequired - else: result = allPathsAsgnResult(n[0]) + else: result = allPathsAsgnResult(p, n[0]) of nkIfStmt, nkIfExpr: var exhaustive = false result = InitSkippable @@ -1101,9 +1104,9 @@ proc allPathsAsgnResult(n: PNode): InitResultEnum = of nkWhileStmt: # some dubious code can assign the result in the 'while' # condition and that would be fine. Everything else isn't: - result = allPathsAsgnResult(n[0]) + result = allPathsAsgnResult(p, n[0]) if result == Unknown: - result = allPathsAsgnResult(n[1]) + result = allPathsAsgnResult(p, n[1]) # we cannot assume that the 'while' loop is really executed at least once: if result == InitSkippable: result = Unknown of harmless: @@ -1128,9 +1131,17 @@ proc allPathsAsgnResult(n: PNode): InitResultEnum = allPathsInBranch(n[0]) for i in 1..} stmt result = newNodeP(nkTypeClassTy, p) diff --git a/compiler/pipelines.nim b/compiler/pipelines.nim index 7f318d6f120f..58e66495318d 100644 --- a/compiler/pipelines.nim +++ b/compiler/pipelines.nim @@ -5,10 +5,12 @@ import sem, cgen, modulegraphs, ast, llstream, parser, msgs, import pipelineutils +import ../dist/checksums/src/checksums/sha1 + when not defined(leanCompiler): import jsgen, docgen2 -import std/[syncio, objectdollar, assertions, tables, strutils] +import std/[syncio, objectdollar, assertions, tables, strutils, strtabs] import renderer import ic/replayer import nir/nir @@ -244,7 +246,10 @@ proc compilePipelineModule*(graph: ModuleGraph; fileIdx: FileIndex; flags: TSymF if result == nil: var cachedModules: seq[FileIndex] = @[] result = moduleFromRodFile(graph, fileIdx, cachedModules) - let filename = AbsoluteFile toFullPath(graph.config, fileIdx) + let path = toFullPath(graph.config, fileIdx) + let filename = AbsoluteFile path + if fileExists(filename): # it could be a stdinfile + graph.cachedFiles[path] = $secureHashFile(path) if result == nil: result = newModule(graph, fileIdx) result.flags.incl flags diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index b4d8759811ef..a0de33ed5096 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -246,7 +246,8 @@ proc sumGeneric(t: PType): int = result += sumGeneric(a) break of tyProc: - result += sumGeneric(t.returnType) + if t.returnType != nil: + result += sumGeneric(t.returnType) for _, a in t.paramTypes: result += sumGeneric(a) break diff --git a/compiler/transf.nim b/compiler/transf.nim index edae6b847df8..a92527fd1e2f 100644 --- a/compiler/transf.nim +++ b/compiler/transf.nim @@ -472,7 +472,8 @@ proc transformYield(c: PTransf, n: PNode): PNode = proc transformAddrDeref(c: PTransf, n: PNode, kinds: TNodeKinds): PNode = result = transformSons(c, n) - if c.graph.config.backend == backendCpp or sfCompileToCpp in c.module.flags: return + # inlining of 'var openarray' iterators; bug #19977 + if n.typ.kind != tyOpenArray and (c.graph.config.backend == backendCpp or sfCompileToCpp in c.module.flags): return var n = result case n[0].kind of nkObjUpConv, nkObjDownConv, nkChckRange, nkChckRangeF, nkChckRange64: diff --git a/doc/grammar.txt b/doc/grammar.txt index f1484bb0b16c..51b3e0053c81 100644 --- a/doc/grammar.txt +++ b/doc/grammar.txt @@ -187,7 +187,7 @@ objectCase = 'case' declColonEquals ':'? COMMENT? objectPart = IND{>} objectPart^+IND{=} DED / objectWhen / objectCase / 'nil' / 'discard' / declColonEquals objectDecl = 'object' ('of' typeDesc)? COMMENT? objectPart -conceptParam = ('var' | 'out')? symbol +conceptParam = ('var' | 'out' | 'ptr' | 'ref' | 'static' | 'type')? symbol conceptDecl = 'concept' conceptParam ^* ',' (pragma)? ('of' typeDesc ^* ',')? &IND{>} stmt typeDef = identVisDot genericParamList? pragma '=' optInd typeDefValue diff --git a/doc/manual.md b/doc/manual.md index 1de7f32b4afc..65a4472e70cb 100644 --- a/doc/manual.md +++ b/doc/manual.md @@ -267,7 +267,7 @@ You can also use the [discard statement](#statements-and-expressions-discard-sta ``` This was how multiline comments were done before version 0.13.0, -and it is used to provide specifications to [testament](testament.html#writing-unitests) test framework. +and it is used to provide specifications to [testament](testament.html#writing-unit-tests) test framework. Identifiers & Keywords diff --git a/lib/pure/algorithm.nim b/lib/pure/algorithm.nim index 65402e9fb4fc..b12ed7cddbf4 100644 --- a/lib/pure/algorithm.nim +++ b/lib/pure/algorithm.nim @@ -387,7 +387,7 @@ func sort*[T](a: var openArray[T], ## ``` ## ## You can inline adhoc comparison procs with the `do notation - ## `_. Example: + ## `_. Example: ## ## ```nim ## people.sort do (x, y: Person) -> int: diff --git a/lib/pure/complex.nim b/lib/pure/complex.nim index dc899a2f7623..8234db410bc7 100644 --- a/lib/pure/complex.nim +++ b/lib/pure/complex.nim @@ -249,14 +249,31 @@ func pow*[T](x, y: Complex[T]): Complex[T] = else: result.re = 0.0 result.im = 0.0 - elif y.re == 1.0 and y.im == 0.0: - result = x - elif y.re == -1.0 and y.im == 0.0: - result = T(1.0) / x - elif y.re == 2.0 and y.im == 0.0: - result = x * x - elif y.re == 0.5 and y.im == 0.0: - result = sqrt(x) + elif y.im == 0.0: + if y.re == 1.0: + result = x + elif y.re == -1.0: + result = T(1.0) / x + elif y.re == 2.0: + result = x * x + elif y.re == 0.5: + result = sqrt(x) + elif x.im == 0.0: + # Revert to real pow when both base and exponent are real + result.re = pow(x.re, y.re) + result.im = 0.0 + else: + # Special case when the exponent is real + let + rho = abs(x) + theta = arctan2(x.im, x.re) + s = pow(rho, y.re) + r = y.re * theta + result.re = s * cos(r) + result.im = s * sin(r) + elif x.im == 0.0 and x.re == E: + # Special case Euler's formula + result = exp(y) else: let rho = abs(x) diff --git a/lib/pure/os.nim b/lib/pure/os.nim index 1fd08e7636bb..2b52d4d99f3f 100644 --- a/lib/pure/os.nim +++ b/lib/pure/os.nim @@ -453,7 +453,7 @@ proc expandFilename*(filename: string): string {.rtl, extern: "nos$1", c_free(cast[pointer](r)) proc getCurrentCompilerExe*(): string {.compileTime.} = discard - ## This is `getAppFilename()`_ at compile time. + ## Returns the path of the currently running Nim compiler or nimble executable. ## ## Can be used to retrieve the currently executing ## Nim compiler from a Nim or nimscript program, or the nimble binary diff --git a/lib/pure/strformat.nim b/lib/pure/strformat.nim index 1700464138a7..41b35da83438 100644 --- a/lib/pure/strformat.nim +++ b/lib/pure/strformat.nim @@ -673,7 +673,6 @@ proc strformatImpl(f: string; openChar, closeChar: char, inc i, 2 else: raiseAssert "invalid format string: '$1' instead of '$1$1'" % $closeChar - inc i else: strlit.add f[i] inc i diff --git a/lib/std/cmdline.nim b/lib/std/cmdline.nim index a57fb76a4e0d..0ba4619e53c9 100644 --- a/lib/std/cmdline.nim +++ b/lib/std/cmdline.nim @@ -181,7 +181,7 @@ when defined(nimdoc): ## Similarly to `argv`:idx: in C, ## it is possible to call `paramStr(0)` but this will return OS specific ## contents (usually the name of the invoked executable). You should avoid - ## this and call `getAppFilename()`_ instead. + ## this and call `getAppFilename() `_ instead. ## ## **Availability**: When generating a dynamic library (see `--app:lib`) on ## Posix this proc is not defined. @@ -192,7 +192,7 @@ when defined(nimdoc): ## * `parseCmdLine proc`_ ## * `paramCount proc`_ ## * `commandLineParams proc`_ - ## * `getAppFilename proc`_ + ## * `getAppFilename proc `_ ## ## **Examples:** ## @@ -282,7 +282,7 @@ when declared(paramCount) or defined(nimdoc): ## Convenience proc which returns the command line parameters. ## ## This returns **only** the parameters. If you want to get the application - ## executable filename, call `getAppFilename()`_. + ## executable filename, call `getAppFilename() `_. ## ## **Availability**: On Posix there is no portable way to get the command ## line from a DLL and thus the proc isn't defined in this environment. You @@ -294,7 +294,7 @@ when declared(paramCount) or defined(nimdoc): ## * `parseCmdLine proc`_ ## * `paramCount proc`_ ## * `paramStr proc`_ - ## * `getAppFilename proc`_ + ## * `getAppFilename proc `_ ## ## **Examples:** ## diff --git a/lib/system.nim b/lib/system.nim index 61a0a9f2d484..b90d525b581a 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -2131,7 +2131,7 @@ when not defined(js) and declared(alloc0) and declared(dealloc): inc(i) dealloc(a) -when notJSnotNims: +when notJSnotNims and not gotoBasedExceptions: type PSafePoint = ptr TSafePoint TSafePoint {.compilerproc, final.} = object diff --git a/lib/system/compilation.nim b/lib/system/compilation.nim index 7cf80eb17070..cda16fae5cd2 100644 --- a/lib/system/compilation.nim +++ b/lib/system/compilation.nim @@ -144,16 +144,17 @@ template currentSourcePath*: string = instantiationInfo(-1, true).filename ## Returns the full file-system path of the current source. ## ## To get the directory containing the current source, use it with - ## `os.parentDir() `_ as `currentSourcePath.parentDir()`. + ## `ospaths2.parentDir() `_ as + ## `currentSourcePath.parentDir()`. ## ## The path returned by this template is set at compile time. ## ## See the docstring of `macros.getProjectPath() `_ - ## for an example to see the distinction between the `currentSourcePath` - ## and `getProjectPath`. + ## for an example to see the distinction between the `currentSourcePath()` + ## and `getProjectPath()`. ## ## See also: - ## * `getCurrentDir proc `_ + ## * `ospaths2.getCurrentDir() proc `_ proc slurp*(filename: string): string {.magic: "Slurp".} ## This is an alias for `staticRead <#staticRead,string>`_. diff --git a/lib/system/embedded.nim b/lib/system/embedded.nim index e0b053c7b305..ea6776f58a96 100644 --- a/lib/system/embedded.nim +++ b/lib/system/embedded.nim @@ -19,8 +19,9 @@ proc nimFrame(s: PFrame) {.compilerRtl, inl, exportc: "nimFrame".} = discard proc popFrame {.compilerRtl, inl.} = discard proc setFrame(s: PFrame) {.compilerRtl, inl.} = discard -proc pushSafePoint(s: PSafePoint) {.compilerRtl, inl.} = discard -proc popSafePoint {.compilerRtl, inl.} = discard +when not gotoBasedExceptions: + proc pushSafePoint(s: PSafePoint) {.compilerRtl, inl.} = discard + proc popSafePoint {.compilerRtl, inl.} = discard proc pushCurrentException(e: ref Exception) {.compilerRtl, inl.} = discard proc popCurrentException {.compilerRtl, inl.} = discard diff --git a/lib/system/excpt.nim b/lib/system/excpt.nim index 6b40ca391989..210b1a525690 100644 --- a/lib/system/excpt.nim +++ b/lib/system/excpt.nim @@ -75,24 +75,39 @@ when NimStackTraceMsgs: var frameMsgBuf* {.threadvar.}: string var framePtr {.threadvar.}: PFrame - excHandler {.threadvar.}: PSafePoint - # list of exception handlers - # a global variable for the root of all try blocks currException {.threadvar.}: ref Exception - gcFramePtr {.threadvar.}: GcFrame -type - FrameState = tuple[gcFramePtr: GcFrame, framePtr: PFrame, - excHandler: PSafePoint, currException: ref Exception] +when not gotoBasedExceptions: + var + excHandler {.threadvar.}: PSafePoint + # list of exception handlers + # a global variable for the root of all try blocks + gcFramePtr {.threadvar.}: GcFrame + +when gotoBasedExceptions: + type + FrameState = tuple[framePtr: PFrame, + currException: ref Exception] +else: + type + FrameState = tuple[gcFramePtr: GcFrame, framePtr: PFrame, + excHandler: PSafePoint, currException: ref Exception] proc getFrameState*(): FrameState {.compilerRtl, inl.} = - return (gcFramePtr, framePtr, excHandler, currException) + when gotoBasedExceptions: + return (framePtr, currException) + else: + return (gcFramePtr, framePtr, excHandler, currException) proc setFrameState*(state: FrameState) {.compilerRtl, inl.} = - gcFramePtr = state.gcFramePtr - framePtr = state.framePtr - excHandler = state.excHandler - currException = state.currException + when gotoBasedExceptions: + framePtr = state.framePtr + currException = state.currException + else: + gcFramePtr = state.gcFramePtr + framePtr = state.framePtr + excHandler = state.excHandler + currException = state.currException proc getFrame*(): PFrame {.compilerRtl, inl.} = framePtr @@ -114,20 +129,21 @@ when false: proc setFrame*(s: PFrame) {.compilerRtl, inl.} = framePtr = s -proc getGcFrame*(): GcFrame {.compilerRtl, inl.} = gcFramePtr -proc popGcFrame*() {.compilerRtl, inl.} = gcFramePtr = gcFramePtr.prev -proc setGcFrame*(s: GcFrame) {.compilerRtl, inl.} = gcFramePtr = s -proc pushGcFrame*(s: GcFrame) {.compilerRtl, inl.} = - s.prev = gcFramePtr - zeroMem(cast[pointer](cast[int](s)+%sizeof(GcFrameHeader)), s.len*sizeof(pointer)) - gcFramePtr = s +when not gotoBasedExceptions: + proc getGcFrame*(): GcFrame {.compilerRtl, inl.} = gcFramePtr + proc popGcFrame*() {.compilerRtl, inl.} = gcFramePtr = gcFramePtr.prev + proc setGcFrame*(s: GcFrame) {.compilerRtl, inl.} = gcFramePtr = s + proc pushGcFrame*(s: GcFrame) {.compilerRtl, inl.} = + s.prev = gcFramePtr + zeroMem(cast[pointer](cast[int](s)+%sizeof(GcFrameHeader)), s.len*sizeof(pointer)) + gcFramePtr = s -proc pushSafePoint(s: PSafePoint) {.compilerRtl, inl.} = - s.prev = excHandler - excHandler = s + proc pushSafePoint(s: PSafePoint) {.compilerRtl, inl.} = + s.prev = excHandler + excHandler = s -proc popSafePoint {.compilerRtl, inl.} = - excHandler = excHandler.prev + proc popSafePoint {.compilerRtl, inl.} = + excHandler = excHandler.prev proc pushCurrentException(e: sink(ref Exception)) {.compilerRtl, inl.} = e.up = currException @@ -407,15 +423,16 @@ proc reportUnhandledError(e: ref Exception) {.nodestroy, gcsafe.} = when hostOS != "any": reportUnhandledErrorAux(e) -proc nimLeaveFinally() {.compilerRtl.} = - when defined(cpp) and not defined(noCppExceptions) and not gotoBasedExceptions: - {.emit: "throw;".} - else: - if excHandler != nil: - c_longjmp(excHandler.context, 1) +when not gotoBasedExceptions: + proc nimLeaveFinally() {.compilerRtl.} = + when defined(cpp) and not defined(noCppExceptions) and not gotoBasedExceptions: + {.emit: "throw;".} else: - reportUnhandledError(currException) - rawQuit(1) + if excHandler != nil: + c_longjmp(excHandler.context, 1) + else: + reportUnhandledError(currException) + rawQuit(1) when gotoBasedExceptions: var nimInErrorMode {.threadvar.}: bool diff --git a/nimdoc/testproject/expected/testproject.html b/nimdoc/testproject/expected/testproject.html index 6a7870c6a880..cd2c7122775e 100644 --- a/nimdoc/testproject/expected/testproject.html +++ b/nimdoc/testproject/expected/testproject.html @@ -47,7 +47,10 @@

testproject

    -
  • +
  • Basic usage
  • +
  • Imports
  • @@ -343,7 +346,11 @@

    testproject

    -

    This is the top level module. +

    +

    Basic usage

    +

    Encoding data

    Apart from strings you can also encode lists of integers or characters:

    + +

    Decoding data

    This is the top level module.

    Example:

    import testproject
     import subdir / subdir_b / utils
    diff --git a/nimdoc/testproject/expected/testproject.idx b/nimdoc/testproject/expected/testproject.idx
    index ac9bbb2cede4..81d65a05a290 100644
    --- a/nimdoc/testproject/expected/testproject.idx
    +++ b/nimdoc/testproject/expected/testproject.idx
    @@ -1,71 +1,74 @@
     nimTitle	testproject	testproject.html	module testproject		0
    -nim	someVariable	testproject.html#someVariable	var someVariable		13
    -nim	C_A	testproject.html#C_A	const C_A		26
    -nim	C_B	testproject.html#C_B	const C_B		27
    -nim	C_C	testproject.html#C_C	const C_C		28
    -nim	C_D	testproject.html#C_D	const C_D		29
    -nim	bar	testproject.html#bar,T,T	proc bar[T](a, b: T): T		31
    -nim	baz	testproject.html#baz,T,T	proc baz[T](a, b: T): T		34
    -nim	buzz	testproject.html#buzz,T,T	proc buzz[T](a, b: T): T		38
    -nim	FooBuzz	testproject.html#FooBuzz	type FooBuzz		43
    -nim	bar	testproject.html#bar	proc bar(f: FooBuzz)		47
    -nim	aVariable	testproject.html#aVariable	var aVariable		52
    +nim	someVariable	testproject.html#someVariable	var someVariable		25
    +nim	C_A	testproject.html#C_A	const C_A		38
    +nim	C_B	testproject.html#C_B	const C_B		39
    +nim	C_C	testproject.html#C_C	const C_C		40
    +nim	C_D	testproject.html#C_D	const C_D		41
    +nim	bar	testproject.html#bar,T,T	proc bar[T](a, b: T): T		43
    +nim	baz	testproject.html#baz,T,T	proc baz[T](a, b: T): T		46
    +nim	buzz	testproject.html#buzz,T,T	proc buzz[T](a, b: T): T		50
    +nim	FooBuzz	testproject.html#FooBuzz	type FooBuzz		55
    +nim	bar	testproject.html#bar	proc bar(f: FooBuzz)		59
    +nim	aVariable	testproject.html#aVariable	var aVariable		64
     nim	A	testproject.html#A	enum A		92
     nim	B	testproject.html#B	enum B		97
    -nim	someFunc	testproject.html#someFunc	proc someFunc()		56
    +nim	someFunc	testproject.html#someFunc	proc someFunc()		68
     nim	fromUtils1	testproject.html#fromUtils1.i	iterator fromUtils1(): int		112
     nim	fromUtils2	testproject.html#fromUtils2.t	template fromUtils2()		119
    -nim	fromUtils3	testproject.html#fromUtils3	proc fromUtils3()		57
    -nim	isValid	testproject.html#isValid,T	proc isValid[T](x: T): bool		59
    -nim	enumValueA2	testproject.html#enumValueA2	Foo.enumValueA2		66
    -nim	Foo	testproject.html#Foo	enum Foo		66
    -nim	z1	testproject.html#z1	proc z1(): Foo		69
    -nim	z2	testproject.html#z2	proc z2()		73
    -nim	z3	testproject.html#z3	proc z3()		78
    -nim	z4	testproject.html#z4	proc z4()		81
    -nim	z5	testproject.html#z5	proc z5(): int		87
    -nim	z6	testproject.html#z6	proc z6(): int		91
    -nim	z6t	testproject.html#z6t.t	template z6t(): int		95
    -nim	z7	testproject.html#z7	proc z7(): int		99
    -nim	z8	testproject.html#z8	proc z8(): int		103
    -nim	z9	testproject.html#z9	proc z9()		111
    -nim	z10	testproject.html#z10	proc z10()		114
    -nim	z11	testproject.html#z11	proc z11()		119
    -nim	z12	testproject.html#z12	proc z12(): int		124
    -nim	z13	testproject.html#z13	proc z13()		129
    -nim	baz	testproject.html#baz	proc baz()		134
    -nim	z17	testproject.html#z17	proc z17()		144
    -nim	p1	testproject.html#p1	proc p1()		156
    -nim	addfBug14485	testproject.html#addfBug14485	proc addfBug14485()		177
    -nim	c_printf	testproject.html#c_printf,cstring	proc c_printf(frmt: cstring): cint		193
    -nim	c_nonexistent	testproject.html#c_nonexistent,cstring	proc c_nonexistent(frmt: cstring): cint		197
    -nim	low	testproject.html#low,T	proc low[T: Ordinal | enum | range](x: T): T		200
    -nim	low2	testproject.html#low2,T	proc low2[T: Ordinal | enum | range](x: T): T		210
    -nim	tripleStrLitTest	testproject.html#tripleStrLitTest	proc tripleStrLitTest()		223
    -nim	method1	testproject.html#method1.e,Moo	method method1(self: Moo)		264
    -nim	method2	testproject.html#method2.e,Moo	method method2(self: Moo): int		266
    -nim	method3	testproject.html#method3.e,Moo	method method3(self: Moo): int		269
    -nim	iter1	testproject.html#iter1.i,int	iterator iter1(n: int): int		274
    -nim	iter2	testproject.html#iter2.i,int	iterator iter2(n: int): int		278
    -nim	bar	testproject.html#bar.m	macro bar(): untyped		285
    -nim	z16	testproject.html#z16.m	macro z16()		288
    -nim	z18	testproject.html#z18.m	macro z18(): int		297
    -nim	foo	testproject.html#foo.t,SomeType,SomeType	template foo(a, b: SomeType)		302
    -nim	myfn	testproject.html#myfn.t	template myfn()		307
    -nim	z14	testproject.html#z14.t	template z14()		328
    -nim	z15	testproject.html#z15.t	template z15()		333
    -nim	asyncFun1	testproject.html#asyncFun1	proc asyncFun1(): Future[int]		358
    -nim	asyncFun2	testproject.html#asyncFun2	proc asyncFun2(): owned(Future[void])		361
    -nim	asyncFun3	testproject.html#asyncFun3	proc asyncFun3(): owned(Future[void])		362
    -nim	testNimDocTrailingExample	testproject.html#testNimDocTrailingExample.t	template testNimDocTrailingExample()		371
    -nim	Circle	testproject.html#Circle	Shapes.Circle		380
    -nim	Triangle	testproject.html#Triangle	Shapes.Triangle		380
    -nim	Rectangle	testproject.html#Rectangle	Shapes.Rectangle		380
    -nim	Shapes	testproject.html#Shapes	enum Shapes		380
    -nim	anything	testproject.html#anything	proc anything()		387
    -nim	T19396	testproject.html#T19396	object T19396		392
    -nim	somePragma	testproject.html#somePragma.t	template somePragma()		396
    -nim	MyObject	testproject.html#MyObject	object MyObject		400
    -nim	AnotherObject	testproject.html#AnotherObject	object AnotherObject		405
    -nimgrp	bar	testproject.html#bar-procs-all	proc		31
    -nimgrp	baz	testproject.html#baz-procs-all	proc		34
    +nim	fromUtils3	testproject.html#fromUtils3	proc fromUtils3()		69
    +nim	isValid	testproject.html#isValid,T	proc isValid[T](x: T): bool		71
    +nim	enumValueA2	testproject.html#enumValueA2	Foo.enumValueA2		78
    +nim	Foo	testproject.html#Foo	enum Foo		78
    +nim	z1	testproject.html#z1	proc z1(): Foo		81
    +nim	z2	testproject.html#z2	proc z2()		85
    +nim	z3	testproject.html#z3	proc z3()		90
    +nim	z4	testproject.html#z4	proc z4()		93
    +nim	z5	testproject.html#z5	proc z5(): int		99
    +nim	z6	testproject.html#z6	proc z6(): int		103
    +nim	z6t	testproject.html#z6t.t	template z6t(): int		107
    +nim	z7	testproject.html#z7	proc z7(): int		111
    +nim	z8	testproject.html#z8	proc z8(): int		115
    +nim	z9	testproject.html#z9	proc z9()		123
    +nim	z10	testproject.html#z10	proc z10()		126
    +nim	z11	testproject.html#z11	proc z11()		131
    +nim	z12	testproject.html#z12	proc z12(): int		136
    +nim	z13	testproject.html#z13	proc z13()		141
    +nim	baz	testproject.html#baz	proc baz()		146
    +nim	z17	testproject.html#z17	proc z17()		156
    +nim	p1	testproject.html#p1	proc p1()		168
    +nim	addfBug14485	testproject.html#addfBug14485	proc addfBug14485()		189
    +nim	c_printf	testproject.html#c_printf,cstring	proc c_printf(frmt: cstring): cint		205
    +nim	c_nonexistent	testproject.html#c_nonexistent,cstring	proc c_nonexistent(frmt: cstring): cint		209
    +nim	low	testproject.html#low,T	proc low[T: Ordinal | enum | range](x: T): T		212
    +nim	low2	testproject.html#low2,T	proc low2[T: Ordinal | enum | range](x: T): T		222
    +nim	tripleStrLitTest	testproject.html#tripleStrLitTest	proc tripleStrLitTest()		235
    +nim	method1	testproject.html#method1.e,Moo	method method1(self: Moo)		276
    +nim	method2	testproject.html#method2.e,Moo	method method2(self: Moo): int		278
    +nim	method3	testproject.html#method3.e,Moo	method method3(self: Moo): int		281
    +nim	iter1	testproject.html#iter1.i,int	iterator iter1(n: int): int		286
    +nim	iter2	testproject.html#iter2.i,int	iterator iter2(n: int): int		290
    +nim	bar	testproject.html#bar.m	macro bar(): untyped		297
    +nim	z16	testproject.html#z16.m	macro z16()		300
    +nim	z18	testproject.html#z18.m	macro z18(): int		309
    +nim	foo	testproject.html#foo.t,SomeType,SomeType	template foo(a, b: SomeType)		314
    +nim	myfn	testproject.html#myfn.t	template myfn()		319
    +nim	z14	testproject.html#z14.t	template z14()		340
    +nim	z15	testproject.html#z15.t	template z15()		345
    +nim	asyncFun1	testproject.html#asyncFun1	proc asyncFun1(): Future[int]		370
    +nim	asyncFun2	testproject.html#asyncFun2	proc asyncFun2(): owned(Future[void])		373
    +nim	asyncFun3	testproject.html#asyncFun3	proc asyncFun3(): owned(Future[void])		374
    +nim	testNimDocTrailingExample	testproject.html#testNimDocTrailingExample.t	template testNimDocTrailingExample()		383
    +nim	Circle	testproject.html#Circle	Shapes.Circle		392
    +nim	Triangle	testproject.html#Triangle	Shapes.Triangle		392
    +nim	Rectangle	testproject.html#Rectangle	Shapes.Rectangle		392
    +nim	Shapes	testproject.html#Shapes	enum Shapes		392
    +nim	anything	testproject.html#anything	proc anything()		399
    +nim	T19396	testproject.html#T19396	object T19396		404
    +nim	somePragma	testproject.html#somePragma.t	template somePragma()		408
    +nim	MyObject	testproject.html#MyObject	object MyObject		412
    +nim	AnotherObject	testproject.html#AnotherObject	object AnotherObject		417
    +nimgrp	bar	testproject.html#bar-procs-all	proc		43
    +nimgrp	baz	testproject.html#baz-procs-all	proc		46
    +heading	Basic usage	testproject.html#basic-usage	 Basic usage		0
    +heading	Encoding data	testproject.html#basic-usage-encoding-data	  Encoding data		0
    +heading	Decoding data	testproject.html#basic-usage-decoding-data	  Decoding data		0
    diff --git a/nimdoc/testproject/testproject.nim b/nimdoc/testproject/testproject.nim
    index d2d3fef3fd2f..383c4c827d1c 100644
    --- a/nimdoc/testproject/testproject.nim
    +++ b/nimdoc/testproject/testproject.nim
    @@ -1,3 +1,15 @@
    +## Basic usage
    +## ===========
    +##
    +## Encoding data
    +## -------------
    +##
    +## Apart from strings you can also encode lists of integers or characters:
    +
    +## Decoding data
    +## -------------
    +##
    +
     
     import subdir / subdir_b / utils
     
    diff --git a/testament/specs.nim b/testament/specs.nim
    index 5107c9ed71ee..c3040c1d8fa6 100644
    --- a/testament/specs.nim
    +++ b/testament/specs.nim
    @@ -513,7 +513,7 @@ proc parseSpec*(filename: string): TSpec =
         try:
           msg % ["/", $DirSep, "file", result.filename]
         except ValueError:
    -      result.parseErrors.addLine "invalid variable interpolation (see 'https://nim-lang.github.io/Nim/testament.html#writing-unitests-output-message-variable-interpolation')"
    +      result.parseErrors.addLine "invalid variable interpolation (see 'https://nim-lang.github.io/Nim/testament.html#writing-unit-tests-output-message-variable-interpolation')"
           msg
       result.nimout = result.nimout.varSub
       result.msg = result.msg.varSub
    diff --git a/tests/arc/t23247.nim b/tests/arc/t23247.nim
    new file mode 100644
    index 000000000000..0fadc50cd960
    --- /dev/null
    +++ b/tests/arc/t23247.nim
    @@ -0,0 +1,52 @@
    +discard """
    +  matrix: ";-d:useMalloc"
    +"""
    +
    +# bug #23247
    +import std/hashes
    +
    +func baseAddr[T](x: openArray[T]): ptr T =
    +  # Return the address of the zero:th element of x or `nil` if x is empty
    +  if x.len == 0: nil else: cast[ptr T](x)
    +
    +func makeUncheckedArray[T](p: ptr T): ptr UncheckedArray[T] =
    +  cast[ptr UncheckedArray[T]](p)
    +
    +type
    +  LabelKey = object
    +    data: seq[string]
    +    refs: ptr UncheckedArray[string]
    +    refslen: int
    +
    +  Gauge = ref object
    +    metrics: seq[seq[seq[string]]]
    +
    +template values(key: LabelKey): openArray[string] =
    +  if key.refslen > 0:
    +    key.refs.toOpenArray(0, key.refslen - 1)
    +  else:
    +    key.data
    +
    +proc hash(key: LabelKey): Hash =
    +  hash(key.values)
    +
    +proc view(T: type LabelKey, values: openArray[string]): T =
    +  # TODO some day, we might get view types - until then..
    +  LabelKey(refs: baseAddr(values).makeUncheckedArray(), refslen: values.len())
    +
    +template withValue2(k: untyped) =
    +  discard hash(k)
    +
    +proc setGauge(
    +    collector: Gauge,
    +    labelValues: openArray[string],
    +) =
    +  let v = LabelKey.view(labelValues)
    +  withValue2(v)
    +  collector.metrics.add @[@labelValues, @labelValues]
    +  discard @labelValues
    +
    +var nim_gc_mem_bytes = Gauge()
    +let threadID = $getThreadId()
    +setGauge(nim_gc_mem_bytes, @[threadID])
    +setGauge(nim_gc_mem_bytes, @[threadID])
    \ No newline at end of file
    diff --git a/tests/arc/tarc_macro.nim b/tests/arc/tarc_macro.nim
    index ea7d279fd8ee..33ade1da4a7c 100644
    --- a/tests/arc/tarc_macro.nim
    +++ b/tests/arc/tarc_macro.nim
    @@ -43,4 +43,15 @@ macro bar2() =
         doAssert &%&%y == 1 # unary operator => need to escape
         doAssert y &% y == 2 # binary operator => no need to escape
         doAssert y == 3
    -bar2()
    \ No newline at end of file
    +bar2()
    +
    +block:
    +  macro foo(a: openArray[string] = []): string =
    +    echo a # Segfault doesn't happen if this is removed
    +    newLit ""
    +
    +  proc bar(a: static[openArray[string]] = []) =
    +    const tmp = foo(a)
    +
    +  # bug #22909
    +  doAssert not compiles(bar())
    diff --git a/tests/iter/titervaropenarray.nim b/tests/iter/titervaropenarray.nim
    index ad1192bd80ff..b2fe71cebfad 100644
    --- a/tests/iter/titervaropenarray.nim
    +++ b/tests/iter/titervaropenarray.nim
    @@ -1,6 +1,6 @@
     discard """
       output: "123"
    -  targets: "c"
    +  targets: "c cpp"
     """
     # Try to break the transformation pass:
     iterator iterAndZero(a: var openArray[int]): int =
    diff --git a/tests/misc/t23240.nim b/tests/misc/t23240.nim
    new file mode 100644
    index 000000000000..d5edcefe8215
    --- /dev/null
    +++ b/tests/misc/t23240.nim
    @@ -0,0 +1,6 @@
    +discard """
    +  cmd: "nim c foo/bar.nim"
    +  action: "reject"
    +  errormsg: "cannot open 'foo/'"
    +  file: ""
    +"""
    diff --git a/tests/overload/t23249.nim b/tests/overload/t23249.nim
    new file mode 100644
    index 000000000000..f4657833b9e2
    --- /dev/null
    +++ b/tests/overload/t23249.nim
    @@ -0,0 +1,17 @@
    +# issue #23249
    +
    +type Control* = object
    +proc onAction*(c: Control, handler: proc(e: int) {.gcsafe.}) = discard
    +proc onAction*(c: Control, handler: proc() {.gcsafe.}) = discard
    +
    +template setControlHandlerBlock(c: Control, p: untyped, a: untyped) =
    +    when compiles(c.p(nil)):
    +        c.p() do() {.gcsafe.}: a
    +    else:
    +        c.p = proc() {.gcsafe.} =
    +            a
    +
    +proc mkLayout() =
    +  var b: Control
    +  setControlHandlerBlock(b, onAction):
    +    echo "hi"
    diff --git a/tests/views/tviews1.nim b/tests/views/tviews1.nim
    index 6662e3e5a8fb..1cc9fcdec33c 100644
    --- a/tests/views/tviews1.nim
    +++ b/tests/views/tviews1.nim
    @@ -105,3 +105,22 @@ block: # bug #22117
         result = aref
     
       doAssert main() == 10
    +
    +type
    +  Slice*[T] = object
    +    first, last: int
    +    p: ptr UncheckedArray[T]
    +
    +var i = 0
    +
    +converter autoToOpenArray*[T](s: Slice[T]): openArray[T] =
    +  inc i
    +  result = toOpenArray(s.p, s.first, s.last)
    +
    +proc acceptOpenArray(s: openArray[byte]) = discard
    +
    +proc bug22597 = # bug #22597
    +  acceptOpenArray(Slice[byte]())
    +  doAssert i == 1
    +
    +bug22597()