diff --git a/compiler/ast.nim b/compiler/ast.nim index 197b7f22d4..d6ab06ec76 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -279,6 +279,8 @@ type sfNonReloadable # symbol will be left as-is when hot code reloading is on - # meaning that it won't be renamed and/or changed in any way sfGeneratedOp # proc is a generated '='; do not inject destructors in it + # variable is generated closure environment; requires early + # destruction for --newruntime. TSymFlags* = set[TSymFlag] diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index bf39788fa2..4eaa5a17d6 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -360,7 +360,7 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) = else: linefmt(p, cpsStmts, "$1 = $2;$n", [rdLoc(dest), rdLoc(src)]) of tyPtr, tyPointer, tyChar, tyBool, tyEnum, tyCString, - tyInt..tyUInt64, tyRange, tyVar, tyLent: + tyInt..tyUInt64, tyRange, tyVar, tyLent, tyNil: linefmt(p, cpsStmts, "$1 = $2;$n", [rdLoc(dest), rdLoc(src)]) else: internalError(p.config, "genAssignment: " & $ty.kind) diff --git a/compiler/dfa.nim b/compiler/dfa.nim index 755e21cb70..db12a8c66d 100644 --- a/compiler/dfa.nim +++ b/compiler/dfa.nim @@ -619,8 +619,8 @@ proc aliases(obj, field: PNode): bool = break return false -proc instrTargets*(ins: Instr; loc: PNode): bool = - assert ins.kind in {def, use} +proc useInstrTargets*(ins: Instr; loc: PNode): bool = + assert ins.kind == use if ins.sym != nil and loc.kind == nkSym: result = ins.sym == loc.sym else: @@ -633,6 +633,20 @@ proc instrTargets*(ins: Instr; loc: PNode): bool = # use x; question does it affect 'x.f'? Yes. result = aliases(ins.n, loc) or aliases(loc, ins.n) +proc defInstrTargets*(ins: Instr; loc: PNode): bool = + assert ins.kind == def + if ins.sym != nil and loc.kind == nkSym: + result = ins.sym == loc.sym + else: + result = ins.n == loc or sameTrees(ins.n, loc) + if not result: + # We can come here if loc is 'x.f' and ins.n is 'x' or the other way round. + # def x.f; question: does it affect the full 'x'? No. + # def x; question: does it affect the 'x.f'? Yes. + # use x.f; question: does it affect the full 'x'? No. + # use x; question does it affect 'x.f'? Yes. + result = aliases(ins.n, loc) + proc isAnalysableFieldAccess*(orig: PNode; owner: PSym): bool = var n = orig while true: diff --git a/compiler/injectdestructors.nim b/compiler/injectdestructors.nim index b1a5e63c0b..b9fa1e3aeb 100644 --- a/compiler/injectdestructors.nim +++ b/compiler/injectdestructors.nim @@ -165,12 +165,12 @@ proc isLastRead(location: PNode; c: var Con; pc, comesFrom: int): int = while pc < c.g.len: case c.g[pc].kind of def: - if instrTargets(c.g[pc], location): + if defInstrTargets(c.g[pc], location): # the path lead to a redefinition of 's' --> abandon it. return high(int) inc pc of use: - if instrTargets(c.g[pc], location): + if useInstrTargets(c.g[pc], location): c.otherRead = c.g[pc].n return -1 inc pc @@ -349,8 +349,10 @@ proc genSink(c: Con; t: PType; dest, ri: PNode): PNode = # we generate a fast assignment in this case: result = newTree(nkFastAsgn, dest) -proc genCopy(c: Con; t: PType; dest, ri: PNode): PNode = +proc genCopy(c: var Con; t: PType; dest, ri: PNode): PNode = if tfHasOwned in t.flags: + # try to improve the error message here: + if c.otherRead == nil: discard isLastRead(ri, c) checkForErrorPragma(c, t, ri, "=") let t = t.skipTypes({tyGenericInst, tyAlias, tySink}) result = genOp(c, t, attachedAsgn, dest, ri) @@ -410,7 +412,7 @@ proc destructiveMoveVar(n: PNode; c: var Con): PNode = add(v, vpart) result.add v - result.add genWasMoved(n, c) + result.add genWasMoved(skipConv(n), c) result.add tempAsNode proc sinkParamIsLastReadCheck(c: var Con, s: PNode) = @@ -611,7 +613,7 @@ proc moveOrCopy(dest, ri: PNode; c: var Con): PNode = of nkTupleConstr, nkClosure: result = genSink(c, dest.typ, dest, ri) let ri2 = copyTree(ri) - for i in 0..