summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorClyybber <darkmine956@gmail.com>2021-03-11 14:03:25 +0100
committerGitHub <noreply@github.com>2021-03-11 14:03:25 +0100
commit3cbc80045dfe84e47e28abc4d19f2bbeba82748d (patch)
tree5f77f08131e2a090c4788e1e28a98b61cea30f2c
parent3ce27511adac12785b51ecc33dc9d2a2fcd2f0b8 (diff)
downloadNim-3cbc80045dfe84e47e28abc4d19f2bbeba82748d.tar.gz
Fix #14325 (#17308)
* Fix #14325
* Refactor and fix
-rw-r--r--compiler/ccgexprs.nim52
-rw-r--r--compiler/renderer.nim4
-rw-r--r--tests/ccgbugs/tlvalueconv.nim (renamed from tests/ccgbugs/t14160.nim)17
3 files changed, 41 insertions, 32 deletions
diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim
index 2a8af5c41..ea09b3400 100644
--- a/compiler/ccgexprs.nim
+++ b/compiler/ccgexprs.nim
@@ -2577,40 +2577,32 @@ proc upConv(p: BProc, n: PNode, d: var TLoc) =
                         [getTypeDesc(p.module, dest), addrLoc(p.config, a)], a.storage)
 
 proc downConv(p: BProc, n: PNode, d: var TLoc) =
-  if p.module.compileToCpp:
-    discard getTypeDesc(p.module, skipTypes(n[0].typ, abstractPtrs))
-    expr(p, n[0], d)     # downcast does C++ for us
-  else:
-    var dest = skipTypes(n.typ, abstractPtrs)
-
-    var arg = n[0]
-    while arg.kind == nkObjDownConv: arg = arg[0]
+  var arg = n[0]
+  while arg.kind == nkObjDownConv: arg = arg[0]
 
-    var src = skipTypes(arg.typ, abstractPtrs)
-    discard getTypeDesc(p.module, src)
+  let dest = skipTypes(n.typ, abstractPtrs)
+  let src = skipTypes(arg.typ, abstractPtrs)
+  discard getTypeDesc(p.module, src)
+  let isRef = skipTypes(arg.typ, abstractInstOwned).kind in {tyRef, tyPtr, tyVar, tyLent}
+  if isRef and d.k == locNone and n.typ.skipTypes(abstractInstOwned).kind in {tyRef, tyPtr} and n.isLValue:
+    # it can happen that we end up generating '&&x->Sup' here, so we pack
+    # the '&x->Sup' into a temporary and then those address is taken
+    # (see bug #837). However sometimes using a temporary is not correct:
+    # init(TFigure(my)) # where it is passed to a 'var TFigure'. We test
+    # this by ensuring the destination is also a pointer:
     var a: TLoc
     initLocExpr(p, arg, a)
-    var r = rdLoc(a)
-    let isRef = skipTypes(arg.typ, abstractInstOwned).kind in {tyRef, tyPtr, tyVar, tyLent}
-    if isRef:
-      r.add("->Sup")
-    else:
-      r.add(".Sup")
+    putIntoDest(p, d, n,
+              "(*(($1*) (&($2))))" % [getTypeDesc(p.module, n.typ), rdLoc(a)], a.storage)
+  elif p.module.compileToCpp:
+    # C++ implicitly downcasts for us
+    expr(p, arg, d)
+  else:
+    var a: TLoc
+    initLocExpr(p, arg, a)
+    var r = rdLoc(a) & (if isRef: "->Sup" else: ".Sup")
     for i in 2..abs(inheritanceDiff(dest, src)): r.add(".Sup")
-    if isRef:
-      # it can happen that we end up generating '&&x->Sup' here, so we pack
-      # the '&x->Sup' into a temporary and then those address is taken
-      # (see bug #837). However sometimes using a temporary is not correct:
-      # init(TFigure(my)) # where it is passed to a 'var TFigure'. We test
-      # this by ensuring the destination is also a pointer:
-      if d.k == locNone and skipTypes(n.typ, abstractInstOwned).kind in {tyRef, tyPtr, tyVar, tyLent}:
-        getTemp(p, n.typ, d)
-        linefmt(p, cpsStmts, "$1 = &$2;$n", [rdLoc(d), r])
-      else:
-        r = "&" & r
-        putIntoDest(p, d, n, r, a.storage)
-    else:
-      putIntoDest(p, d, n, r, a.storage)
+    putIntoDest(p, d, n, if isRef: "&" & r else: r, a.storage)
 
 proc exprComplexConst(p: BProc, n: PNode, d: var TLoc) =
   let t = n.typ
diff --git a/compiler/renderer.nim b/compiler/renderer.nim
index ed1c52bb7..13ff6941f 100644
--- a/compiler/renderer.nim
+++ b/compiler/renderer.nim
@@ -1143,9 +1143,9 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
     gcomma(g, n)
     put(g, tkParRi, ")")
   of nkObjDownConv, nkObjUpConv:
+    let typ = if (n.typ != nil) and (n.typ.sym != nil): n.typ.sym.name.s else: ""
+    put(g, tkParLe, typ & "(")
     if n.len >= 1: gsub(g, n[0])
-    put(g, tkParLe, "(")
-    gcomma(g, n, 1)
     put(g, tkParRi, ")")
   of nkClosedSymChoice, nkOpenSymChoice:
     if renderIds in g.flags:
diff --git a/tests/ccgbugs/t14160.nim b/tests/ccgbugs/tlvalueconv.nim
index be7088e29..b2cb11eef 100644
--- a/tests/ccgbugs/t14160.nim
+++ b/tests/ccgbugs/tlvalueconv.nim
@@ -1,3 +1,9 @@
+discard """
+  matrix: "--gc:refc; --gc:arc"
+"""
+
+# bug #14160
+
 type
   TPassContext = object of RootObj
   PPassContext = ref TPassContext
@@ -11,5 +17,16 @@ type
 proc main() =
   var g = ModuleGraph(vm: new(Pctx))
   PCtx(g.vm) = nil #This generates invalid C code
+  doAssert g.vm == nil
 
 main()
+
+# bug #14325
+
+proc main2() =
+  var g = ModuleGraph(vm: new(Pctx))
+  PPassContext(PCtx(g.vm)) = nil #This compiles, but crashes at runtime with gc:arc
+  doAssert g.vm == nil
+
+main2()
+