Skip to content

Commit 28278eb

Browse files
committed
Fixes #25261
1 parent 6543040 commit 28278eb

File tree

3 files changed

+72
-11
lines changed

3 files changed

+72
-11
lines changed

compiler/ccgstmts.nim

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,7 @@ proc genState(p: BProc, n: PNode) =
226226
elif n0.kind == nkStrLit:
227227
p.s(cpsStmts).addLabel(n0.strVal)
228228

229-
proc blockLeaveActions(p: BProc, howManyTrys, howManyExcepts: int) =
229+
proc blockLeaveActions(p: BProc, howManyTrys, howManyExcepts: int, isReturnStmt = false) =
230230
# Called by return and break stmts.
231231
# Deals with issues faced when jumping out of try/except/finally stmts.
232232

@@ -258,9 +258,9 @@ proc blockLeaveActions(p: BProc, howManyTrys, howManyExcepts: int) =
258258

259259
# Pop exceptions that was handled by the
260260
# except-blocks we are in
261-
if noSafePoints notin p.flags:
262-
for i in countdown(howManyExcepts-1, 0):
263-
p.s(cpsStmts).addCallStmt(cgsymValue(p.module, "popCurrentException"))
261+
if noSafePoints notin p.flags and (not isReturnStmt or not isClosureIterator(p.prc.typ)):
262+
for i in countdown(howManyExcepts-1, 0):
263+
p.s(cpsStmts).addCallStmt(cgsymValue(p.module, "popCurrentException"))
264264

265265
proc genGotoState(p: BProc, n: PNode) =
266266
# we resist the temptation to translate it into duff's device as it later
@@ -556,7 +556,8 @@ proc genReturnStmt(p: BProc, t: PNode) =
556556
if (t[0].kind != nkEmpty): genStmts(p, t[0])
557557
blockLeaveActions(p,
558558
howManyTrys = p.nestedTryStmts.len,
559-
howManyExcepts = p.inExceptBlockLen)
559+
howManyExcepts = p.inExceptBlockLen,
560+
isReturnStmt = true)
560561
if (p.finallySafePoints.len > 0) and noSafePoints notin p.flags:
561562
# If we're in a finally block, and we came here by exception
562563
# consume it before we return.

compiler/closureiters.nim

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,9 @@ type
180180
varStates: Table[ItemId, int] # Used to detect if local variable belongs to multiple states
181181
finallyPathLen: PNode # int literal
182182

183+
nullifyCurExc: PNode # Empty node, if no yields in tries
184+
restoreExternExc: PNode # Empty node, id no yields in tries
185+
183186
const
184187
nkSkip = {nkEmpty..nkNilLit, nkTemplateDef, nkTypeSection, nkStaticStmt,
185188
nkCommentStmt, nkMixinStmt, nkBindStmt, nkTypeOfExpr} + procDefs
@@ -862,7 +865,7 @@ proc newEndFinallyNode(ctx: var Ctx, info: TLineInfo): PNode =
862865
retStmt.flags.incl(nfNoRewrite)
863866

864867
let ifBody = newTree(nkIfStmt,
865-
newTree(nkElifBranch, excNilCmp, retStmt),
868+
newTree(nkElifBranch, excNilCmp, newTree(nkStmtList, ctx.newRestoreExternException(), retStmt)),
866869
newTree(nkElse,
867870
newTree(nkStmtList,
868871
newTreeI(nkRaiseStmt, info, ctx.g.emptyNode))))
@@ -917,16 +920,15 @@ proc transformBreakStmt(ctx: var Ctx, n: PNode): PNode =
917920
result = n
918921

919922
proc transformReturnStmt(ctx: var Ctx, n: PNode): PNode =
920-
# "Returning" involves jumping along all the cureent finally path.
923+
# "Returning" involves jumping along all the current finally path.
921924
# The last finally should exit to state 0 which is a special case for last exit
922925
# (either return or propagating exception to the caller).
923926
# It is eccounted for in newEndFinallyNode.
924927
result = newNodeI(nkStmtList, n.info)
925928

926929
# Returns prevent exception propagation
927-
result.add(ctx.newNullifyCurExc(n.info))
930+
result.add(ctx.nullifyCurExc)
928931

929-
result.add(ctx.newRestoreExternException())
930932

931933
var finallyChain = newSeq[PNode]()
932934

@@ -950,6 +952,7 @@ proc transformReturnStmt(ctx: var Ctx, n: PNode): PNode =
950952
result.add(ctx.newJumpAlongFinallyChain(finallyChain, n.info))
951953
else:
952954
# There are no (split) finallies on the path, so we can return right away
955+
result.add(ctx.restoreExternExc)
953956
result.add(n)
954957

955958
proc transformBreaksAndReturns(ctx: var Ctx, n: PNode): PNode =
@@ -960,7 +963,7 @@ proc transformBreaksAndReturns(ctx: var Ctx, n: PNode): PNode =
960963
# of nkContinueStmt: # By this point all relevant continues should be
961964
# lowered to breaks in transf.nim.
962965
of nkReturnStmt:
963-
if ctx.curFinallyLevel > 0 and nfNoRewrite notin n.flags:
966+
if nfNoRewrite notin n.flags:
964967
result = ctx.transformReturnStmt(n)
965968
else:
966969
for i in 0..<n.len:
@@ -995,7 +998,7 @@ proc transformClosureIteratorBody(ctx: var Ctx, n: PNode, gotoOut: PNode): PNode
995998
of nkYieldStmt:
996999
result = addGotoOut(result, gotoOut)
9971000
if ctx.curExceptLevel > 0 or ctx.curFinallyLevel > 0:
998-
result = newTree(nkStmtList, ctx.newRestoreExternException(), result)
1001+
result = newTree(nkStmtList, ctx.restoreExternExc, result)
9991002

10001003
of nkElse, nkElseExpr:
10011004
result[0] = addGotoOut(result[0], gotoOut)
@@ -1469,6 +1472,11 @@ proc transformClosureIterator*(g: ModuleGraph; idgen: IdGenerator; fn: PSym, n:
14691472

14701473
ctx.curExcLandingState = ctx.newStateLabel()
14711474
ctx.stateLoopLabel = newSym(skLabel, getIdent(ctx.g.cache, ":stateLoop"), idgen, fn, fn.info)
1475+
1476+
1477+
ctx.nullifyCurExc = newTree(nkStmtList)
1478+
ctx.restoreExternExc = newTree(nkStmtList)
1479+
14721480
var n = n.toStmtList
14731481
# echo "transformed into ", n
14741482

@@ -1490,6 +1498,9 @@ proc transformClosureIterator*(g: ModuleGraph; idgen: IdGenerator; fn: PSym, n:
14901498
let finalStateBody = newTree(nkStmtList)
14911499
if ctx.hasExceptions:
14921500
finalStateBody.add(ctx.newRestoreExternException())
1501+
ctx.nullifyCurExc.add(ctx.newNullifyCurExc(fn.info))
1502+
ctx.restoreExternExc.add(ctx.newRestoreExternException())
1503+
14931504
finalStateBody.add(newTree(nkGotoState, g.newIntLit(n.info, -1)))
14941505
discard ctx.newState(finalStateBody, true, finalState)
14951506

tests/iter/tyieldintry.nim

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -798,3 +798,52 @@ block: #25202
798798
doAssert(checkpoints1 == checkpoints2)
799799

800800
p()
801+
802+
block: #25261
803+
iterator y(): int {.closure.} =
804+
try:
805+
try:
806+
raise newException(CatchableError, "Error")
807+
except CatchableError:
808+
return 123
809+
yield 0
810+
finally:
811+
discard
812+
813+
let w = y
814+
doAssert(w() == 123)
815+
doAssert(getCurrentExceptionMsg() == "")
816+
817+
try:
818+
raise newException(ValueError, "Outer error")
819+
except:
820+
doAssert(getCurrentExceptionMsg() == "Outer error")
821+
let w = y
822+
doAssert(w() == 123)
823+
doAssert(getCurrentExceptionMsg() == "Outer error")
824+
doAssert(getCurrentExceptionMsg() == "")
825+
826+
block:
827+
# Looks almost like above, but last finally changed to except
828+
iterator y(): int {.closure.} =
829+
try:
830+
try:
831+
raise newException(CatchableError, "Error")
832+
except CatchableError:
833+
return 123
834+
yield 0
835+
except:
836+
discard
837+
838+
let w = y
839+
doAssert(w() == 123)
840+
doAssert(getCurrentExceptionMsg() == "")
841+
842+
try:
843+
raise newException(ValueError, "Outer error")
844+
except:
845+
doAssert(getCurrentExceptionMsg() == "Outer error")
846+
let w = y
847+
doAssert(w() == 123)
848+
doAssert(getCurrentExceptionMsg() == "Outer error")
849+
doAssert(getCurrentExceptionMsg() == "")

0 commit comments

Comments
 (0)