diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index eb3ee4bfb7..2e49cc8c33 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -424,7 +424,15 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) = simpleAsgn(p.s(cpsStmts), dest, src) of tyArray: if containsGarbageCollectedRef(dest.t) and p.config.selectedGC notin {gcArc, gcAtomicArc, gcOrc, gcYrc, gcHooks}: - genGenericAsgn(p, dest, src, flags) + # Static array literals may contain GC-managed values (for example, + # strings). They must be copied deeply so that the destination does not + # attempt to adjust the reference count of the static literal's + # interior pointers. This mirrors the handling for tuples and objects + # above, where static sources force a real copy. + let newflags = + if src.storage == OnStatic: flags + {needToCopy} + else: flags + genGenericAsgn(p, dest, src, newflags) else: let rd = rdLoc(dest) let rs = rdLoc(src) diff --git a/tests/iter/tclosureiters.nim b/tests/iter/tclosureiters.nim index 4a26398523..7ea9d8c4cd 100644 --- a/tests/iter/tclosureiters.nim +++ b/tests/iter/tclosureiters.nim @@ -174,3 +174,19 @@ iterator pairs(): (int, int) {.closure.} = for pair in pairs(): echo pair + +# issue #26158: static array literals containing strings must be copied safely +# when a closure iterator stores them in its environment. +iterator fromStatic(): int {.closure.} = + for _ in static([(" ",)]): + break + +for _ in fromStatic(): + break + +iterator fromLiteral(): int {.closure.} = + for _ in [(" ",)]: + break + +for _ in fromLiteral(): + break