This commit is contained in:
Andreas Rumpf
2026-06-07 19:55:56 +02:00
committed by GitHub
parent f1ff8b6d9e
commit 3c6449dbdd
2 changed files with 66 additions and 4 deletions

View File

@@ -803,6 +803,23 @@ proc hasCustomDestructor(c: Con, t: PType): bool =
obj = skipTypes(obj.baseClass, abstractPtrs)
result = result or isCustomDestructor(c, obj)
const
exprBranchKinds = {nkStmtListExpr, nkBlockExpr, nkIfExpr, nkCaseStmt,
nkTryStmt, nkPragmaBlock}
proc distributeAsgn(asgnKind: TNodeKind; dest, ri: PNode; c: var Con; s: var Scope): PNode =
## Distributes an assignment ``dest = ri`` into the leaf expressions of
## ``ri`` when ``ri`` is an expression-based control flow construct. This
## avoids creating pointless intermediate temporaries (bug #25850). The
## descent is recursive so that nestings like ``block: ...; if c: a else: b``
## assign directly to ``dest`` instead of going through a temp per branch.
if ri.kind in exprBranchKinds:
template process(child, s): untyped =
distributeAsgn(asgnKind, dest, child, c, s)
handleNestedTempl(ri, process, willProduceStmt = true)
else:
result = newTree(asgnKind, dest, p(ri, c, s, consumed))
proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode; tmpFlags = {sfSingleUsedTemp}; inReturn = false): PNode =
if n.kind in {nkStmtList, nkStmtListExpr, nkBlockStmt, nkBlockExpr, nkIfStmt,
nkIfExpr, nkCaseStmt, nkWhen, nkWhileStmt, nkParForStmt, nkTryStmt, nkPragmaBlock}:
@@ -1004,13 +1021,11 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode; tmpFlags = {sfSing
result = moveOrCopy(p(n[0], c, s, mode), n[1], c, s, flags)
elif isDiscriminantField(n[0]):
result = c.genDiscriminantAsgn(s, n)
elif n[1].kind in {nkStmtListExpr, nkBlockExpr, nkIfExpr, nkCaseStmt, nkTryStmt, nkPragmaBlock}:
elif n[1].kind in exprBranchKinds:
# Distribute the assignment into each branch to avoid
# creating pointless temporaries for expression-based control flow.
let dest = p(n[0], c, s, mode)
template process(child, s): untyped =
newTree(n.kind, dest, p(child, c, s, consumed))
handleNestedTempl(n[1], process, willProduceStmt = true)
result = distributeAsgn(n.kind, dest, n[1], c, s)
else:
result = copyNode(n)
result.add p(n[0], c, s, mode)

47
tests/arc/t25850.nim Normal file
View File

@@ -0,0 +1,47 @@
discard """
cmd: '''nim c --mm:orc --expandArc:uIf --expandArc:uCase $file'''
nimout: '''
--expandArc: uIf
block :tmp:
let s = w()
if true:
r[] = s
else:
r[] = s
-- end of expandArc ------------------------
--expandArc: uCase
block :tmp:
let s = w()
case n
of 0:
r[] = s
else:
r[] = w()
-- end of expandArc ------------------------
'''
"""
# bug #25850
# Assigning an expression-based control flow construct (an `if`/`case` nested in
# a `block`) must distribute the assignment directly into the leaf branches
# instead of creating redundant intermediate temporaries per branch.
proc w(): array[1000, byte] {.noinline.} = discard
proc uIf(r: ptr array[1000, byte]) =
r[] = (block:
let s = w()
if true: s else: s)
proc uCase(r: ptr array[1000, byte], n: int) =
r[] = (block:
let s = w()
case n
of 0: s
else: w())
var d: array[1000, byte]
uIf(addr d)
uCase(addr d, 0)