diff options
author | Andreas Rumpf <rumpf_a@web.de> | 2020-07-27 23:27:20 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-07-27 23:27:20 +0200 |
commit | e6f0d4a5a59f8230133481d25ce1c3f6e8daf0a5 (patch) | |
tree | 4a5081869ac285012a06851fd2a74cbdd0a4b8ad /compiler | |
parent | 377f71676629d5621d052e662996d30323ea3bee (diff) | |
download | Nim-e6f0d4a5a59f8230133481d25ce1c3f6e8daf0a5.tar.gz |
fixes #15076 (#15095)
Diffstat (limited to 'compiler')
-rw-r--r-- | compiler/injectdestructors.nim | 33 | ||||
-rw-r--r-- | compiler/liftdestructors.nim | 2 | ||||
-rw-r--r-- | compiler/sempass2.nim | 29 |
3 files changed, 36 insertions, 28 deletions
diff --git a/compiler/injectdestructors.nim b/compiler/injectdestructors.nim index 231ece0ce..fa960b5cf 100644 --- a/compiler/injectdestructors.nim +++ b/compiler/injectdestructors.nim @@ -48,6 +48,13 @@ type const toDebug {.strdefine.} = "" +proc hasDestructor(c: Con; t: PType): bool {.inline.} = + result = ast.hasDestructor(t) + when toDebug.len > 0: + # for more effective debugging + if not result and c.graph.config.selectedGC in {gcArc, gcOrc}: + assert(not containsGarbageCollectedRef(t)) + template dbg(body) = when toDebug.len > 0: if c.owner.name.s == toDebug or toDebug == "always": @@ -330,7 +337,7 @@ proc genDiscriminantAsgn(c: var Con; s: var Scope; n: PNode): PNode = let leDotExpr = if le.kind == nkCheckedFieldExpr: le[0] else: le let objType = leDotExpr[0].typ - if hasDestructor(objType): + if hasDestructor(c, objType): if objType.attachedOps[attachedDestructor] != nil and sfOverriden in objType.attachedOps[attachedDestructor].flags: localError(c.graph.config, n.info, errGenerated, """Assignment to discriminant for objects with user defined destructor is not supported, object must have default destructor. @@ -364,8 +371,8 @@ proc genDefaultCall(t: PType; c: Con; info: TLineInfo): PNode = proc destructiveMoveVar(n: PNode; c: var Con; s: var Scope): PNode = # generate: (let tmp = v; reset(v); tmp) - if not hasDestructor(n.typ): - assert n.kind != nkSym or not hasDestructor(n.sym.typ) + if not hasDestructor(c, n.typ): + assert n.kind != nkSym or not hasDestructor(c, n.sym.typ) result = copyTree(n) else: result = newNodeIT(nkStmtListExpr, n.info, n.typ) @@ -393,7 +400,7 @@ proc isCapturedVar(n: PNode): bool = proc passCopyToSink(n: PNode; c: var Con; s: var Scope): PNode = result = newNodeIT(nkStmtListExpr, n.info, n.typ) let tmp = c.getTemp(s, n.typ, n.info) - if hasDestructor(n.typ): + if hasDestructor(c, n.typ): result.add c.genWasMoved(tmp) var m = c.genCopy(tmp, n) m.add p(n, c, s, normal) @@ -432,7 +439,7 @@ proc containsConstSeq(n: PNode): bool = proc ensureDestruction(arg, orig: PNode; c: var Con; s: var Scope): PNode = # it can happen that we need to destroy expression contructors # like [], (), closures explicitly in order to not leak them. - if arg.typ != nil and hasDestructor(arg.typ): + if arg.typ != nil and hasDestructor(c, arg.typ): # produce temp creation for (fn, env). But we need to move 'env'? # This was already done in the sink parameter handling logic. result = newNodeIT(nkStmtListExpr, arg.info, arg.typ) @@ -521,7 +528,7 @@ template processScopeExpr(c: var Con; s: var Scope; ret: PNode, processCall: unt # tricky because you would have to intercept moveOrCopy at a certain point let tmp = c.getTemp(s.parent[], ret.typ, ret.info) tmp.sym.flags.incl sfSingleUsedTemp - let cpy = if ret.typ.hasDestructor: + let cpy = if hasDestructor(c, ret.typ): moveOrCopy(tmp, ret, c, s, isDecl = true) else: newTree(nkFastAsgn, tmp, p(ret, c, s, normal)) @@ -774,10 +781,10 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode): PNode = result = newNodeI(nkStmtList, n.info) for it in n: var ri = it[^1] - if it.kind == nkVarTuple and hasDestructor(ri.typ): + if it.kind == nkVarTuple and hasDestructor(c, ri.typ): let x = lowerTupleUnpacking(c.graph, it, c.owner) result.add p(x, c, s, consumed) - elif it.kind == nkIdentDefs and hasDestructor(it[0].typ) and not isCursor(it[0], c): + elif it.kind == nkIdentDefs and hasDestructor(c, it[0].typ) and not isCursor(it[0], c): for j in 0..<it.len-2: let v = it[j] if v.kind == nkSym: @@ -797,7 +804,7 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode): PNode = v.add itCopy result.add v of nkAsgn, nkFastAsgn: - if hasDestructor(n[0].typ) and n[1].kind notin {nkProcDef, nkDo, nkLambda} and + if hasDestructor(c, n[0].typ) and n[1].kind notin {nkProcDef, nkDo, nkLambda} and not isCursor(n[0], c): # rule (self-assignment-removal): if n[1].kind == nkSym and n[0].kind == nkSym and n[0].sym == n[1].sym: @@ -828,7 +835,7 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode): PNode = result = shallowCopy(n) for i in 0 ..< n.len: result[i] = p(n[i], c, s, normal) - if n.typ != nil and hasDestructor(n.typ): + if n.typ != nil and hasDestructor(c, n.typ): if mode == normal: result = ensureDestruction(result, n, c, s) @@ -858,7 +865,7 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode): PNode = result[0] = p(n[0], c, s, normal) for i in 1 ..< n.len: result[i] = n[i] - if mode == sinkArg and hasDestructor(n.typ): + if mode == sinkArg and hasDestructor(c, n.typ): if isAnalysableFieldAccess(n, c.owner) and isLastRead(n, c): s.wasMoved.add c.genWasMoved(n) else: @@ -868,7 +875,7 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode): PNode = result = shallowCopy(n) for i in 0 ..< n.len: result[i] = p(n[i], c, s, normal) - if mode == sinkArg and hasDestructor(n.typ): + if mode == sinkArg and hasDestructor(c, n.typ): if isAnalysableFieldAccess(n, c.owner) and isLastRead(n, c): # consider 'a[(g; destroy(g); 3)]', we want to say 'wasMoved(a[3])' # without the junk, hence 'c.genWasMoved(n)' @@ -1004,7 +1011,7 @@ proc injectDestructorCalls*(g: ModuleGraph; owner: PSym; n: PNode): PNode = let params = owner.typ.n for i in 1..<params.len: let t = params[i].sym.typ - if isSinkTypeForParam(t) and hasDestructor(t.skipTypes({tySink})): + if isSinkTypeForParam(t) and hasDestructor(c, t.skipTypes({tySink})): scope.final.add c.genDestroy(params[i]) #if optNimV2 in c.graph.config.globalOptions: # injectDefaultCalls(n, c) diff --git a/compiler/liftdestructors.nim b/compiler/liftdestructors.nim index 034e62494..1e6b552e2 100644 --- a/compiler/liftdestructors.nim +++ b/compiler/liftdestructors.nim @@ -507,6 +507,8 @@ proc atomicRefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = var actions = newNodeI(nkStmtList, c.info) let elemType = t.lastSon + createTypeBoundOps(c.g, c.c, elemType, c.info) + if isFinal(elemType): addDestructorCall(c, elemType, actions, genDeref(x, nkDerefExpr)) actions.add callCodegenProc(c.g, "nimRawDispose", c.info, x) diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim index e9dcc7d8a..ab360ab95 100644 --- a/compiler/sempass2.nim +++ b/compiler/sempass2.nim @@ -84,6 +84,19 @@ proc `<=`(a, b: TLockLevel): bool {.borrow.} proc `==`(a, b: TLockLevel): bool {.borrow.} proc max(a, b: TLockLevel): TLockLevel {.borrow.} +proc createTypeBoundOps(tracked: PEffects, typ: PType; info: TLineInfo) = + if typ == nil: return + when false: + let realType = typ.skipTypes(abstractInst) + if realType.kind == tyRef and + optSeqDestructors in tracked.config.globalOptions: + createTypeBoundOps(tracked.graph, tracked.c, realType.lastSon, info) + + createTypeBoundOps(tracked.graph, tracked.c, typ, info) + if (tfHasAsgn in typ.flags) or + optSeqDestructors in tracked.config.globalOptions: + tracked.owner.flags.incl sfInjectDestructors + proc isLocalVar(a: PEffects, s: PSym): bool = # and (s.kind != skParam or s.typ.kind == tyOut) s.kind in {skVar, skResult} and sfGlobal notin s.flags and @@ -400,6 +413,7 @@ proc trackTryStmt(tracked: PEffects, n: PNode) = if b[j].isInfixAs(): assert(b[j][1].kind == nkType) catches(tracked, b[j][1].typ) + createTypeBoundOps(tracked, b[j][2].typ, b[j][2].info) else: assert(b[j].kind == nkType) catches(tracked, b[j].typ) @@ -720,20 +734,6 @@ proc checkRange(c: PEffects; value: PNode; typ: PType) = checkLe(c, lowBound, value) checkLe(c, value, highBound) -proc createTypeBoundOps(tracked: PEffects, typ: PType; info: TLineInfo) = - if typ == nil: return - let realType = typ.skipTypes(abstractInst) - when false: - # XXX fix this in liftdestructors instead - if realType.kind == tyRef and - optSeqDestructors in tracked.config.globalOptions: - createTypeBoundOps(tracked.graph, tracked.c, realType.lastSon, info) - - createTypeBoundOps(tracked.graph, tracked.c, typ, info) - if (tfHasAsgn in typ.flags) or - optSeqDestructors in tracked.config.globalOptions: - tracked.owner.flags.incl sfInjectDestructors - proc trackCall(tracked: PEffects; n: PNode) = template gcsafeAndSideeffectCheck() = if notGcSafe(op) and not importedFromC(a): @@ -799,7 +799,6 @@ proc trackCall(tracked: PEffects; n: PNode) = # check required for 'nim check': if n[1].typ.len > 0: - createTypeBoundOps(tracked, n[1].typ.lastSon, n.info) createTypeBoundOps(tracked, n[1].typ, n.info) # new(x, finalizer): Problem: how to move finalizer into 'createTypeBoundOps'? |