fixes #26045; #26046; when nimvm leak push options (#26047)

fixes #26045;
fixes #26046

The fix isolates compiler option state while semantically checking each
when nimvm branch.

compiler/semexprs.nim:2745 snapshots the option stack, compiler options,
diagnostics settings, and enabled features. It analyzes one branch and
restores that state in finally. Both the nimvm and else branches use
this function.

This prevents:

```nim
when nimvm:
  {.push overflowChecks: off.}
```

from disabling overflow checks in following runtime code. It also means
a {.pop.} in the opposite branch correctly reports that it has no
corresponding {.push.}.

(cherry picked from commit f6651e6c70)
This commit is contained in:
ringabout
2026-08-03 17:49:48 +08:00
committed by narimiran
parent 770203c361
commit 8a411da772
3 changed files with 48 additions and 2 deletions

View File

@@ -2664,6 +2664,22 @@ proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags; expectedType: P
else:
result = semDirectOp(c, n, flags, expectedType)
proc semNimvmBranch(c: PContext, n: PNode, flags: TExprFlags): PNode =
let
oldOptionStack = c.optionStack[0..^1]
oldOptions = c.config.options
oldNotes = c.config.notes
oldWarningAsErrors = c.config.warningAsErrors
oldFeatures = c.features
try:
result = semExpr(c, n, flags)
finally:
c.optionStack = oldOptionStack
c.config.options = oldOptions
c.config.notes = oldNotes
c.config.warningAsErrors = oldWarningAsErrors
c.features = oldFeatures
proc semWhen(c: PContext, n: PNode, semCheck = true): PNode =
# If semCheck is set to false, ``when`` will return the verbatim AST of
# the correct branch. Otherwise the AST will be passed through semStmt.
@@ -2700,7 +2716,7 @@ proc semWhen(c: PContext, n: PNode, semCheck = true): PNode =
checkSonsLen(it, 2, c.config)
if whenNimvm:
if semCheck:
it[1] = semExpr(c, it[1], flags)
it[1] = semNimvmBranch(c, it[1], flags)
typ = commonType(c, typ, it[1].typ)
result = n # when nimvm is not elimited until codegen
elif c.inGenericContext > 0:
@@ -2731,7 +2747,8 @@ proc semWhen(c: PContext, n: PNode, semCheck = true): PNode =
discard
elif result == nil or whenNimvm:
if semCheck:
it[0] = semExpr(c, it[0], flags)
it[0] = if whenNimvm: semNimvmBranch(c, it[0], flags)
else: semExpr(c, it[0], flags)
typ = commonType(c, typ, it[0].typ)
if typ != nil and typ.kind != tyUntyped:
it[0] = fitNode(c, typ, it[0], it[0].info)

View File

@@ -0,0 +1,21 @@
discard """
output: "ok"
"""
var overflowDetected = false
when nimvm:
{.push overflowChecks: off.}
else:
var branchX = high(int)
try:
inc branchX
except OverflowDefect:
overflowDetected = true
doAssert overflowDetected
var x = high(int)
try:
inc x
except OverflowDefect:
echo "ok"

View File

@@ -0,0 +1,8 @@
discard """
errormsg: "{.pop.} without a corresponding {.push.}"
line: 8
"""
when nimvm:
{.push checks: off.}
else: {.pop.}