sempass2.nim 38 KB

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