Files
Nim/tests/ccg/tclosure_err_panic_goto.nim
ringabout a28e450154 fixes #25851; ensure --panics:on does not skip nimErr_ check after closure calls (#25855)
fixes #25851

## Summary: `--panics:on` drops `nimErr_` check after closure calls
(#25851)

### Bug

With `--exceptions:goto` and `--panics:on`, the compiler skipped the
`nimErr_` check after indirect closure calls whose result flows directly
into another call (e.g., `result.add elem(src)`). A raise inside the
closure was silently swallowed — the loop continued, and the next
`raise` hit the already-set `nimInErrorMode` flag, overflowing its
`bool` storage into `OverflowDefect`.

### Root Cause

**ast.nim** — `canRaise` checked `fn.typ.n[0].len < effectListLen` first
(false after the expansion) and then `exceptionEffects != nil` (also
false, nil), so it returned `false` — meaning "cannot raise." The C
codegen trusted this and omitted the `nimErr_` check.

### Fix

**ast.nim** — `canRaise` now treats `nil` `exceptionEffects` as "unknown
→ can raise" (`exceptionEffects == nil` as an additional true
condition). This is defense-in-depth: even if some other path expands
the list but leaves `exceptionEffects` nil (e.g., a type with `{.tags.}`
but no `{.raises.}`), the error check is still emitted.

### Test

tclosure_err_panic_goto.nim — exercises the double-trigger pattern
(`drawBool` sets the error flag → closure call must propagate it) with
`matrix: "; --panics:on"` covering both exception modes.

(cherry picked from commit 88a18de44f)
2026-06-08 08:46:56 +02:00

37 lines
1.1 KiB
Nim
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

discard """
matrix: "; --panics:on"
"""
# issue #25851: --panics:on must not drop the nimErr_ check after a closure
# call whose result is consumed directly (e.g. `result.add elem(src)`).
# Regression from #25295.
type
Overrun = object of CatchableError
Source = object
data: seq[bool]
cursor: int
ElemFn = proc(src: var Source): bool {.closure.}
proc drawBool(src: var Source): bool =
if src.cursor >= src.data.len: raise newException(Overrun, "exhausted")
result = src.data[src.cursor]; inc src.cursor
proc listRun(elem: ElemFn, src: var Source): seq[bool] =
result = @[]
while true:
if not src.drawBool(): break
result.add elem(src) # closure call the result flows straight
# into `add`, which previously caused the
# compiler to skip the nimErr_ check.
let elem: ElemFn = proc(src: var Source): bool = src.drawBool()
# Both --panics:on and --panics:off must propagate the Overrun.
var caught = false
try:
var src = Source(data: @[true])
discard listRun(elem, src)
except Overrun:
caught = true
doAssert caught, "Overrun exception was swallowed"