diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index c38ea3aa60..eb3ee4bfb7 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -251,8 +251,9 @@ proc genGenericAsgn(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) = # (for objects, etc.): if optSeqDestructors in p.config.globalOptions: simpleAsgn(p.s(cpsStmts), dest, src) - elif needToCopy notin flags or - tfShallow in skipTypes(dest.t, abstractVarRange).flags: + elif src.storage != OnStatic and + (needToCopy notin flags or + tfShallow in skipTypes(dest.t, abstractVarRange).flags): if (dest.storage == OnStack and p.config.selectedGC != gcGo) or not usesWriteBarrier(p.config): let rad = addrLoc(p.config, dest) let ras = addrLoc(p.config, src) diff --git a/tests/assign/tshallow_asgn_from_static.nim b/tests/assign/tshallow_asgn_from_static.nim new file mode 100644 index 0000000000..1dd62e103f --- /dev/null +++ b/tests/assign/tshallow_asgn_from_static.nim @@ -0,0 +1,32 @@ +discard """ + matrix: "--mm:refc; --mm:orc" + output: '''aaaeee +["p", "q", "r"]''' +""" + +# A `{.shallow.}` destination type must not shortcut the deep copy when the +# source is static data: `genericShallowAssign` would `incRef` the string +# literals, which have no GC header. `genOptAsgnTuple`/`genOptAsgnObject` +# already give `OnStatic` priority over `tfShallow`; `genGenericAsgn` has to +# agree with them. + +type + Obj {.shallow.} = object + a, b, c, d, e: string # asgnComplexity > 4, so genGenericAsgn is used + ShallowArray {.shallow.} = array[3, string] + Holder = ref object + o: Obj + a: ShallowArray + +const + c1 = Obj(a: "aaa", b: "bbb", c: "ccc", d: "ddd", e: "eee") + ca: ShallowArray = ["p", "q", "r"] + +proc main = + var h = Holder() + h.o = c1 + h.a = ca + echo h.o.a, h.o.e + echo h.a + +main() diff --git a/tests/async/tawait_in_array_literal_loop.nim b/tests/async/tawait_in_array_literal_loop.nim new file mode 100644 index 0000000000..77048c8920 --- /dev/null +++ b/tests/async/tawait_in_array_literal_loop.nim @@ -0,0 +1,37 @@ +discard """ + matrix: "--mm:refc; --mm:orc" + output: "ok" +""" + +# the loop temp lifted into the env must be deep-copied: a shallow assign from +# the static const array made refc incRef string literals in static memory + +import std/asyncdispatch + +const ips = ["::1", "2001:db8::", "::"] + +proc overLiteral(): Future[int] {.async.} = + var n = 0 + for ip in ["::1", "2001:db8::", "::"]: + await sleepAsync(1) + n += ip.len + return n + +proc overConst(): Future[int] {.async.} = + var n = 0 + for ip in ips: + await sleepAsync(1) + n += ip.len + return n + +proc overNested(): Future[int] {.async.} = + var n = 0 + for x in [(1, "::1"), (2, "2001:db8::"), (3, "::")]: + await sleepAsync(1) + n += x[1].len + return n + +doAssert waitFor(overLiteral()) == 15 +doAssert waitFor(overConst()) == 15 +doAssert waitFor(overNested()) == 15 +echo "ok"