mirror of
https://github.com/nim-lang/Nim.git
synced 2026-02-12 22:33:49 +00:00
use dummy dest for void branches to fix noreturn in VM (#22617)
fixes #22216
(cherry picked from commit 2542dc09c8)
This commit is contained in:
@@ -408,13 +408,19 @@ proc genIf(c: PCtx, n: PNode; dest: var TDest) =
|
||||
c.gen(it[0], tmp)
|
||||
elsePos = c.xjmp(it[0], opcFJmp, tmp) # if false
|
||||
c.clearDest(n, dest)
|
||||
c.gen(it[1], dest) # then part
|
||||
if isEmptyType(it[1].typ): # maybe noreturn call, don't touch `dest`
|
||||
c.gen(it[1])
|
||||
else:
|
||||
c.gen(it[1], dest) # then part
|
||||
if i < n.len-1:
|
||||
endings.add(c.xjmp(it[1], opcJmp, 0))
|
||||
c.patch(elsePos)
|
||||
else:
|
||||
c.clearDest(n, dest)
|
||||
c.gen(it[0], dest)
|
||||
if isEmptyType(it[0].typ): # maybe noreturn call, don't touch `dest`
|
||||
c.gen(it[0])
|
||||
else:
|
||||
c.gen(it[0], dest)
|
||||
for endPos in endings: c.patch(endPos)
|
||||
c.clearDest(n, dest)
|
||||
|
||||
@@ -508,17 +514,25 @@ proc genCase(c: PCtx; n: PNode; dest: var TDest) =
|
||||
let it = n[i]
|
||||
if it.len == 1:
|
||||
# else stmt:
|
||||
if it[0].kind != nkNilLit or it[0].typ != nil:
|
||||
let body = it[0]
|
||||
if body.kind != nkNilLit or body.typ != nil:
|
||||
# an nkNilLit with nil for typ implies there is no else branch, this
|
||||
# avoids unused related errors as we've already consumed the dest
|
||||
c.gen(it[0], dest)
|
||||
if isEmptyType(body.typ): # maybe noreturn call, don't touch `dest`
|
||||
c.gen(body)
|
||||
else:
|
||||
c.gen(body, dest)
|
||||
else:
|
||||
let b = rawGenLiteral(c, it)
|
||||
c.gABx(it, opcBranch, tmp, b)
|
||||
let elsePos = c.xjmp(it.lastSon, opcFJmp, tmp)
|
||||
c.gen(it.lastSon, dest)
|
||||
let body = it.lastSon
|
||||
let elsePos = c.xjmp(body, opcFJmp, tmp)
|
||||
if isEmptyType(body.typ): # maybe noreturn call, don't touch `dest`
|
||||
c.gen(body)
|
||||
else:
|
||||
c.gen(body, dest)
|
||||
if i < n.len-1:
|
||||
endings.add(c.xjmp(it.lastSon, opcJmp, 0))
|
||||
endings.add(c.xjmp(body, opcJmp, 0))
|
||||
c.patch(elsePos)
|
||||
c.clearDest(n, dest)
|
||||
for endPos in endings: c.patch(endPos)
|
||||
@@ -534,7 +548,10 @@ proc genTry(c: PCtx; n: PNode; dest: var TDest) =
|
||||
if dest < 0 and not isEmptyType(n.typ): dest = getTemp(c, n.typ)
|
||||
var endings: seq[TPosition] = @[]
|
||||
let ehPos = c.xjmp(n, opcTry, 0)
|
||||
c.gen(n[0], dest)
|
||||
if isEmptyType(n[0].typ): # maybe noreturn call, don't touch `dest`
|
||||
c.gen(n[0])
|
||||
else:
|
||||
c.gen(n[0], dest)
|
||||
c.clearDest(n, dest)
|
||||
# Add a jump past the exception handling code
|
||||
let jumpToFinally = c.xjmp(n, opcJmp, 0)
|
||||
@@ -552,7 +569,11 @@ proc genTry(c: PCtx; n: PNode; dest: var TDest) =
|
||||
if it.len == 1:
|
||||
# general except section:
|
||||
c.gABx(it, opcExcept, 0, 0)
|
||||
c.gen(it.lastSon, dest)
|
||||
let body = it.lastSon
|
||||
if isEmptyType(body.typ): # maybe noreturn call, don't touch `dest`
|
||||
c.gen(body)
|
||||
else:
|
||||
c.gen(body, dest)
|
||||
c.clearDest(n, dest)
|
||||
if i < n.len:
|
||||
endings.add(c.xjmp(it, opcJmp, 0))
|
||||
|
||||
32
tests/vm/tnoreturn.nim
Normal file
32
tests/vm/tnoreturn.nim
Normal file
@@ -0,0 +1,32 @@
|
||||
block: # issue #22216
|
||||
type
|
||||
Result[T, E] = object
|
||||
case oVal: bool
|
||||
of false:
|
||||
eVal: E
|
||||
of true:
|
||||
vVal: T
|
||||
|
||||
func raiseResultDefect(m: string) {.noreturn, noinline.} =
|
||||
raise (ref Defect)(msg: m)
|
||||
|
||||
template withAssertOk(self: Result, body: untyped): untyped =
|
||||
case self.oVal
|
||||
of false:
|
||||
raiseResultDefect("Trying to access value with err Result")
|
||||
else:
|
||||
body
|
||||
|
||||
func value[T, E](self: Result[T, E]): T {.inline.} =
|
||||
withAssertOk(self):
|
||||
self.vVal
|
||||
|
||||
const
|
||||
x = Result[int, string](oVal: true, vVal: 123)
|
||||
z = x.value()
|
||||
|
||||
let
|
||||
xx = Result[int, string](oVal: true, vVal: 123)
|
||||
zz = x.value()
|
||||
|
||||
doAssert z == zz
|
||||
Reference in New Issue
Block a user