diff options
Diffstat (limited to 'compiler/ccgexprs.nim')
-rw-r--r-- | compiler/ccgexprs.nim | 52 |
1 files changed, 22 insertions, 30 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 |