diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 17f2159495..0f4391a946 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -2159,32 +2159,38 @@ proc genSomeCast(p: BProc, e: PNode, d: var TLoc) = putIntoDest(p, d, e, "(($1) ($2))" % [getTypeDesc(p.module, e.typ), rdCharLoc(a)], a.storage) +proc genUnionCast(p: BProc, e: PNode, d: var TLoc) = + # 'cast' and some float type involved? --> use a union. + let + destt = skipTypes(e.typ, abstractRange) + srct = skipTypes(e[1].typ, abstractRange) + inc(p.labels) + var lbl = p.labels.rope + var tmp: TLoc = default(TLoc) + tmp.snippet = "LOC$1.source" % [lbl] + let destsize = getSize(p.config, destt) + let srcsize = getSize(p.config, srct) + + if destsize > srcsize: + linefmt(p, cpsLocals, "union { $1 dest; $2 source; } LOC$3;$n #nimZeroMem(&LOC$3, sizeof(LOC$3));$n", + [getTypeDesc(p.module, e.typ), getTypeDesc(p.module, e[1].typ), lbl]) + else: + linefmt(p, cpsLocals, "union { $1 source; $2 dest; } LOC$3;$n", + [getTypeDesc(p.module, e[1].typ), getTypeDesc(p.module, e.typ), lbl]) + tmp.k = locExpr + tmp.lode = lodeTyp srct + tmp.storage = OnStack + tmp.flags = {} + expr(p, e[1], tmp) + putIntoDest(p, d, e, "LOC$#.dest" % [lbl], tmp.storage) + proc genCast(p: BProc, e: PNode, d: var TLoc) = const ValueTypes = {tyFloat..tyFloat128, tyTuple, tyObject, tyArray} let destt = skipTypes(e.typ, abstractRange) srct = skipTypes(e[1].typ, abstractRange) if destt.kind in ValueTypes or srct.kind in ValueTypes: - # 'cast' and some float type involved? --> use a union. - inc(p.labels) - var lbl = p.labels.rope - var tmp: TLoc = default(TLoc) - tmp.snippet = "LOC$1.source" % [lbl] - let destsize = getSize(p.config, destt) - let srcsize = getSize(p.config, srct) - - if destsize > srcsize: - linefmt(p, cpsLocals, "union { $1 dest; $2 source; } LOC$3;$n #nimZeroMem(&LOC$3, sizeof(LOC$3));$n", - [getTypeDesc(p.module, e.typ), getTypeDesc(p.module, e[1].typ), lbl]) - else: - linefmt(p, cpsLocals, "union { $1 source; $2 dest; } LOC$3;$n", - [getTypeDesc(p.module, e[1].typ), getTypeDesc(p.module, e.typ), lbl]) - tmp.k = locExpr - tmp.lode = lodeTyp srct - tmp.storage = OnStack - tmp.flags = {} - expr(p, e[1], tmp) - putIntoDest(p, d, e, "LOC$#.dest" % [lbl], tmp.storage) + genUnionCast(p, e, d) else: # I prefer the shorter cast version for pointer types -> generate less # C code; plus it's the right thing to do for closures: @@ -2238,9 +2244,14 @@ proc genRangeChck(p: BProc, n: PNode, d: var TLoc) = [getTypeDesc(p.module, dest), rdCharLoc(a)], a.storage) proc genConv(p: BProc, e: PNode, d: var TLoc) = + const FloatTypes = {tyFloat..tyFloat128} let destType = e.typ.skipTypes({tyVar, tyLent, tyGenericInst, tyAlias, tySink}) if sameBackendType(destType, e[1].typ): expr(p, e[1], d) + elif destType.kind in FloatTypes or + skipTypes(e[1].typ, abstractRange).kind in FloatTypes: + # 'conv' and some float type involved? --> use a union. + genUnionCast(p, e, d) else: genSomeCast(p, e, d) diff --git a/tests/c/tconv.nim b/tests/c/tconv.nim new file mode 100644 index 0000000000..673527768b --- /dev/null +++ b/tests/c/tconv.nim @@ -0,0 +1,14 @@ +discard """ + matrix: "-d:danger;" + targets: "c cpp" +""" + +block: # bug #18540 + block: + let num = 256.1 + doAssert ord(uint8(num)) == 154 + block: + let num = 255.0 + doAssert ord(char(num)) == 0 + let z = char(num) + doAssert ord(z) == 0