summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--compiler/ccgexprs.nim14
-rw-r--r--tests/ccgbugs/tderefblock.nim24
2 files changed, 38 insertions, 0 deletions
diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim
index 4c15101a9..1f16f458f 100644
--- a/compiler/ccgexprs.nim
+++ b/compiler/ccgexprs.nim
@@ -731,7 +731,21 @@ 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)
+  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
+
   let mt = mapType(p.config, e[0].typ, mapTypeChooser(e[0]))
   if mt in {ctArray, ctPtrToArray} and lfEnforceDeref notin d.flags:
     # XXX the amount of hacks for C's arrays is incredible, maybe we should
diff --git a/tests/ccgbugs/tderefblock.nim b/tests/ccgbugs/tderefblock.nim
new file mode 100644
index 000000000..55253da10
--- /dev/null
+++ b/tests/ccgbugs/tderefblock.nim
@@ -0,0 +1,24 @@
+discard """
+  cmd: "nim c -d:release -d:danger $file"
+  output: "42"
+"""
+
+# bug #20107
+
+type Foo = object
+  a, b, c, d: uint64
+
+proc c(i: uint64): Foo =
+  Foo(a: i, b: i, c: i, d: i)
+
+func x(f: Foo): lent Foo {.inline.} =
+  f
+
+proc m() =
+  let f = block:
+    let i = c(42)
+    x(i)
+
+  echo $f.a
+
+m()