diff options
-rw-r--r-- | compiler/ast.nim | 4 | ||||
-rw-r--r-- | compiler/ccgexprs.nim | 4 | ||||
-rw-r--r-- | compiler/ccgstmts.nim | 4 | ||||
-rw-r--r-- | lib/core/strs.nim | 10 | ||||
-rw-r--r-- | tests/destructor/tnewruntime_misc.nim | 6 |
5 files changed, 26 insertions, 2 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim index 6238acb14..48e8afa67 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -759,7 +759,9 @@ type lfImportCompilerProc, # ``importc`` of a compilerproc lfSingleUse # no location yet and will only be used once lfEnforceDeref # a copyMem is required to dereference if this a - # ptr array due to C array limitations. See #1181, #6422, #11171 + # ptr array due to C array limitations. + # See #1181, #6422, #11171 + lfPrepareForMutation # string location is about to be mutated (V2) TStorageLoc* = enum OnUnknown, # location is unknown (stack, heap or static) OnStatic, # in a static section diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index a9932a0ce..224054506 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -944,6 +944,10 @@ proc genSeqElem(p: BProc, n, x, y: PNode, d: var TLoc) = if d.k == locNone: d.storage = OnHeap if skipTypes(a.t, abstractVar).kind in {tyRef, tyPtr}: a.r = ropecg(p.module, "(*$1)", [a.r]) + + if lfPrepareForMutation in d.flags and ty.kind == tyString and + p.config.selectedGC == gcDestructors: + linefmt(p, cpsStmts, "#nimPrepareStrMutationV2($1);$n", [byRefLoc(p, a)]) putIntoDest(p, d, n, ropecg(p.module, "$1$3[$2]", [rdLoc(a), rdCharLoc(b), dataField(p)]), a.storage) diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim index bf07c1af7..337b36904 100644 --- a/compiler/ccgstmts.nim +++ b/compiler/ccgstmts.nim @@ -1266,11 +1266,13 @@ proc genAsgn(p: BProc, e: PNode, fastAsgn: bool) = discard getTypeDesc(p.module, le.typ.skipTypes(skipPtrs)) initLoc(a, locNone, le, OnUnknown) a.flags.incl(lfEnforceDeref) + a.flags.incl(lfPrepareForMutation) expr(p, le, a) + a.flags.excl(lfPrepareForMutation) if fastAsgn: incl(a.flags, lfNoDeepCopy) assert(a.t != nil) genLineDir(p, ri) - loadInto(p, e.sons[0], ri, a) + loadInto(p, le, ri, a) else: genLineDir(p, e) asgnFieldDiscriminant(p, e) diff --git a/lib/core/strs.nim b/lib/core/strs.nim index 677e8731d..92c39331f 100644 --- a/lib/core/strs.nim +++ b/lib/core/strs.nim @@ -189,3 +189,13 @@ proc nimAsgnStrV2(a: var NimStringV2, b: NimStringV2) {.compilerRtl.} = a.p.cap = b.len a.len = b.len copyMem(unsafeAddr a.p.data[0], unsafeAddr b.p.data[0], b.len+1) + +proc nimPrepareStrMutationV2(s: var NimStringV2) {.compilerRtl.} = + if s.p != nil and s.p.allocator == nil: + let oldP = s.p + # can't mutate a literal, so we need a fresh copy here: + let allocator = getLocalAllocator() + s.p = cast[ptr NimStrPayload](allocator.alloc(allocator, contentSize(s.len))) + s.p.allocator = allocator + s.p.cap = s.len + copyMem(unsafeAddr s.p.data[0], unsafeAddr oldP.data[0], s.len+1) diff --git a/tests/destructor/tnewruntime_misc.nim b/tests/destructor/tnewruntime_misc.nim index 029a2a78d..2bdae5c8b 100644 --- a/tests/destructor/tnewruntime_misc.nim +++ b/tests/destructor/tnewruntime_misc.nim @@ -2,6 +2,7 @@ discard """ cmd: '''nim cpp --newruntime $file''' output: '''(field: "value") Indeed +axc 0 new: 0''' """ @@ -24,6 +25,11 @@ proc main = echo w["key"][] echo getEnv("HEAPTRASHING") + # bug #11891 + var x = "abc" + x[1] = 'x' + echo x + main() # bug #11745 |