summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--compiler/ccgexprs.nim15
-rw-r--r--compiler/transf.nim16
-rw-r--r--tests/ccgbugs/tderefblock.nim55
3 files changed, 69 insertions, 17 deletions
diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim
index 44466fb57..5a8e2d296 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 445bc1df1..752d031e1 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 fd21a19b8..d3ba07667 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"