mirror of
https://github.com/nim-lang/Nim.git
synced 2025-12-28 08:54:53 +00:00
shallow fold prevention for addr, nkHiddenAddr (#24322)
fixes #24305, refs #23807 Since #23014 `nkHiddenAddr` is produced to fast assign array elements in iterators. However the array access inside this `nkHiddenAddr` can get folded at compile time, generating invalid code. In #23807, compile time folding of regular `addr` expressions was changed to be prevented in `transf` but `nkHiddenAddr` was not updated alongside it. The method for preventing folding in `addr` in #23807 was also faulty, it should only trigger on the immediate child node of the address rather than all nodes nested inside it. This caused a regression as outlined in [this comment](https://github.com/nim-lang/Nim/pull/24322#issuecomment-2419560182). To fix both issues, `addr` and `nkHiddenAddr` now both shallowly prevent constant folding for their immediate children.
This commit is contained in:
@@ -56,7 +56,6 @@ type
|
||||
contSyms, breakSyms: seq[PSym] # to transform 'continue' and 'break'
|
||||
deferDetected, tooEarly: bool
|
||||
isIntroducingNewLocalVars: bool # true if we are in `introducingNewLocalVars` (don't transform yields)
|
||||
inAddr: bool
|
||||
flags: TransformFlags
|
||||
graph: ModuleGraph
|
||||
idgen: IdGenerator
|
||||
@@ -103,12 +102,12 @@ proc newTemp(c: PTransf, typ: PType, info: TLineInfo): PNode =
|
||||
else:
|
||||
result = newSymNode(r)
|
||||
|
||||
proc transform(c: PTransf, n: PNode): PNode
|
||||
proc transform(c: PTransf, n: PNode, noConstFold = false): PNode
|
||||
|
||||
proc transformSons(c: PTransf, n: PNode): PNode =
|
||||
proc transformSons(c: PTransf, n: PNode, noConstFold = false): PNode =
|
||||
result = newTransNode(n)
|
||||
for i in 0..<n.len:
|
||||
result[i] = transform(c, n[i])
|
||||
result[i] = transform(c, n[i], noConstFold)
|
||||
|
||||
proc newAsgnStmt(c: PTransf, kind: TNodeKind, le: PNode, ri: PNode; isFirstWrite: bool): PNode =
|
||||
result = newTransNode(kind, ri.info, 2)
|
||||
@@ -481,8 +480,8 @@ proc transformYield(c: PTransf, n: PNode): PNode =
|
||||
result.add(introduceNewLocalVars(c, c.transCon.forLoopBody))
|
||||
c.isIntroducingNewLocalVars = false
|
||||
|
||||
proc transformAddrDeref(c: PTransf, n: PNode, kinds: TNodeKinds): PNode =
|
||||
result = transformSons(c, n)
|
||||
proc transformAddrDeref(c: PTransf, n: PNode, kinds: TNodeKinds, isAddr = false): PNode =
|
||||
result = transformSons(c, n, noConstFold = isAddr)
|
||||
# inlining of 'var openarray' iterators; bug #19977
|
||||
if n.typ.kind != tyOpenArray and (c.graph.config.backend == backendCpp or sfCompileToCpp in c.module.flags): return
|
||||
var n = result
|
||||
@@ -1010,7 +1009,7 @@ proc transformDerefBlock(c: PTransf, n: PNode): PNode =
|
||||
result[i] = e0[i]
|
||||
result[e0.len-1] = newTreeIT(nkHiddenDeref, n.info, n.typ, e0[e0.len-1])
|
||||
|
||||
proc transform(c: PTransf, n: PNode): PNode =
|
||||
proc transform(c: PTransf, n: PNode, noConstFold = false): PNode =
|
||||
when false:
|
||||
var oldDeferAnchor: PNode
|
||||
if n.kind in {nkElifBranch, nkOfBranch, nkExceptBranch, nkElifExpr,
|
||||
@@ -1077,12 +1076,9 @@ proc transform(c: PTransf, n: PNode): PNode =
|
||||
of nkCallKinds:
|
||||
result = transformCall(c, n)
|
||||
of nkHiddenAddr:
|
||||
result = transformAddrDeref(c, n, {nkHiddenDeref})
|
||||
result = transformAddrDeref(c, n, {nkHiddenDeref}, isAddr = true)
|
||||
of nkAddr:
|
||||
let oldInAddr = c.inAddr
|
||||
c.inAddr = true
|
||||
result = transformAddrDeref(c, n, {nkDerefExpr, nkHiddenDeref})
|
||||
c.inAddr = oldInAddr
|
||||
result = transformAddrDeref(c, n, {nkDerefExpr, nkHiddenDeref}, isAddr = true)
|
||||
of nkDerefExpr:
|
||||
result = transformAddrDeref(c, n, {nkAddr, nkHiddenAddr})
|
||||
of nkHiddenDeref:
|
||||
@@ -1162,7 +1158,7 @@ proc transform(c: PTransf, n: PNode): PNode =
|
||||
let exprIsPointerCast = n.kind in {nkCast, nkConv, nkHiddenStdConv} and
|
||||
n.typ != nil and
|
||||
n.typ.kind == tyPointer
|
||||
if not exprIsPointerCast and not c.inAddr:
|
||||
if not exprIsPointerCast and not noConstFold:
|
||||
var cnst = getConstExpr(c.module, result, c.idgen, c.graph)
|
||||
# we inline constants if they are not complex constants:
|
||||
if cnst != nil and not dontInlineConstant(n, cnst):
|
||||
|
||||
32
tests/iter/tfoldedaddr.nim
Normal file
32
tests/iter/tfoldedaddr.nim
Normal file
@@ -0,0 +1,32 @@
|
||||
discard """
|
||||
output: '''
|
||||
23
|
||||
23
|
||||
23
|
||||
23
|
||||
23
|
||||
23
|
||||
'''
|
||||
"""
|
||||
|
||||
block: # issue #24305
|
||||
iterator demo(a: openArray[int]): int =
|
||||
for k in countUp(a[0], 19):
|
||||
yield 23
|
||||
|
||||
for k in demo(@[17]):
|
||||
echo k
|
||||
|
||||
block: # issue #24305 with array
|
||||
iterator demo(a: array[1, int]): int =
|
||||
for k in countUp(a[0], 19):
|
||||
yield 23
|
||||
|
||||
for k in demo([17]):
|
||||
echo k
|
||||
|
||||
block: # related regression
|
||||
proc main =
|
||||
let a = [0, 1, 2]
|
||||
let x = addr a[low(a)]
|
||||
main()
|
||||
Reference in New Issue
Block a user