diff options
Diffstat (limited to 'compiler/sempass2.nim')
-rw-r--r-- | compiler/sempass2.nim | 29 |
1 files changed, 23 insertions, 6 deletions
diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim index 0a9de674b..75dea069f 100644 --- a/compiler/sempass2.nim +++ b/compiler/sempass2.nim @@ -9,9 +9,12 @@ import intsets, ast, astalgo, msgs, renderer, magicsys, types, idents, trees, - wordrecg, strutils, options, guards, writetracking, lineinfos, + wordrecg, strutils, options, guards, lineinfos, semfold, modulegraphs +when not defined(leanCompiler): + import writetracking + when defined(useDfa): import dfa @@ -48,10 +51,12 @@ type tags: PNode # list of tags bottom, inTryStmt: int owner: PSym + owner_module: PSym init: seq[int] # list of initialized variables guards: TModel # nested guards locked: seq[PNode] # locked locations gcUnsafe, isRecursive, isToplevel, hasSideEffect, inEnforcedGcSafe: bool + inEnforcedNoSideEffects: bool maxLockLevel, currLockLevel: TLockLevel config: ConfigRef graph: ModuleGraph @@ -190,10 +195,10 @@ proc markGcUnsafe(a: PEffects; reason: PNode) = when true: template markSideEffect(a: PEffects; reason: typed) = - a.hasSideEffect = true + if not a.inEnforcedNoSideEffects: a.hasSideEffect = true else: template markSideEffect(a: PEffects; reason: typed) = - a.hasSideEffect = true + if not a.inEnforcedNoSideEffects: a.hasSideEffect = true markGcUnsafe(a, reason) proc listGcUnsafety(s: PSym; onlyWarning: bool; cycleCheck: var IntSet; conf: ConfigRef) = @@ -562,8 +567,10 @@ proc trackOperand(tracked: PEffects, n: PNode, paramType: PType) = if op != nil and op.kind == tyProc and n.skipConv.kind != nkNilLit: internalAssert tracked.config, op.n.sons[0].kind == nkEffectList var effectList = op.n.sons[0] - let s = n.skipConv - if s.kind == nkSym and s.sym.kind in routineKinds: + var s = n.skipConv + if s.kind == nkCast and s[1].typ.kind == tyProc: + s = s[1] + if s.kind == nkSym and s.sym.kind in routineKinds and isNoEffectList(effectList): propagateEffects(tracked, n, s.sym) elif isNoEffectList(effectList): if isForwardedProc(n): @@ -709,9 +716,13 @@ proc track(tracked: PEffects, n: PNode) = for i in 0 ..< safeLen(n): track(tracked, n.sons[i]) of nkCallKinds: + if getConstExpr(tracked.owner_module, n, tracked.graph) != nil: + return # p's effects are ours too: - let a = n.sons[0] + var a = n.sons[0] let op = a.typ + if a.kind == nkCast and a[1].typ.kind == tyProc: + a = a[1] # XXX: in rare situations, templates and macros will reach here after # calling getAst(templateOrMacro()). Currently, templates and macros # are indistinguishable from normal procs (both have tyProc type) and @@ -836,15 +847,20 @@ proc track(tracked: PEffects, n: PNode) = let oldLocked = tracked.locked.len let oldLockLevel = tracked.currLockLevel var enforcedGcSafety = false + var enforceNoSideEffects = false for i in 0 ..< pragmaList.len: let pragma = whichPragma(pragmaList.sons[i]) if pragma == wLocks: lockLocations(tracked, pragmaList.sons[i]) elif pragma == wGcSafe: enforcedGcSafety = true + elif pragma == wNosideeffect: + enforceNoSideEffects = true if enforcedGcSafety: tracked.inEnforcedGcSafe = true + if enforceNoSideEffects: tracked.inEnforcedNoSideEffects = true track(tracked, n.lastSon) if enforcedGcSafety: tracked.inEnforcedGcSafe = false + if enforceNoSideEffects: tracked.inEnforcedNoSideEffects = false setLen(tracked.locked, oldLocked) tracked.currLockLevel = oldLockLevel of nkTypeSection, nkProcDef, nkConverterDef, nkMethodDef, nkIteratorDef, @@ -934,6 +950,7 @@ proc initEffects(g: ModuleGraph; effects: PNode; s: PSym; t: var TEffects) = t.exc = effects.sons[exceptionEffects] t.tags = effects.sons[tagEffects] t.owner = s + t.owner_module = s.getModule t.init = @[] t.guards.s = @[] t.guards.o = initOperators(g) |