mirror of
https://github.com/nim-lang/Nim.git
synced 2026-06-09 21:28:13 +00:00
@@ -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
47
tests/arc/t25850.nim
Normal 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)
|
||||
Reference in New Issue
Block a user