From 9cb06d357e75bdf74f99e1e982841d8bbe90ae0e Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Wed, 19 Apr 2023 17:55:54 +0800 Subject: [PATCH] fixes #21540; deref block at transf phase to make injectdestructors function properly (#21688) * fixes #21540; deref block at transf phase to make injectdestructors function properly * add a test case * add one more test * fixes the type of block * transform block --- compiler/ccgexprs.nim | 15 +--------- compiler/transf.nim | 16 +++++++++- tests/ccgbugs/tderefblock.nim | 55 +++++++++++++++++++++++++++++++++-- 3 files changed, 69 insertions(+), 17 deletions(-) diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 44466fb571cc..5a8e2d296eba 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -752,21 +752,8 @@ proc isCppRef(p: BProc; typ: PType): bool {.inline.} = skipTypes(typ, abstractInstOwned).kind in {tyVar} and tfVarIsPtr notin skipTypes(typ, abstractInstOwned).flags -proc derefBlock(p: BProc, e: PNode, d: var TLoc) = - # We transform (block: x)[] to (block: x[]) - let e0 = e[0] - var n = shallowCopy(e0) - n.typ = e.typ - for i in 0 ..< e0.len - 1: - n[i] = e0[i] - n[e0.len-1] = newTreeIT(nkHiddenDeref, e.info, e.typ, e0[e0.len-1]) - expr p, n, d - proc genDeref(p: BProc, e: PNode, d: var TLoc) = - if e.kind == nkHiddenDeref and e[0].kind in {nkBlockExpr, nkBlockStmt}: - # bug #20107. Watch out to not deref the pointer too late. - derefBlock(p, e, d) - return + assert e[0].kind notin {nkBlockExpr, nkBlockStmt}, "it should have been transformed in transf" let mt = mapType(p.config, e[0].typ, mapTypeChooser(e[0])) if mt in {ctArray, ctPtrToArray} and lfEnforceDeref notin d.flags: diff --git a/compiler/transf.nim b/compiler/transf.nim index 445bc1df1899..752d031e1444 100644 --- a/compiler/transf.nim +++ b/compiler/transf.nim @@ -941,6 +941,15 @@ proc commonOptimizations*(g: ModuleGraph; idgen: IdGenerator; c: PSym, n: PNode) else: result = n +proc transformDerefBlock(c: PTransf, n: PNode): PNode = + # We transform (block: x)[] to (block: x[]) + let e0 = n[0] + result = shallowCopy(e0) + result.typ = n.typ + for i in 0 ..< e0.len - 1: + result[i] = e0[i] + result[e0.len-1] = newTreeIT(nkHiddenDeref, n.info, n.typ, e0[e0.len-1]) + proc transform(c: PTransf, n: PNode): PNode = when false: var oldDeferAnchor: PNode @@ -1012,7 +1021,12 @@ proc transform(c: PTransf, n: PNode): PNode = of nkAddr: result = transformAddrDeref(c, n, {nkDerefExpr, nkHiddenDeref}) of nkDerefExpr, nkHiddenDeref: - result = transformAddrDeref(c, n, {nkAddr, nkHiddenAddr}) + if n[0].kind in {nkBlockExpr, nkBlockStmt}: + # bug #20107 bug #21540. Watch out to not deref the pointer too late. + let e = transformDerefBlock(c, n) + result = transformBlock(c, e) + else: + result = transformAddrDeref(c, n, {nkAddr, nkHiddenAddr}) of nkHiddenStdConv, nkHiddenSubConv, nkConv: result = transformConv(c, n) of nkDiscardStmt: diff --git a/tests/ccgbugs/tderefblock.nim b/tests/ccgbugs/tderefblock.nim index fd21a19b87bd..d3ba07667932 100644 --- a/tests/ccgbugs/tderefblock.nim +++ b/tests/ccgbugs/tderefblock.nim @@ -1,6 +1,5 @@ discard """ - cmd: "nim c -d:release -d:danger $file" - matrix: ";--gc:orc" + matrix: "--mm:refc -d:release -d:danger;--mm:orc -d:useMalloc -d:release -d:danger" output: "42" """ @@ -23,3 +22,55 @@ proc m() = echo $f.a m() + +block: # bug #21540 + type + Option = object + val: string + has: bool + + proc some(val: string): Option = + result.has = true + result.val = val + + # Remove lent and it works + proc get(self: Option): lent string = + result = self.val + + type + StringStream = ref object + data: string + pos: int + + proc readAll(s: StringStream): string = + result = newString(s.data.len) + copyMem(addr(result[0]), addr(s.data[0]), s.data.len) + + proc newStringStream(s: string = ""): StringStream = + new(result) + result.data = s + + proc parseJson(s: string): string = + let stream = newStringStream(s) + result = stream.readAll() + + proc main = + let initialFEN = block: + let initialFEN = some parseJson("startpos") + initialFEN.get + + doAssert initialFEN == "startpos" + + main() + +import std/[ + json, + options +] + +block: # bug #21540 + let cheek = block: + let initialFEN = some("""{"initialFen": "startpos"}""".parseJson{"initialFen"}.getStr) + initialFEN.get + + doAssert cheek == "startpos"