mirror of
https://github.com/nim-lang/Nim.git
synced 2026-01-03 03:32:32 +00:00
Fixes various issues with shallow copying.
* The {.shallow.} pragma is now properly respected for objects and
tuples that are not handled by genGenericAsgn(). Mirroring the
decision in generic assignments, whether an assignment is shallow
depends on the destination of the assignment, but not the source.
* String literals and complex inline constants are now properly assigned
a location kind of locData.
* Assignments from a locData source will now force deep copying to
occur, even if shallowCopy or {.shallow.} is being used. This
avoids potential crashes from `shallowCopy s, "xxx"` or from
`shallowCopy t, ("a", "b")`.
This commit is contained in:
@@ -212,22 +212,36 @@ proc optAsgnLoc(a: TLoc, t: PType, field: PRope): TLoc =
|
||||
result.heapRoot = a.heapRoot
|
||||
|
||||
proc genOptAsgnTuple(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
|
||||
let newflags =
|
||||
if src.k == locData:
|
||||
flags + { needToCopy }
|
||||
elif tfShallow in dest.t.flags:
|
||||
flags - { needToCopy }
|
||||
else:
|
||||
flags
|
||||
for i in 0 .. <dest.t.len:
|
||||
let t = dest.t.sons[i]
|
||||
let field = ropef("Field$1", i.toRope)
|
||||
genAssignment(p, optAsgnLoc(dest, t, field),
|
||||
optAsgnLoc(src, t, field), flags)
|
||||
optAsgnLoc(src, t, field), newflags)
|
||||
|
||||
proc genOptAsgnObject(p: BProc, dest, src: TLoc, flags: TAssignmentFlags,
|
||||
t: PNode) =
|
||||
if t == nil: return
|
||||
let newflags =
|
||||
if src.k == locData:
|
||||
flags + { needToCopy }
|
||||
elif tfShallow in dest.t.flags:
|
||||
flags - { needToCopy }
|
||||
else:
|
||||
flags
|
||||
case t.kind
|
||||
of nkSym:
|
||||
let field = t.sym
|
||||
genAssignment(p, optAsgnLoc(dest, field.typ, field.loc.r),
|
||||
optAsgnLoc(src, field.typ, field.loc.r), flags)
|
||||
optAsgnLoc(src, field.typ, field.loc.r), newflags)
|
||||
of nkRecList:
|
||||
for child in items(t): genOptAsgnObject(p, dest, src, flags, child)
|
||||
for child in items(t): genOptAsgnObject(p, dest, src, newflags, child)
|
||||
else: nil
|
||||
|
||||
proc genGenericAsgn(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
|
||||
@@ -263,13 +277,13 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
|
||||
of tyRef:
|
||||
genRefAssign(p, dest, src, flags)
|
||||
of tySequence:
|
||||
if needToCopy notin flags:
|
||||
if needToCopy notin flags and src.k != locData:
|
||||
genRefAssign(p, dest, src, flags)
|
||||
else:
|
||||
linefmt(p, cpsStmts, "#genericSeqAssign($1, $2, $3);$n",
|
||||
addrLoc(dest), rdLoc(src), genTypeInfo(p.module, dest.t))
|
||||
of tyString:
|
||||
if needToCopy notin flags:
|
||||
if needToCopy notin flags and src.k != locData:
|
||||
genRefAssign(p, dest, src, flags)
|
||||
else:
|
||||
if dest.s == OnStack or not usesNativeGC():
|
||||
@@ -351,6 +365,22 @@ proc putLocIntoDest(p: BProc, d: var TLoc, s: TLoc) =
|
||||
else:
|
||||
d = s # ``d`` is free, so fill it with ``s``
|
||||
|
||||
proc putDataIntoDest(p: BProc, d: var TLoc, t: PType, r: PRope) =
|
||||
var a: TLoc
|
||||
if d.k != locNone:
|
||||
# need to generate an assignment here
|
||||
initLoc(a, locData, getUniqueType(t), OnUnknown)
|
||||
a.r = r
|
||||
if lfNoDeepCopy in d.flags: genAssignment(p, d, a, {})
|
||||
else: genAssignment(p, d, a, {needToCopy})
|
||||
else:
|
||||
# we cannot call initLoc() here as that would overwrite
|
||||
# the flags field!
|
||||
d.k = locData
|
||||
d.t = getUniqueType(t)
|
||||
d.r = r
|
||||
d.a = -1
|
||||
|
||||
proc putIntoDest(p: BProc, d: var TLoc, t: PType, r: PRope) =
|
||||
var a: TLoc
|
||||
if d.k != locNone:
|
||||
@@ -1766,7 +1796,7 @@ proc exprComplexConst(p: BProc, n: PNode, d: var TLoc) =
|
||||
if d.k == locNone:
|
||||
fillLoc(d, locData, t, tmp, OnHeap)
|
||||
else:
|
||||
putIntoDest(p, d, t, tmp)
|
||||
putDataIntoDest(p, d, t, tmp)
|
||||
|
||||
proc expr(p: BProc, n: PNode, d: var TLoc) =
|
||||
case n.kind
|
||||
@@ -1820,7 +1850,9 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
|
||||
of nkNilLit:
|
||||
if not isEmptyType(n.typ):
|
||||
putIntoDest(p, d, n.typ, genLiteral(p, n))
|
||||
of nkStrLit..nkTripleStrLit, nkIntLit..nkUInt64Lit,
|
||||
of nkStrLit..nkTripleStrLit:
|
||||
putDataIntoDest(p, d, n.typ, genLiteral(p, n))
|
||||
of nkIntLit..nkUInt64Lit,
|
||||
nkFloatLit..nkFloat128Lit, nkCharLit:
|
||||
putIntoDest(p, d, n.typ, genLiteral(p, n))
|
||||
of nkCall, nkHiddenCallConv, nkInfix, nkPrefix, nkPostfix, nkCommand,
|
||||
|
||||
Reference in New Issue
Block a user