fixes #23925; VM generates wrong cast for negative enum values (#23951)

Follow up of #23927 which solves the build error.

This is still only a partial fix as it doesn't take into account
unordered enums. I'll make a separate issue for those.

---------

Co-authored-by: ringabout <43030857+ringabout@users.noreply.github.com>
This commit is contained in:
autumngray
2024-08-27 14:03:56 +02:00
committed by GitHub
parent f09c549d42
commit 540b414c86
2 changed files with 36 additions and 6 deletions

View File

@@ -900,9 +900,15 @@ proc genCard(c: PCtx; n: PNode; dest: var TDest) =
c.freeTemp(tmp)
proc genCastIntFloat(c: PCtx; n: PNode; dest: var TDest) =
template isSigned(typ: PType): bool {.dirty.} =
typ.kind == tyEnum and firstOrd(c.config, typ) < 0 or
typ.kind in {tyInt..tyInt64}
template isUnsigned(typ: PType): bool {.dirty.} =
typ.kind == tyEnum and firstOrd(c.config, typ) >= 0 or
typ.kind in {tyUInt..tyUInt64, tyChar, tyBool}
const allowedIntegers = {tyInt..tyInt64, tyUInt..tyUInt64, tyChar, tyEnum, tyBool}
var signedIntegers = {tyInt..tyInt64}
var unsignedIntegers = {tyUInt..tyUInt64, tyChar, tyEnum, tyBool}
let src = n[1].typ.skipTypes(abstractRange)#.kind
let dst = n[0].typ.skipTypes(abstractRange)#.kind
let srcSize = getSize(c.config, src)
@@ -914,12 +920,12 @@ proc genCastIntFloat(c: PCtx; n: PNode; dest: var TDest) =
if dest < 0: dest = c.getTemp(n[0].typ)
c.gABC(n, opcAsgnInt, dest, tmp)
if dstSize != sizeof(BiggestInt): # don't do anything on biggest int types
if dst.kind in signedIntegers: # we need to do sign extensions
if isSigned(dst): # we need to do sign extensions
if dstSize <= srcSize:
# Sign extension can be omitted when the size increases.
c.gABC(n, opcSignExtend, dest, TRegister(dstSize*8))
elif dst.kind in unsignedIntegers:
if src.kind in signedIntegers or dstSize < srcSize:
elif isUnsigned(dst):
if isSigned(src) or dstSize < srcSize:
# Cast from signed to unsigned always needs narrowing. Cast
# from unsigned to unsigned only needs narrowing when target
# is smaller than source.
@@ -947,7 +953,7 @@ proc genCastIntFloat(c: PCtx; n: PNode; dest: var TDest) =
if dest < 0: dest = c.getTemp(n[0].typ)
if src.kind == tyFloat32:
c.gABC(n, opcCastFloatToInt32, dest, tmp)
if dst.kind in unsignedIntegers:
if isUnsigned(dst):
# integers are sign extended by default.
# since there is no opcCastFloatToUInt32, narrowing should do the trick.
c.gABC(n, opcNarrowU, dest, TRegister(32))

View File

@@ -766,3 +766,27 @@ block: # issue #15730
static: # more nil cstring issues
let x = cstring(nil)
doAssert x.len == 0
block: # bug #23925
type Foo = enum A = -1
proc foo =
doAssert cast[Foo](-1) == A
doAssert ord(A) == -1
static: foo()
foo()
type E = enum
e0 e1 e2 e3 e4 e5 e6 e7 e8 e9 e10 e11 e12 e13 e14 e15 e16 e17 e18 e19 e20
e21 e22 e23 e24 e25 e26 e27 e28 e29 e30 e31 e32 e33 e34 e35 e36 e37 e38
e39 e40 e41 e42 e43 e44 e45 e46 e47 e48 e49 e50 e51 e52 e53 e54 e55 e56
e57 e58 e59 e60 e61 e62 e63 e64 e65 e66 e67 e68 e69 e70 e71 e72 e73 e74
e75 e76 e77 e78 e79 e80 e81 e82 e83 e84 e85 e86 e87 e88 e89 e90 e91 e92
e93 e94 e95 e96 e97 e98 e99 e100 e101 e102 e103 e104 e105 e106 e107 e108
e109 e110 e111 e112 e113 e114 e115 e116 e117 e118 e119 e120 e121 e122
e123 e124 e125 e126 e127 e128
proc bar =
doAssert cast[E](int(e128)) == e128
static: bar()
bar()