sempass2.nim 37 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012
  1. #
  2. #
  3. # The Nim Compiler
  4. # (c) Copyright 2015 Andreas Rumpf
  5. #
  6. # See the file "copying.txt", included in this
  7. # distribution, for details about the copyright.
  8. #
  9. import
  10. intsets, ast, astalgo, msgs, renderer, magicsys, types, idents, trees,
  11. wordrecg, strutils, options, guards, writetracking, lineinfos,
  12. modulegraphs
  13. when defined(useDfa):
  14. import dfa
  15. # Second semantic checking pass over the AST. Necessary because the old
  16. # way had some inherent problems. Performs:
  17. #
  18. # * effect+exception tracking
  19. # * "usage before definition" checking
  20. # ------------------------ exception and tag tracking -------------------------
  21. discard """
  22. exception tracking:
  23. a() # raises 'x', 'e'
  24. try:
  25. b() # raises 'e'
  26. except e:
  27. # must not undo 'e' here; hrm
  28. c()
  29. --> we need a stack of scopes for this analysis
  30. # XXX enhance the algorithm to care about 'dirty' expressions:
  31. lock a[i].L:
  32. inc i # mark 'i' dirty
  33. lock a[j].L:
  34. access a[i], a[j] # --> reject a[i]
  35. """
  36. type
  37. TEffects = object
  38. exc: PNode # stack of exceptions
  39. tags: PNode # list of tags
  40. bottom, inTryStmt: int
  41. owner: PSym
  42. init: seq[int] # list of initialized variables
  43. guards: TModel # nested guards
  44. locked: seq[PNode] # locked locations
  45. gcUnsafe, isRecursive, isToplevel, hasSideEffect, inEnforcedGcSafe: bool
  46. maxLockLevel, currLockLevel: TLockLevel
  47. config: ConfigRef
  48. graph: ModuleGraph
  49. PEffects = var TEffects
  50. proc `<`(a, b: TLockLevel): bool {.borrow.}
  51. proc `<=`(a, b: TLockLevel): bool {.borrow.}
  52. proc `==`(a, b: TLockLevel): bool {.borrow.}
  53. proc max(a, b: TLockLevel): TLockLevel {.borrow.}
  54. proc isLocalVar(a: PEffects, s: PSym): bool =
  55. s.kind in {skVar, skResult} and sfGlobal notin s.flags and
  56. s.owner == a.owner and s.typ != nil
  57. proc getLockLevel(t: PType): TLockLevel =
  58. var t = t
  59. # tyGenericInst(TLock {tyGenericBody}, tyStatic, tyObject):
  60. if t.kind == tyGenericInst and t.len == 3: t = t.sons[1]
  61. if t.kind == tyStatic and t.n != nil and t.n.kind in {nkCharLit..nkInt64Lit}:
  62. result = t.n.intVal.TLockLevel
  63. proc lockLocations(a: PEffects; pragma: PNode) =
  64. if pragma.kind != nkExprColonExpr:
  65. localError(a.config, pragma.info, "locks pragma without argument")
  66. return
  67. var firstLL = TLockLevel(-1'i16)
  68. for x in pragma[1]:
  69. let thisLL = getLockLevel(x.typ)
  70. if thisLL != 0.TLockLevel:
  71. if thisLL < 0.TLockLevel or thisLL > MaxLockLevel.TLockLevel:
  72. localError(a.config, x.info, "invalid lock level: " & $thisLL)
  73. elif firstLL < 0.TLockLevel: firstLL = thisLL
  74. elif firstLL != thisLL:
  75. localError(a.config, x.info,
  76. "multi-lock requires the same static lock level for every operand")
  77. a.maxLockLevel = max(a.maxLockLevel, firstLL)
  78. a.locked.add x
  79. if firstLL >= 0.TLockLevel and firstLL != a.currLockLevel:
  80. if a.currLockLevel > 0.TLockLevel and a.currLockLevel <= firstLL:
  81. localError(a.config, pragma.info, "invalid nested locking")
  82. a.currLockLevel = firstLL
  83. proc guardGlobal(a: PEffects; n: PNode; guard: PSym) =
  84. # check whether the corresponding lock is held:
  85. for L in a.locked:
  86. if L.kind == nkSym and L.sym == guard: return
  87. # we allow accesses nevertheless in top level statements for
  88. # easier initialization:
  89. #if a.isTopLevel:
  90. # message(n.info, warnUnguardedAccess, renderTree(n))
  91. #else:
  92. if not a.isTopLevel:
  93. localError(a.config, n.info, "unguarded access: " & renderTree(n))
  94. # 'guard*' are checks which are concerned with 'guard' annotations
  95. # (var x{.guard: y.}: int)
  96. proc guardDotAccess(a: PEffects; n: PNode) =
  97. let ri = n.sons[1]
  98. if ri.kind != nkSym or ri.sym.kind != skField: return
  99. var g = ri.sym.guard
  100. if g.isNil or a.isTopLevel: return
  101. # fixup guard:
  102. if g.kind == skUnknown:
  103. var field: PSym = nil
  104. var ty = n.sons[0].typ.skipTypes(abstractPtrs)
  105. if ty.kind == tyTuple and not ty.n.isNil:
  106. field = lookupInRecord(ty.n, g.name)
  107. else:
  108. while ty != nil and ty.kind == tyObject:
  109. field = lookupInRecord(ty.n, g.name)
  110. if field != nil: break
  111. ty = ty.sons[0]
  112. if ty == nil: break
  113. ty = ty.skipTypes(skipPtrs)
  114. if field == nil:
  115. localError(a.config, n.info, "invalid guard field: " & g.name.s)
  116. return
  117. g = field
  118. #ri.sym.guard = field
  119. # XXX unfortunately this is not correct for generic instantiations!
  120. if g.kind == skField:
  121. let dot = newNodeI(nkDotExpr, n.info, 2)
  122. dot.sons[0] = n.sons[0]
  123. dot.sons[1] = newSymNode(g)
  124. dot.typ = g.typ
  125. for L in a.locked:
  126. #if a.guards.sameSubexprs(dot, L): return
  127. if guards.sameTree(dot, L): return
  128. localError(a.config, n.info, "unguarded access: " & renderTree(n))
  129. else:
  130. guardGlobal(a, n, g)
  131. proc makeVolatile(a: PEffects; s: PSym) {.inline.} =
  132. template compileToCpp(a): untyped =
  133. a.config.cmd == cmdCompileToCpp or sfCompileToCpp in getModule(a.owner).flags
  134. if a.inTryStmt > 0 and not compileToCpp(a):
  135. incl(s.flags, sfVolatile)
  136. proc initVar(a: PEffects, n: PNode; volatileCheck: bool) =
  137. if n.kind != nkSym: return
  138. let s = n.sym
  139. if isLocalVar(a, s):
  140. if volatileCheck: makeVolatile(a, s)
  141. for x in a.init:
  142. if x == s.id: return
  143. a.init.add s.id
  144. proc initVarViaNew(a: PEffects, n: PNode) =
  145. if n.kind != nkSym: return
  146. let s = n.sym
  147. if {tfNeedsInit, tfNotNil} * s.typ.flags <= {tfNotNil}:
  148. # 'x' is not nil, but that doesn't mean its "not nil" children
  149. # are initialized:
  150. initVar(a, n, volatileCheck=true)
  151. elif isLocalVar(a, s):
  152. makeVolatile(a, s)
  153. proc warnAboutGcUnsafe(n: PNode; conf: ConfigRef) =
  154. #assert false
  155. message(conf, n.info, warnGcUnsafe, renderTree(n))
  156. proc markGcUnsafe(a: PEffects; reason: PSym) =
  157. if not a.inEnforcedGcSafe:
  158. a.gcUnsafe = true
  159. if a.owner.kind in routineKinds: a.owner.gcUnsafetyReason = reason
  160. proc markGcUnsafe(a: PEffects; reason: PNode) =
  161. if not a.inEnforcedGcSafe:
  162. a.gcUnsafe = true
  163. if a.owner.kind in routineKinds:
  164. if reason.kind == nkSym:
  165. a.owner.gcUnsafetyReason = reason.sym
  166. else:
  167. a.owner.gcUnsafetyReason = newSym(skUnknown, a.owner.name,
  168. a.owner, reason.info, {})
  169. when true:
  170. template markSideEffect(a: PEffects; reason: typed) =
  171. a.hasSideEffect = true
  172. else:
  173. template markSideEffect(a: PEffects; reason: typed) =
  174. a.hasSideEffect = true
  175. markGcUnsafe(a, reason)
  176. proc listGcUnsafety(s: PSym; onlyWarning: bool; cycleCheck: var IntSet; conf: ConfigRef) =
  177. let u = s.gcUnsafetyReason
  178. if u != nil and not cycleCheck.containsOrIncl(u.id):
  179. let msgKind = if onlyWarning: warnGcUnsafe2 else: errGenerated
  180. case u.kind
  181. of skLet, skVar:
  182. message(conf, s.info, msgKind,
  183. ("'$#' is not GC-safe as it accesses '$#'" &
  184. " which is a global using GC'ed memory") % [s.name.s, u.name.s])
  185. of routineKinds:
  186. # recursive call *always* produces only a warning so the full error
  187. # message is printed:
  188. listGcUnsafety(u, true, cycleCheck, conf)
  189. message(conf, s.info, msgKind,
  190. "'$#' is not GC-safe as it calls '$#'" %
  191. [s.name.s, u.name.s])
  192. of skParam, skForVar:
  193. message(conf, s.info, msgKind,
  194. "'$#' is not GC-safe as it performs an indirect call via '$#'" %
  195. [s.name.s, u.name.s])
  196. else:
  197. message(conf, u.info, msgKind,
  198. "'$#' is not GC-safe as it performs an indirect call here" % s.name.s)
  199. proc listGcUnsafety(s: PSym; onlyWarning: bool; conf: ConfigRef) =
  200. var cycleCheck = initIntSet()
  201. listGcUnsafety(s, onlyWarning, cycleCheck, conf)
  202. proc useVar(a: PEffects, n: PNode) =
  203. let s = n.sym
  204. if isLocalVar(a, s):
  205. if s.id notin a.init:
  206. if {tfNeedsInit, tfNotNil} * s.typ.flags != {}:
  207. message(a.config, n.info, warnProveInit, s.name.s)
  208. else:
  209. message(a.config, n.info, warnUninit, s.name.s)
  210. # prevent superfluous warnings about the same variable:
  211. a.init.add s.id
  212. if {sfGlobal, sfThread} * s.flags != {} and s.kind in {skVar, skLet} and
  213. s.magic != mNimVm:
  214. if s.guard != nil: guardGlobal(a, n, s.guard)
  215. if {sfGlobal, sfThread} * s.flags == {sfGlobal} and
  216. (tfHasGCedMem in s.typ.flags or s.typ.isGCedMem):
  217. #if warnGcUnsafe in gNotes: warnAboutGcUnsafe(n)
  218. markGcUnsafe(a, s)
  219. markSideEffect(a, s)
  220. else:
  221. markSideEffect(a, s)
  222. type
  223. TIntersection = seq[tuple[id, count: int]] # a simple count table
  224. proc addToIntersection(inter: var TIntersection, s: int) =
  225. for j in 0..<inter.len:
  226. if s == inter[j].id:
  227. inc inter[j].count
  228. return
  229. inter.add((id: s, count: 1))
  230. proc throws(tracked, n: PNode) =
  231. if n.typ == nil or n.typ.kind != tyError: tracked.add n
  232. proc getEbase(g: ModuleGraph; info: TLineInfo): PType =
  233. result = g.sysTypeFromName(info, "Exception")
  234. proc excType(g: ModuleGraph; n: PNode): PType =
  235. # reraise is like raising E_Base:
  236. let t = if n.kind == nkEmpty or n.typ.isNil: getEbase(g, n.info) else: n.typ
  237. result = skipTypes(t, skipPtrs)
  238. proc createRaise(g: ModuleGraph; n: PNode): PNode =
  239. result = newNode(nkType)
  240. result.typ = getEbase(g, n.info)
  241. if not n.isNil: result.info = n.info
  242. proc createTag(g: ModuleGraph; n: PNode): PNode =
  243. result = newNode(nkType)
  244. result.typ = g.sysTypeFromName(n.info, "RootEffect")
  245. if not n.isNil: result.info = n.info
  246. proc addEffect(a: PEffects, e: PNode, useLineInfo=true) =
  247. assert e.kind != nkRaiseStmt
  248. var aa = a.exc
  249. for i in a.bottom ..< aa.len:
  250. if sameType(a.graph.excType(aa[i]), a.graph.excType(e)):
  251. if not useLineInfo or a.config.cmd == cmdDoc: return
  252. elif aa[i].info == e.info: return
  253. throws(a.exc, e)
  254. proc addTag(a: PEffects, e: PNode, useLineInfo=true) =
  255. var aa = a.tags
  256. for i in 0 ..< aa.len:
  257. if sameType(aa[i].typ.skipTypes(skipPtrs), e.typ.skipTypes(skipPtrs)):
  258. if not useLineInfo or a.config.cmd == cmdDoc: return
  259. elif aa[i].info == e.info: return
  260. throws(a.tags, e)
  261. proc mergeEffects(a: PEffects, b, comesFrom: PNode) =
  262. if b.isNil:
  263. addEffect(a, createRaise(a.graph, comesFrom))
  264. else:
  265. for effect in items(b): addEffect(a, effect, useLineInfo=comesFrom != nil)
  266. proc mergeTags(a: PEffects, b, comesFrom: PNode) =
  267. if b.isNil:
  268. addTag(a, createTag(a.graph, comesFrom))
  269. else:
  270. for effect in items(b): addTag(a, effect, useLineInfo=comesFrom != nil)
  271. proc listEffects(a: PEffects) =
  272. for e in items(a.exc): message(a.config, e.info, hintUser, typeToString(e.typ))
  273. for e in items(a.tags): message(a.config, e.info, hintUser, typeToString(e.typ))
  274. #if a.maxLockLevel != 0:
  275. # message(e.info, hintUser, "lockLevel: " & a.maxLockLevel)
  276. proc catches(tracked: PEffects, e: PType) =
  277. let e = skipTypes(e, skipPtrs)
  278. var L = tracked.exc.len
  279. var i = tracked.bottom
  280. while i < L:
  281. # r supertype of e?
  282. if safeInheritanceDiff(tracked.graph.excType(tracked.exc[i]), e) <= 0:
  283. tracked.exc.sons[i] = tracked.exc.sons[L-1]
  284. dec L
  285. else:
  286. inc i
  287. if tracked.exc.len > 0:
  288. setLen(tracked.exc.sons, L)
  289. else:
  290. assert L == 0
  291. proc catchesAll(tracked: PEffects) =
  292. if tracked.exc.len > 0:
  293. setLen(tracked.exc.sons, tracked.bottom)
  294. proc track(tracked: PEffects, n: PNode)
  295. proc trackTryStmt(tracked: PEffects, n: PNode) =
  296. let oldBottom = tracked.bottom
  297. tracked.bottom = tracked.exc.len
  298. let oldState = tracked.init.len
  299. var inter: TIntersection = @[]
  300. inc tracked.inTryStmt
  301. track(tracked, n.sons[0])
  302. dec tracked.inTryStmt
  303. for i in oldState..<tracked.init.len:
  304. addToIntersection(inter, tracked.init[i])
  305. var branches = 1
  306. var hasFinally = false
  307. for i in 1 ..< n.len:
  308. let b = n.sons[i]
  309. let blen = sonsLen(b)
  310. if b.kind == nkExceptBranch:
  311. inc branches
  312. if blen == 1:
  313. catchesAll(tracked)
  314. else:
  315. for j in countup(0, blen - 2):
  316. if b.sons[j].isInfixAs():
  317. assert(b.sons[j][1].kind == nkType)
  318. catches(tracked, b.sons[j][1].typ)
  319. else:
  320. assert(b.sons[j].kind == nkType)
  321. catches(tracked, b.sons[j].typ)
  322. setLen(tracked.init, oldState)
  323. track(tracked, b.sons[blen-1])
  324. for i in oldState..<tracked.init.len:
  325. addToIntersection(inter, tracked.init[i])
  326. else:
  327. assert b.kind == nkFinally
  328. setLen(tracked.init, oldState)
  329. track(tracked, b.sons[blen-1])
  330. hasFinally = true
  331. tracked.bottom = oldBottom
  332. if not hasFinally:
  333. setLen(tracked.init, oldState)
  334. for id, count in items(inter):
  335. if count == branches: tracked.init.add id
  336. proc isIndirectCall(n: PNode, owner: PSym): bool =
  337. # we don't count f(...) as an indirect call if 'f' is an parameter.
  338. # Instead we track expressions of type tyProc too. See the manual for
  339. # details:
  340. if n.kind != nkSym:
  341. result = true
  342. elif n.sym.kind == skParam:
  343. result = owner != n.sym.owner or owner == nil
  344. elif n.sym.kind notin routineKinds:
  345. result = true
  346. proc isForwardedProc(n: PNode): bool =
  347. result = n.kind == nkSym and sfForward in n.sym.flags
  348. proc trackPragmaStmt(tracked: PEffects, n: PNode) =
  349. for i in countup(0, sonsLen(n) - 1):
  350. var it = n.sons[i]
  351. if whichPragma(it) == wEffects:
  352. # list the computed effects up to here:
  353. listEffects(tracked)
  354. proc effectSpec(n: PNode, effectType: TSpecialWord): PNode =
  355. for i in countup(0, sonsLen(n) - 1):
  356. var it = n.sons[i]
  357. if it.kind == nkExprColonExpr and whichPragma(it) == effectType:
  358. result = it.sons[1]
  359. if result.kind notin {nkCurly, nkBracket}:
  360. result = newNodeI(nkCurly, result.info)
  361. result.add(it.sons[1])
  362. return
  363. proc documentEffect(cache: IdentCache; n, x: PNode, effectType: TSpecialWord, idx: int): PNode =
  364. let spec = effectSpec(x, effectType)
  365. if isNil(spec):
  366. let s = n.sons[namePos].sym
  367. let actual = s.typ.n.sons[0]
  368. if actual.len != effectListLen: return
  369. let real = actual.sons[idx]
  370. # warning: hack ahead:
  371. var effects = newNodeI(nkBracket, n.info, real.len)
  372. for i in 0 ..< real.len:
  373. var t = typeToString(real[i].typ)
  374. if t.startsWith("ref "): t = substr(t, 4)
  375. effects.sons[i] = newIdentNode(getIdent(cache, t), n.info)
  376. # set the type so that the following analysis doesn't screw up:
  377. effects.sons[i].typ = real[i].typ
  378. result = newNode(nkExprColonExpr, n.info, @[
  379. newIdentNode(getIdent(cache, specialWords[effectType]), n.info), effects])
  380. proc documentWriteEffect(cache: IdentCache; n: PNode; flag: TSymFlag; pragmaName: string): PNode =
  381. let s = n.sons[namePos].sym
  382. let params = s.typ.n
  383. var effects = newNodeI(nkBracket, n.info)
  384. for i in 1 ..< params.len:
  385. if params[i].kind == nkSym and flag in params[i].sym.flags:
  386. effects.add params[i]
  387. if effects.len > 0:
  388. result = newNode(nkExprColonExpr, n.info, @[
  389. newIdentNode(getIdent(cache, pragmaName), n.info), effects])
  390. proc documentNewEffect(cache: IdentCache; n: PNode): PNode =
  391. let s = n.sons[namePos].sym
  392. if tfReturnsNew in s.typ.flags:
  393. result = newIdentNode(getIdent(cache, "new"), n.info)
  394. proc documentRaises*(cache: IdentCache; n: PNode) =
  395. if n.sons[namePos].kind != nkSym: return
  396. let pragmas = n.sons[pragmasPos]
  397. let p1 = documentEffect(cache, n, pragmas, wRaises, exceptionEffects)
  398. let p2 = documentEffect(cache, n, pragmas, wTags, tagEffects)
  399. let p3 = documentWriteEffect(cache, n, sfWrittenTo, "writes")
  400. let p4 = documentNewEffect(cache, n)
  401. let p5 = documentWriteEffect(cache, n, sfEscapes, "escapes")
  402. if p1 != nil or p2 != nil or p3 != nil or p4 != nil or p5 != nil:
  403. if pragmas.kind == nkEmpty:
  404. n.sons[pragmasPos] = newNodeI(nkPragma, n.info)
  405. if p1 != nil: n.sons[pragmasPos].add p1
  406. if p2 != nil: n.sons[pragmasPos].add p2
  407. if p3 != nil: n.sons[pragmasPos].add p3
  408. if p4 != nil: n.sons[pragmasPos].add p4
  409. if p5 != nil: n.sons[pragmasPos].add p5
  410. template notGcSafe(t): untyped = {tfGcSafe, tfNoSideEffect} * t.flags == {}
  411. proc importedFromC(n: PNode): bool =
  412. # when imported from C, we assume GC-safety.
  413. result = n.kind == nkSym and sfImportc in n.sym.flags
  414. proc getLockLevel(s: PSym): TLockLevel =
  415. result = s.typ.lockLevel
  416. if result == UnspecifiedLockLevel:
  417. if {sfImportc, sfNoSideEffect} * s.flags != {} or
  418. tfNoSideEffect in s.typ.flags:
  419. result = 0.TLockLevel
  420. else:
  421. result = UnknownLockLevel
  422. #message(s.info, warnUser, "FOR THIS " & s.name.s)
  423. proc mergeLockLevels(tracked: PEffects, n: PNode, lockLevel: TLockLevel) =
  424. if lockLevel >= tracked.currLockLevel:
  425. # if in lock section:
  426. if tracked.currLockLevel > 0.TLockLevel:
  427. localError tracked.config, n.info, errGenerated,
  428. "expected lock level < " & $tracked.currLockLevel &
  429. " but got lock level " & $lockLevel
  430. tracked.maxLockLevel = max(tracked.maxLockLevel, lockLevel)
  431. proc propagateEffects(tracked: PEffects, n: PNode, s: PSym) =
  432. let pragma = s.ast.sons[pragmasPos]
  433. let spec = effectSpec(pragma, wRaises)
  434. mergeEffects(tracked, spec, n)
  435. let tagSpec = effectSpec(pragma, wTags)
  436. mergeTags(tracked, tagSpec, n)
  437. if notGcSafe(s.typ) and sfImportc notin s.flags:
  438. if warnGcUnsafe in tracked.config.notes: warnAboutGcUnsafe(n, tracked.config)
  439. markGcUnsafe(tracked, s)
  440. if tfNoSideEffect notin s.typ.flags:
  441. markSideEffect(tracked, s)
  442. mergeLockLevels(tracked, n, s.getLockLevel)
  443. proc procVarcheck(n: PNode; conf: ConfigRef) =
  444. if n.kind in nkSymChoices:
  445. for x in n: procVarCheck(x, conf)
  446. elif n.kind == nkSym and n.sym.magic != mNone and n.sym.kind in routineKinds:
  447. localError(conf, n.info, "'$1' cannot be passed to a procvar" % n.sym.name.s)
  448. proc notNilCheck(tracked: PEffects, n: PNode, paramType: PType) =
  449. let n = n.skipConv
  450. if paramType.isNil or paramType.kind != tyTypeDesc:
  451. procVarcheck skipConvAndClosure(n), tracked.config
  452. #elif n.kind in nkSymChoices:
  453. # echo "came here"
  454. let paramType = paramType.skipTypesOrNil(abstractInst)
  455. if paramType != nil and tfNotNil in paramType.flags and
  456. n.typ != nil and tfNotNil notin n.typ.flags:
  457. if n.kind == nkAddr:
  458. # addr(x[]) can't be proven, but addr(x) can:
  459. if not containsNode(n, {nkDerefExpr, nkHiddenDeref}): return
  460. elif (n.kind == nkSym and n.sym.kind in routineKinds) or
  461. (n.kind in procDefs+{nkObjConstr, nkBracket, nkClosure, nkStrLit..nkTripleStrLit}) or
  462. (n.kind in nkCallKinds and n[0].kind == nkSym and n[0].sym.magic == mArrToSeq):
  463. # 'p' is not nil obviously:
  464. return
  465. case impliesNotNil(tracked.guards, n)
  466. of impUnknown:
  467. message(tracked.config, n.info, errGenerated,
  468. "cannot prove '$1' is not nil" % n.renderTree)
  469. of impNo:
  470. message(tracked.config, n.info, errGenerated,
  471. "'$1' is provably nil" % n.renderTree)
  472. of impYes: discard
  473. proc assumeTheWorst(tracked: PEffects; n: PNode; op: PType) =
  474. addEffect(tracked, createRaise(tracked.graph, n))
  475. addTag(tracked, createTag(tracked.graph, n))
  476. let lockLevel = if op.lockLevel == UnspecifiedLockLevel: UnknownLockLevel
  477. else: op.lockLevel
  478. #if lockLevel == UnknownLockLevel:
  479. # message(n.info, warnUser, "had to assume the worst here")
  480. mergeLockLevels(tracked, n, lockLevel)
  481. proc isOwnedProcVar(n: PNode; owner: PSym): bool =
  482. # XXX prove the soundness of this effect system rule
  483. result = n.kind == nkSym and n.sym.kind == skParam and owner == n.sym.owner
  484. proc isNoEffectList(n: PNode): bool {.inline.} =
  485. assert n.kind == nkEffectList
  486. n.len == 0 or (n[tagEffects] == nil and n[exceptionEffects] == nil)
  487. proc trackOperand(tracked: PEffects, n: PNode, paramType: PType) =
  488. let a = skipConvAndClosure(n)
  489. let op = a.typ
  490. if op != nil and op.kind == tyProc and n.skipConv.kind != nkNilLit:
  491. internalAssert tracked.config, op.n.sons[0].kind == nkEffectList
  492. var effectList = op.n.sons[0]
  493. let s = n.skipConv
  494. if s.kind == nkSym and s.sym.kind in routineKinds:
  495. propagateEffects(tracked, n, s.sym)
  496. elif isNoEffectList(effectList):
  497. if isForwardedProc(n):
  498. # we have no explicit effects but it's a forward declaration and so it's
  499. # stated there are no additional effects, so simply propagate them:
  500. propagateEffects(tracked, n, n.sym)
  501. elif not isOwnedProcVar(a, tracked.owner):
  502. # we have no explicit effects so assume the worst:
  503. assumeTheWorst(tracked, n, op)
  504. # assume GcUnsafe unless in its type; 'forward' does not matter:
  505. if notGcSafe(op) and not isOwnedProcVar(a, tracked.owner):
  506. if warnGcUnsafe in tracked.config.notes: warnAboutGcUnsafe(n, tracked.config)
  507. markGcUnsafe(tracked, a)
  508. elif tfNoSideEffect notin op.flags and not isOwnedProcVar(a, tracked.owner):
  509. markSideEffect(tracked, a)
  510. else:
  511. mergeEffects(tracked, effectList.sons[exceptionEffects], n)
  512. mergeTags(tracked, effectList.sons[tagEffects], n)
  513. if notGcSafe(op):
  514. if warnGcUnsafe in tracked.config.notes: warnAboutGcUnsafe(n, tracked.config)
  515. markGcUnsafe(tracked, a)
  516. elif tfNoSideEffect notin op.flags:
  517. markSideEffect(tracked, a)
  518. if paramType != nil and paramType.kind == tyVar:
  519. if n.kind == nkSym and isLocalVar(tracked, n.sym):
  520. makeVolatile(tracked, n.sym)
  521. if paramType != nil and paramType.kind == tyProc and tfGcSafe in paramType.flags:
  522. let argtype = skipTypes(a.typ, abstractInst)
  523. # XXX figure out why this can be a non tyProc here. See httpclient.nim for an
  524. # example that triggers it.
  525. if argtype.kind == tyProc and notGcSafe(argtype) and not tracked.inEnforcedGcSafe:
  526. localError(tracked.config, n.info, $n & " is not GC safe")
  527. notNilCheck(tracked, n, paramType)
  528. proc breaksBlock(n: PNode): bool =
  529. # sematic check doesn't allow statements after raise, break, return or
  530. # call to noreturn proc, so it is safe to check just the last statements
  531. var it = n
  532. while it.kind in {nkStmtList, nkStmtListExpr} and it.len > 0:
  533. it = it.lastSon
  534. result = it.kind in {nkBreakStmt, nkReturnStmt, nkRaiseStmt} or
  535. it.kind in nkCallKinds and it[0].kind == nkSym and sfNoReturn in it[0].sym.flags
  536. proc trackCase(tracked: PEffects, n: PNode) =
  537. track(tracked, n.sons[0])
  538. let oldState = tracked.init.len
  539. let oldFacts = tracked.guards.s.len
  540. let stringCase = skipTypes(n.sons[0].typ,
  541. abstractVarRange-{tyTypeDesc}).kind in {tyFloat..tyFloat128, tyString}
  542. let interesting = not stringCase and interestingCaseExpr(n.sons[0]) and
  543. warnProveField in tracked.config.notes
  544. var inter: TIntersection = @[]
  545. var toCover = 0
  546. for i in 1..<n.len:
  547. let branch = n.sons[i]
  548. setLen(tracked.init, oldState)
  549. if interesting:
  550. setLen(tracked.guards.s, oldFacts)
  551. addCaseBranchFacts(tracked.guards, n, i)
  552. for i in 0 ..< branch.len:
  553. track(tracked, branch.sons[i])
  554. if not breaksBlock(branch.lastSon): inc toCover
  555. for i in oldState..<tracked.init.len:
  556. addToIntersection(inter, tracked.init[i])
  557. setLen(tracked.init, oldState)
  558. if not stringCase or lastSon(n).kind == nkElse:
  559. for id, count in items(inter):
  560. if count >= toCover: tracked.init.add id
  561. # else we can't merge
  562. setLen(tracked.guards.s, oldFacts)
  563. proc trackIf(tracked: PEffects, n: PNode) =
  564. track(tracked, n.sons[0].sons[0])
  565. let oldFacts = tracked.guards.s.len
  566. addFact(tracked.guards, n.sons[0].sons[0])
  567. let oldState = tracked.init.len
  568. var inter: TIntersection = @[]
  569. var toCover = 0
  570. track(tracked, n.sons[0].sons[1])
  571. if not breaksBlock(n.sons[0].sons[1]): inc toCover
  572. for i in oldState..<tracked.init.len:
  573. addToIntersection(inter, tracked.init[i])
  574. for i in 1..<n.len:
  575. let branch = n.sons[i]
  576. setLen(tracked.guards.s, oldFacts)
  577. for j in 0..i-1:
  578. addFactNeg(tracked.guards, n.sons[j].sons[0])
  579. if branch.len > 1:
  580. addFact(tracked.guards, branch.sons[0])
  581. setLen(tracked.init, oldState)
  582. for i in 0 ..< branch.len:
  583. track(tracked, branch.sons[i])
  584. if not breaksBlock(branch.lastSon): inc toCover
  585. for i in oldState..<tracked.init.len:
  586. addToIntersection(inter, tracked.init[i])
  587. setLen(tracked.init, oldState)
  588. if lastSon(n).len == 1:
  589. for id, count in items(inter):
  590. if count >= toCover: tracked.init.add id
  591. # else we can't merge as it is not exhaustive
  592. setLen(tracked.guards.s, oldFacts)
  593. proc trackBlock(tracked: PEffects, n: PNode) =
  594. if n.kind in {nkStmtList, nkStmtListExpr}:
  595. var oldState = -1
  596. for i in 0..<n.len:
  597. if hasSubnodeWith(n.sons[i], nkBreakStmt):
  598. # block:
  599. # x = def
  600. # if ...: ... break # some nested break
  601. # y = def
  602. # --> 'y' not defined after block!
  603. if oldState < 0: oldState = tracked.init.len
  604. track(tracked, n.sons[i])
  605. if oldState > 0: setLen(tracked.init, oldState)
  606. else:
  607. track(tracked, n)
  608. proc isTrue*(n: PNode): bool =
  609. n.kind == nkSym and n.sym.kind == skEnumField and n.sym.position != 0 or
  610. n.kind == nkIntLit and n.intVal != 0
  611. proc paramType(op: PType, i: int): PType =
  612. if op != nil and i < op.len: result = op.sons[i]
  613. proc cstringCheck(tracked: PEffects; n: PNode) =
  614. if n.sons[0].typ.kind == tyCString and (let a = skipConv(n[1]);
  615. a.typ.kind == tyString and a.kind notin {nkStrLit..nkTripleStrLit}):
  616. message(tracked.config, n.info, warnUnsafeCode, renderTree(n))
  617. proc track(tracked: PEffects, n: PNode) =
  618. case n.kind
  619. of nkSym:
  620. useVar(tracked, n)
  621. of nkRaiseStmt:
  622. n.sons[0].info = n.info
  623. #throws(tracked.exc, n.sons[0])
  624. addEffect(tracked, n.sons[0], useLineInfo=false)
  625. for i in 0 ..< safeLen(n):
  626. track(tracked, n.sons[i])
  627. of nkCallKinds:
  628. # p's effects are ours too:
  629. let a = n.sons[0]
  630. let op = a.typ
  631. # XXX: in rare situations, templates and macros will reach here after
  632. # calling getAst(templateOrMacro()). Currently, templates and macros
  633. # are indistinguishable from normal procs (both have tyProc type) and
  634. # we can detect them only by checking for attached nkEffectList.
  635. if op != nil and op.kind == tyProc and op.n.sons[0].kind == nkEffectList:
  636. if a.kind == nkSym:
  637. if a.sym == tracked.owner: tracked.isRecursive = true
  638. # even for recursive calls we need to check the lock levels (!):
  639. mergeLockLevels(tracked, n, a.sym.getLockLevel)
  640. if sfSideEffect in a.sym.flags: markSideEffect(tracked, a)
  641. else:
  642. mergeLockLevels(tracked, n, op.lockLevel)
  643. var effectList = op.n.sons[0]
  644. if a.kind == nkSym and a.sym.kind == skMethod:
  645. propagateEffects(tracked, n, a.sym)
  646. elif isNoEffectList(effectList):
  647. if isForwardedProc(a):
  648. propagateEffects(tracked, n, a.sym)
  649. elif isIndirectCall(a, tracked.owner):
  650. assumeTheWorst(tracked, n, op)
  651. else:
  652. mergeEffects(tracked, effectList.sons[exceptionEffects], n)
  653. mergeTags(tracked, effectList.sons[tagEffects], n)
  654. if notGcSafe(op) and not importedFromC(a):
  655. # and it's not a recursive call:
  656. if not (a.kind == nkSym and a.sym == tracked.owner):
  657. if warnGcUnsafe in tracked.config.notes: warnAboutGcUnsafe(n, tracked.config)
  658. markGcUnsafe(tracked, a)
  659. if tfNoSideEffect notin op.flags and not importedFromC(a):
  660. # and it's not a recursive call:
  661. if not (a.kind == nkSym and a.sym == tracked.owner):
  662. markSideEffect(tracked, a)
  663. if a.kind != nkSym or a.sym.magic != mNBindSym:
  664. for i in 1 ..< len(n): trackOperand(tracked, n.sons[i], paramType(op, i))
  665. if a.kind == nkSym and a.sym.magic in {mNew, mNewFinalize, mNewSeq}:
  666. # may not look like an assignment, but it is:
  667. let arg = n.sons[1]
  668. initVarViaNew(tracked, arg)
  669. if arg.typ.len != 0 and {tfNeedsInit} * arg.typ.lastSon.flags != {}:
  670. if a.sym.magic == mNewSeq and n[2].kind in {nkCharLit..nkUInt64Lit} and
  671. n[2].intVal == 0:
  672. # var s: seq[notnil]; newSeq(s, 0) is a special case!
  673. discard
  674. else:
  675. message(tracked.config, arg.info, warnProveInit, $arg)
  676. for i in 0 ..< safeLen(n):
  677. track(tracked, n.sons[i])
  678. of nkDotExpr:
  679. guardDotAccess(tracked, n)
  680. for i in 0 ..< len(n): track(tracked, n.sons[i])
  681. of nkCheckedFieldExpr:
  682. track(tracked, n.sons[0])
  683. if warnProveField in tracked.config.notes:
  684. checkFieldAccess(tracked.guards, n, tracked.config)
  685. of nkTryStmt: trackTryStmt(tracked, n)
  686. of nkPragma: trackPragmaStmt(tracked, n)
  687. of nkAsgn, nkFastAsgn:
  688. track(tracked, n.sons[1])
  689. initVar(tracked, n.sons[0], volatileCheck=true)
  690. invalidateFacts(tracked.guards, n.sons[0])
  691. track(tracked, n.sons[0])
  692. addAsgnFact(tracked.guards, n.sons[0], n.sons[1])
  693. notNilCheck(tracked, n.sons[1], n.sons[0].typ)
  694. when false: cstringCheck(tracked, n)
  695. of nkVarSection, nkLetSection:
  696. for child in n:
  697. let last = lastSon(child)
  698. if last.kind != nkEmpty: track(tracked, last)
  699. if child.kind == nkIdentDefs and last.kind != nkEmpty:
  700. for i in 0 .. child.len-3:
  701. initVar(tracked, child.sons[i], volatileCheck=false)
  702. addAsgnFact(tracked.guards, child.sons[i], last)
  703. notNilCheck(tracked, last, child.sons[i].typ)
  704. elif child.kind == nkVarTuple and last.kind != nkEmpty:
  705. for i in 0 .. child.len-2:
  706. if child[i].kind == nkEmpty or
  707. child[i].kind == nkSym and child[i].sym.name.s == "_":
  708. continue
  709. initVar(tracked, child[i], volatileCheck=false)
  710. if last.kind in {nkPar, nkTupleConstr}:
  711. addAsgnFact(tracked.guards, child[i], last[i])
  712. notNilCheck(tracked, last[i], child[i].typ)
  713. # since 'var (a, b): T = ()' is not even allowed, there is always type
  714. # inference for (a, b) and thus no nil checking is necessary.
  715. of nkConstSection:
  716. for child in n:
  717. let last = lastSon(child)
  718. track(tracked, last)
  719. of nkCaseStmt: trackCase(tracked, n)
  720. of nkWhen, nkIfStmt, nkIfExpr: trackIf(tracked, n)
  721. of nkBlockStmt, nkBlockExpr: trackBlock(tracked, n.sons[1])
  722. of nkWhileStmt:
  723. track(tracked, n.sons[0])
  724. # 'while true' loop?
  725. if isTrue(n.sons[0]):
  726. trackBlock(tracked, n.sons[1])
  727. else:
  728. # loop may never execute:
  729. let oldState = tracked.init.len
  730. let oldFacts = tracked.guards.s.len
  731. addFact(tracked.guards, n.sons[0])
  732. track(tracked, n.sons[1])
  733. setLen(tracked.init, oldState)
  734. setLen(tracked.guards.s, oldFacts)
  735. of nkForStmt, nkParForStmt:
  736. # we are very conservative here and assume the loop is never executed:
  737. let oldState = tracked.init.len
  738. for i in 0 ..< len(n):
  739. track(tracked, n.sons[i])
  740. setLen(tracked.init, oldState)
  741. of nkObjConstr:
  742. when false: track(tracked, n.sons[0])
  743. let oldFacts = tracked.guards.s.len
  744. for i in 1 ..< len(n):
  745. let x = n.sons[i]
  746. track(tracked, x)
  747. if x.sons[0].kind == nkSym and sfDiscriminant in x.sons[0].sym.flags:
  748. addDiscriminantFact(tracked.guards, x)
  749. setLen(tracked.guards.s, oldFacts)
  750. of nkPragmaBlock:
  751. let pragmaList = n.sons[0]
  752. let oldLocked = tracked.locked.len
  753. let oldLockLevel = tracked.currLockLevel
  754. var enforcedGcSafety = false
  755. for i in 0 ..< pragmaList.len:
  756. let pragma = whichPragma(pragmaList.sons[i])
  757. if pragma == wLocks:
  758. lockLocations(tracked, pragmaList.sons[i])
  759. elif pragma == wGcSafe:
  760. enforcedGcSafety = true
  761. if enforcedGcSafety: tracked.inEnforcedGcSafe = true
  762. track(tracked, n.lastSon)
  763. if enforcedGcSafety: tracked.inEnforcedGcSafe = false
  764. setLen(tracked.locked, oldLocked)
  765. tracked.currLockLevel = oldLockLevel
  766. of nkTypeSection, nkProcDef, nkConverterDef, nkMethodDef, nkIteratorDef,
  767. nkMacroDef, nkTemplateDef, nkLambda, nkDo, nkFuncDef:
  768. discard
  769. of nkCast, nkHiddenStdConv, nkHiddenSubConv, nkConv:
  770. if n.len == 2: track(tracked, n.sons[1])
  771. of nkObjUpConv, nkObjDownConv, nkChckRange, nkChckRangeF, nkChckRange64:
  772. if n.len == 1: track(tracked, n.sons[0])
  773. else:
  774. for i in 0 ..< safeLen(n): track(tracked, n.sons[i])
  775. proc subtypeRelation(g: ModuleGraph; spec, real: PNode): bool =
  776. result = safeInheritanceDiff(g.excType(real), spec.typ) <= 0
  777. proc checkRaisesSpec(g: ModuleGraph; spec, real: PNode, msg: string, hints: bool;
  778. effectPredicate: proc (g: ModuleGraph; a, b: PNode): bool {.nimcall.}) =
  779. # check that any real exception is listed in 'spec'; mark those as used;
  780. # report any unused exception
  781. var used = initIntSet()
  782. for r in items(real):
  783. block search:
  784. for s in 0 ..< spec.len:
  785. if effectPredicate(g, spec[s], r):
  786. used.incl(s)
  787. break search
  788. # XXX call graph analysis would be nice here!
  789. pushInfoContext(g.config, spec.info)
  790. localError(g.config, r.info, errGenerated, msg & typeToString(r.typ))
  791. popInfoContext(g.config)
  792. # hint about unnecessarily listed exception types:
  793. if hints:
  794. for s in 0 ..< spec.len:
  795. if not used.contains(s):
  796. message(g.config, spec[s].info, hintXDeclaredButNotUsed, renderTree(spec[s]))
  797. proc checkMethodEffects*(g: ModuleGraph; disp, branch: PSym) =
  798. ## checks for consistent effects for multi methods.
  799. let actual = branch.typ.n.sons[0]
  800. if actual.len != effectListLen: return
  801. let p = disp.ast.sons[pragmasPos]
  802. let raisesSpec = effectSpec(p, wRaises)
  803. if not isNil(raisesSpec):
  804. checkRaisesSpec(g, raisesSpec, actual.sons[exceptionEffects],
  805. "can raise an unlisted exception: ", hints=off, subtypeRelation)
  806. let tagsSpec = effectSpec(p, wTags)
  807. if not isNil(tagsSpec):
  808. checkRaisesSpec(g, tagsSpec, actual.sons[tagEffects],
  809. "can have an unlisted effect: ", hints=off, subtypeRelation)
  810. if sfThread in disp.flags and notGcSafe(branch.typ):
  811. localError(g.config, branch.info, "base method is GC-safe, but '$1' is not" %
  812. branch.name.s)
  813. if branch.typ.lockLevel > disp.typ.lockLevel:
  814. when true:
  815. message(g.config, branch.info, warnLockLevel,
  816. "base method has lock level $1, but dispatcher has $2" %
  817. [$branch.typ.lockLevel, $disp.typ.lockLevel])
  818. else:
  819. # XXX make this an error after bigbreak has been released:
  820. localError(g.config, branch.info,
  821. "base method has lock level $1, but dispatcher has $2" %
  822. [$branch.typ.lockLevel, $disp.typ.lockLevel])
  823. proc setEffectsForProcType*(g: ModuleGraph; t: PType, n: PNode) =
  824. var effects = t.n[0]
  825. if t.kind != tyProc or effects.kind != nkEffectList: return
  826. if n.kind != nkEmpty:
  827. internalAssert g.config, effects.len == 0
  828. newSeq(effects.sons, effectListLen)
  829. let raisesSpec = effectSpec(n, wRaises)
  830. if not isNil(raisesSpec):
  831. effects[exceptionEffects] = raisesSpec
  832. let tagsSpec = effectSpec(n, wTags)
  833. if not isNil(tagsSpec):
  834. effects[tagEffects] = tagsSpec
  835. effects[pragmasEffects] = n
  836. proc initEffects(g: ModuleGraph; effects: PNode; s: PSym; t: var TEffects) =
  837. newSeq(effects.sons, effectListLen)
  838. effects.sons[exceptionEffects] = newNodeI(nkArgList, s.info)
  839. effects.sons[tagEffects] = newNodeI(nkArgList, s.info)
  840. effects.sons[usesEffects] = g.emptyNode
  841. effects.sons[writeEffects] = g.emptyNode
  842. effects.sons[pragmasEffects] = g.emptyNode
  843. t.exc = effects.sons[exceptionEffects]
  844. t.tags = effects.sons[tagEffects]
  845. t.owner = s
  846. t.init = @[]
  847. t.guards.s = @[]
  848. t.guards.o = initOperators(g)
  849. t.locked = @[]
  850. t.graph = g
  851. t.config = g.config
  852. proc trackProc*(g: ModuleGraph; s: PSym, body: PNode) =
  853. var effects = s.typ.n.sons[0]
  854. if effects.kind != nkEffectList: return
  855. # effects already computed?
  856. if sfForward in s.flags: return
  857. if effects.len == effectListLen: return
  858. var t: TEffects
  859. initEffects(g, effects, s, t)
  860. track(t, body)
  861. if not isEmptyType(s.typ.sons[0]) and
  862. {tfNeedsInit, tfNotNil} * s.typ.sons[0].flags != {} and
  863. s.kind in {skProc, skFunc, skConverter, skMethod}:
  864. var res = s.ast.sons[resultPos].sym # get result symbol
  865. if res.id notin t.init:
  866. message(g.config, body.info, warnProveInit, "result")
  867. let p = s.ast.sons[pragmasPos]
  868. let raisesSpec = effectSpec(p, wRaises)
  869. if not isNil(raisesSpec):
  870. checkRaisesSpec(g, raisesSpec, t.exc, "can raise an unlisted exception: ",
  871. hints=on, subtypeRelation)
  872. # after the check, use the formal spec:
  873. effects.sons[exceptionEffects] = raisesSpec
  874. let tagsSpec = effectSpec(p, wTags)
  875. if not isNil(tagsSpec):
  876. checkRaisesSpec(g, tagsSpec, t.tags, "can have an unlisted effect: ",
  877. hints=off, subtypeRelation)
  878. # after the check, use the formal spec:
  879. effects.sons[tagEffects] = tagsSpec
  880. if sfThread in s.flags and t.gcUnsafe:
  881. if optThreads in g.config.globalOptions and optThreadAnalysis in g.config.globalOptions:
  882. #localError(s.info, "'$1' is not GC-safe" % s.name.s)
  883. listGcUnsafety(s, onlyWarning=false, g.config)
  884. else:
  885. listGcUnsafety(s, onlyWarning=true, g.config)
  886. #localError(s.info, warnGcUnsafe2, s.name.s)
  887. if sfNoSideEffect in s.flags and t.hasSideEffect:
  888. when false:
  889. listGcUnsafety(s, onlyWarning=false, g.config)
  890. else:
  891. localError(g.config, s.info, "'$1' can have side effects" % s.name.s)
  892. if not t.gcUnsafe:
  893. s.typ.flags.incl tfGcSafe
  894. if not t.hasSideEffect and sfSideEffect notin s.flags:
  895. s.typ.flags.incl tfNoSideEffect
  896. if s.typ.lockLevel == UnspecifiedLockLevel:
  897. s.typ.lockLevel = t.maxLockLevel
  898. elif t.maxLockLevel > s.typ.lockLevel:
  899. #localError(s.info,
  900. message(g.config, s.info, warnLockLevel,
  901. "declared lock level is $1, but real lock level is $2" %
  902. [$s.typ.lockLevel, $t.maxLockLevel])
  903. when defined(useDfa):
  904. if s.kind == skFunc:
  905. dataflowAnalysis(s, body)
  906. when false: trackWrites(s, body)
  907. proc trackTopLevelStmt*(g: ModuleGraph; module: PSym; n: PNode) =
  908. if n.kind in {nkPragma, nkMacroDef, nkTemplateDef, nkProcDef, nkFuncDef,
  909. nkTypeSection, nkConverterDef, nkMethodDef, nkIteratorDef}:
  910. return
  911. var effects = newNode(nkEffectList, n.info)
  912. var t: TEffects
  913. initEffects(g, effects, module, t)
  914. t.isToplevel = true
  915. track(t, n)